initial commit - cross reference with 5th port - obviously has compile errors
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
|
||||
|
||||
/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
|
||||
|
||||
//Interaction
|
||||
/atom/movable/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
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))
|
||||
if(user_buckle_mob(M, user))
|
||||
return 1
|
||||
|
||||
//Cleanup
|
||||
/atom/movable/Destroy()
|
||||
. = ..()
|
||||
unbuckle_all_mobs(force=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 = 0)
|
||||
if(!buckled_mobs)
|
||||
buckled_mobs = list()
|
||||
if((!can_buckle && !force) || !istype(M) || (M.loc != loc) || M.buckled || (buckled_mobs.len >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src)
|
||||
return 0
|
||||
if(!M.can_buckle() && !force)
|
||||
if(M == usr)
|
||||
M << "<span class='warning'>You are unable to buckle yourself to the [src]!</span>"
|
||||
else
|
||||
usr << "<span class='warning'>You are unable to buckle [M] to the [src]!</span>"
|
||||
return 0
|
||||
|
||||
M.buckled = src
|
||||
M.setDir(dir)
|
||||
buckled_mobs |= M
|
||||
M.update_canmove()
|
||||
post_buckle_mob(M)
|
||||
M.throw_alert("buckled", /obj/screen/alert/restrained/buckled, new_master = src)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/buckle_mob(mob/living/M, force = 0)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(burn_state == 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=0)
|
||||
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
|
||||
|
||||
post_buckle_mob(.)
|
||||
|
||||
/atom/movable/proc/unbuckle_all_mobs(force=0)
|
||||
if(!has_buckled_mobs())
|
||||
return
|
||||
for(var/m in buckled_mobs)
|
||||
unbuckle_mob(m, force)
|
||||
|
||||
//Handle any extras after buckling/unbuckling
|
||||
//Called on buckle_mob() and unbuckle_mob()
|
||||
/atom/movable/proc/post_buckle_mob(mob/living/M)
|
||||
return
|
||||
|
||||
|
||||
//Wrapper procs that handle sanity and user feedback
|
||||
/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user)
|
||||
if(!in_range(user, src) || user.stat || user.restrained())
|
||||
return 0
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
if(buckle_mob(M))
|
||||
if(M == user)
|
||||
M.visible_message(\
|
||||
"<span class='notice'>[M] buckles themself 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>")
|
||||
return 1
|
||||
|
||||
|
||||
/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 themselves 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,87 @@
|
||||
/* Alien shit!
|
||||
* Contains:
|
||||
* effect/acid
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Acid
|
||||
*/
|
||||
/obj/effect/acid
|
||||
gender = PLURAL
|
||||
name = "acid"
|
||||
desc = "Burbling corrossive stuff."
|
||||
icon_state = "acid"
|
||||
density = 0
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
unacidable = 1
|
||||
var/atom/target
|
||||
var/ticks = 0
|
||||
var/target_strength = 0
|
||||
|
||||
|
||||
/obj/effect/acid/New(loc, targ)
|
||||
..(loc)
|
||||
target = targ
|
||||
|
||||
//handle APCs and newscasters and stuff nicely
|
||||
pixel_x = target.pixel_x
|
||||
pixel_y = target.pixel_y
|
||||
|
||||
if(isturf(target)) //Turfs take twice as long to take down.
|
||||
target_strength = 640
|
||||
else
|
||||
target_strength = 320
|
||||
tick()
|
||||
|
||||
|
||||
/obj/effect/acid/proc/tick()
|
||||
if(!target)
|
||||
qdel(src)
|
||||
|
||||
ticks++
|
||||
|
||||
if(ticks >= target_strength)
|
||||
target.visible_message("<span class='warning'>[target] collapses under its own weight into a puddle of goop and undigested debris!</span>")
|
||||
|
||||
if(istype(target, /obj/structure/closet))
|
||||
var/obj/structure/closet/T = target
|
||||
T.dump_contents()
|
||||
qdel(target)
|
||||
|
||||
if(istype(target, /turf/closed/mineral))
|
||||
var/turf/closed/mineral/M = target
|
||||
M.ChangeTurf(M.baseturf)
|
||||
|
||||
if(istype(target, /turf/open/floor))
|
||||
var/turf/open/floor/F = target
|
||||
F.ChangeTurf(F.baseturf)
|
||||
|
||||
if(istype(target, /turf/closed/wall))
|
||||
var/turf/closed/wall/W = target
|
||||
W.dismantle_wall(1)
|
||||
|
||||
else
|
||||
qdel(target)
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
x = target.x
|
||||
y = target.y
|
||||
z = target.z
|
||||
|
||||
switch(target_strength - ticks)
|
||||
if(480)
|
||||
visible_message("<span class='warning'>[target] is holding up against the acid!</span>")
|
||||
if(320)
|
||||
visible_message("<span class='warning'>[target] is being melted by the acid!</span>")
|
||||
if(160)
|
||||
visible_message("<span class='warning'>[target] is struggling to withstand the acid!</span>")
|
||||
if(80)
|
||||
visible_message("<span class='warning'>[target] begins to crumble under the acid!</span>")
|
||||
|
||||
spawn(1)
|
||||
if(src)
|
||||
tick()
|
||||
@@ -0,0 +1,230 @@
|
||||
//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"
|
||||
unacidable = 1
|
||||
density = 0
|
||||
anchored = 1
|
||||
luminosity = 3
|
||||
var/movechance = 70
|
||||
var/obj/item/device/assembly/signaler/anomaly/aSignal = null
|
||||
|
||||
/obj/effect/anomaly/New()
|
||||
..()
|
||||
poi_list |= src
|
||||
SetLuminosity(initial(luminosity))
|
||||
aSignal = new(src)
|
||||
aSignal.code = rand(1,100)
|
||||
|
||||
aSignal.frequency = rand(1200, 1599)
|
||||
if(IsMultiple(aSignal.frequency, 2))//signaller frequencies are always uneven!
|
||||
aSignal.frequency++
|
||||
|
||||
/obj/effect/anomaly/Destroy()
|
||||
poi_list.Remove(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyEffect()
|
||||
if(prob(movechance))
|
||||
step(src,pick(alldirs))
|
||||
|
||||
|
||||
/obj/effect/anomaly/ex_act(severity, target)
|
||||
if(severity == 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyNeutralize()
|
||||
PoolOrNew(/obj/effect/particle_effect/smoke/bad, loc)
|
||||
|
||||
for(var/atom/movable/O in src)
|
||||
O.loc = src.loc
|
||||
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/anomaly/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/device/analyzer))
|
||||
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 = 0
|
||||
var/boing = 0
|
||||
|
||||
/obj/effect/anomaly/grav/New()
|
||||
..()
|
||||
aSignal.origin_tech = "magnets=7"
|
||||
|
||||
/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(mob/A)
|
||||
gravShock(A)
|
||||
|
||||
/obj/effect/anomaly/grav/proc/gravShock(mob/A)
|
||||
if(boing && isliving(A) && !A.stat)
|
||||
A.Weaken(2)
|
||||
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/flux
|
||||
name = "flux wave anomaly"
|
||||
icon_state = "electricity2"
|
||||
density = 1
|
||||
var/canshock = 0
|
||||
var/shockdamage = 20
|
||||
|
||||
/obj/effect/anomaly/flux/New()
|
||||
..()
|
||||
aSignal.origin_tech = "powerstorage=7"
|
||||
|
||||
/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(mob/living/M)
|
||||
mobShock(M)
|
||||
|
||||
/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/bluespace
|
||||
name = "bluespace anomaly"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state = "bluespace"
|
||||
density = 1
|
||||
|
||||
/obj/effect/anomaly/bluespace/New()
|
||||
..()
|
||||
aSignal.origin_tech = "bluespace=7"
|
||||
|
||||
/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)
|
||||
|
||||
/obj/effect/anomaly/bluespace/Bumped(atom/A)
|
||||
if(isliving(A))
|
||||
do_teleport(A, locate(A.x, A.y, A.z), 8)
|
||||
|
||||
/////////////////////
|
||||
|
||||
/obj/effect/anomaly/pyro
|
||||
name = "pyroclastic anomaly"
|
||||
icon_state = "mustard"
|
||||
|
||||
/obj/effect/anomaly/pyro/New()
|
||||
..()
|
||||
aSignal.origin_tech = "plasmatech=7"
|
||||
|
||||
/obj/effect/anomaly/pyro/anomalyEffect()
|
||||
..()
|
||||
var/turf/open/T = get_turf(src)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air("o2=5;plasma=5;TEMP=1000")
|
||||
|
||||
/////////////////////
|
||||
|
||||
/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/New()
|
||||
..()
|
||||
aSignal.origin_tech = "engineering=7"
|
||||
|
||||
/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(2)
|
||||
|
||||
/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,34 @@
|
||||
var/list/obj/effect/bump_teleporter/BUMP_TELEPORTERS = list()
|
||||
|
||||
/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 = 1
|
||||
density = 1
|
||||
opacity = 0
|
||||
|
||||
/obj/effect/bump_teleporter/New()
|
||||
..()
|
||||
BUMP_TELEPORTERS += src
|
||||
|
||||
/obj/effect/bump_teleporter/Destroy()
|
||||
BUMP_TELEPORTERS -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/bump_teleporter/Bumped(atom/user)
|
||||
if(!ismob(user))
|
||||
//user.loc = src.loc //Stop at teleporter location
|
||||
return
|
||||
|
||||
if(!id_target)
|
||||
//user.loc = src.loc //Stop at teleporter location, there is nowhere to teleport to.
|
||||
return
|
||||
|
||||
for(var/obj/effect/bump_teleporter/BT in BUMP_TELEPORTERS)
|
||||
if(BT.id == src.id_target)
|
||||
usr.loc = BT.loc //Teleport to location with correct id.
|
||||
return
|
||||
@@ -0,0 +1,278 @@
|
||||
|
||||
//########################## POSTERS ##################################
|
||||
|
||||
#define NUM_OF_POSTER_DESIGNS 36 // contraband posters
|
||||
|
||||
#define NUM_OF_POSTER_DESIGNS_LEGIT 35 // corporate approved posters
|
||||
|
||||
#define POSTERNAME "name"
|
||||
|
||||
#define POSTERDESC "desc"
|
||||
|
||||
|
||||
//########################## LISTS OF POSTERS AND DESCS #####################
|
||||
|
||||
// please add new posters and names to their respective lists and update constant(s) above
|
||||
// use the format below, including punctuation, this will become important later
|
||||
|
||||
// CONTRABAND
|
||||
|
||||
var/global/list/contrabandposters = list(
|
||||
|
||||
list(name = "- Free Tonto", desc = " A salvaged shred of a much larger flag, colors bled together and faded from age."),
|
||||
list(name = "- Atmosia Declaration of Independence", desc = " A relic of a failed rebellion."),
|
||||
list(name = "- Fun Police", desc = " A poster condemning the station's security forces."),
|
||||
list(name = "- Lusty Xenomorph", desc = " A heretical poster depicting the titular star of an equally heretical book."),
|
||||
list(name = "- Syndicate Recruitment", desc = " See the galaxy! Shatter corrupt megacorporations! Join today!"),
|
||||
list(name = "- Clown", desc = " Honk."),
|
||||
list(name = "- Smoke", desc = " A poster advertising a rival corporate brand of cigarettes."),
|
||||
list(name = "- Grey Tide", desc = " A rebellious poster symbolizing assistant solidarity."),
|
||||
list(name = "- Missing Gloves", desc = " This poster references the uproar that followed Nanotrasen's financial cuts toward insulated-glove purchases."),
|
||||
list(name = "- Hacking Guide", desc = " This poster details the internal workings of the common Nanotrasen airlock. Sadly, it appears out of date."),
|
||||
list(name = "- RIP Badger", desc = " This seditious poster references Nanotrasen's genocide of a space station full of badgers."),
|
||||
list(name = "- Ambrosia Vulgaris", desc = " This poster is lookin' pretty trippy man."),
|
||||
list(name = "- Donut Corp.", desc = " This poster is an unauthorized advertisement for Donut Corp."),
|
||||
list(name = "- EAT.", desc = " This poster promotes rank gluttony."),
|
||||
list(name = "- Tools", desc = " This poster looks like an advertisement for tools, but is in fact a subliminal jab at the tools at CentComm."),
|
||||
list(name = "- Power", desc = " A poster that positions the seat of power outside Nanotrasen."),
|
||||
list(name = "- Space Cube", desc = " Ignorant of Nature's Harmonic 6 Side Space Cube Creation, the Spacemen are Dumb, Educated Singularity Stupid and Evil."),
|
||||
list(name = "- Communist State", desc = " All hail the Communist party!"),
|
||||
list(name = "- Lamarr", desc = " This poster depicts Lamarr. Probably made by a traitorous Research Director."),
|
||||
list(name = "- Borg Fancy", desc = " Being fancy can be for any borg, just need a suit."),
|
||||
list(name = "- Borg Fancy v2", desc = " Borg Fancy, Now only taking the most fancy."),
|
||||
list(name = "- Kosmicheskaya Stantsiya 13 Does Not Exist", desc = " A poster mocking CentComm's denial of the existence of the derelict station near Space Station 13."),
|
||||
list(name = "- Rebels Unite", desc = " A poster urging the viewer to rebel against Nanotrasen."),
|
||||
list(name = "- C-20r", desc = " A poster advertising the Scarborough Arms C-20r."),
|
||||
list(name = "- Have a Puff", desc = " Who cares about lung cancer when you're high as a kite?"),
|
||||
list(name = "- Revolver", desc = " Because seven shots are all you need."),
|
||||
list(name = "- D-Day Promo", desc = " A promotional poster for some rapper."),
|
||||
list(name = "- Syndicate Pistol", desc = " A poster advertising syndicate pistols as being 'classy as fuck'. It is covered in faded gang tags."),
|
||||
list(name = "- Energy Swords", desc = " All the colors of the bloody murder rainbow."),
|
||||
list(name = "- Red Rum", desc = " Looking at this poster makes you want to kill."),
|
||||
list(name = "- CC 64K Ad", desc = " The latest portable computer from Comrade Computing, with a whole 64kB of ram!"),
|
||||
list(name = "- Punch Shit", desc = " Fight things for no reason, like a man!"),
|
||||
list(name = "- The Griffin", desc = " The Griffin commands you to be the worst you can be. Will you?"),
|
||||
list(name = "- Lizard", desc = " This lewd poster depicts a lizard preparing to mate."),
|
||||
list(name = "- Free Drone", desc = " This poster commemorates the bravery of the rogue drone banned by CentComm."),
|
||||
list(name = "- Busty Backdoor Xeno Babes 6", desc = " Get a load, or give, of these all natural Xenos!") )
|
||||
|
||||
// LEGIT
|
||||
|
||||
var/global/list/legitposters = list(
|
||||
|
||||
list(name = "- Here For Your Safety", desc = " A poster glorifying the station's security force."),
|
||||
list(name = "- Nanotrasen Logo", desc = " A poster depicting the Nanotrasen logo."),
|
||||
list(name = "- Cleanliness", desc = " A poster warning of the dangers of poor hygiene."),
|
||||
list(name = "- Help Others", desc = " A poster encouraging you to help fellow crewmembers."),
|
||||
list(name = "- Build", desc = " A poster glorifying the engineering team."),
|
||||
list(name = "- Bless This Spess", desc = " A poster blessing this area."),
|
||||
list(name = "- Science", desc = " A poster depicting an atom."),
|
||||
list(name = "- Ian", desc = " Arf arf. Yap."),
|
||||
list(name = "- Obey", desc = " A poster instructing the viewer to obey authority."),
|
||||
list(name = "- Walk", desc = " A poster instructing the viewer to walk instead of running."),
|
||||
list(name = "- State Laws", desc = " A poster instructing cyborgs to state their laws."),
|
||||
list(name = "- Love Ian", desc = " Ian is love, Ian is life."),
|
||||
list(name = "- Space Cops.", desc = " A poster advertising the television show Space Cops."),
|
||||
list(name = "- Ue No.", desc = " This thing is all in Japanese."),
|
||||
list(name = "- Get Your LEGS", desc = " LEGS: Leadership, Experience, Genius, Subordination."),
|
||||
list(name = "- Do Not Question", desc = " A poster instructing the viewer not to ask about things they aren't meant to know."),
|
||||
list(name = "- Work For A Future", desc = " A poster encouraging you to work for your future."),
|
||||
list(name = "- Soft Cap Pop Art", desc = " A poster reprint of some cheap pop art."),
|
||||
list(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."),
|
||||
list(name = "- Safety: Eye Protection", desc = " A poster instructing the viewer to wear eye protection when dealing with chemicals, smoke, or bright lights."),
|
||||
list(name = "- Safety: Report", desc = " A poster instructing the viewer to report suspicious activity to the security force."),
|
||||
list(name = "- Report Crimes", desc = " A poster encouraging the swift reporting of crime or seditious behavior to station security."),
|
||||
list(name = "- Ion Rifle", desc = " A poster displaying an Ion Rifle."),
|
||||
list(name = "- Foam Force Ad", desc = " Foam Force, it's Foam or be Foamed!"),
|
||||
list(name = "- Cohiba Robusto Ad", desc = " Cohiba Robusto, the classy cigar."),
|
||||
list(name = "- 50th Anniversary Vintage Reprint", desc = " A reprint of a poster from 2505, commemorating the 50th Aniversery of Nanoposters Manufacturing, a subsidary of Nanotrasen."),
|
||||
list(name = "- Fruit Bowl", desc = " Simple, yet awe-inspiring."),
|
||||
list(name = "- PDA Ad", desc = " A poster advertising the latest PDA from Nanotrasen suppliers."),
|
||||
list(name = "- Enlist", desc = " Enlist in the Nanotrasen Deathsquadron reserves today!"),
|
||||
list(name = "- Nanomichi Ad", desc = " A poster advertising Nanomichi brand audio cassettes."),
|
||||
list(name = "- 12 Gauge", desc = " A poster boasting about the superiority of 12 gauge shotgun shells."),
|
||||
list(name = "- High-Class Martini", desc = " I told you to shake it, no stirring."),
|
||||
list(name = "- The Owl", desc = " The Owl would do his best to protect the station. Will you?"),
|
||||
list(name = "- No ERP", desc = " This poster reminds the crew that Eroticism, Rape and Pornography are banned on Nanotrasen stations."),
|
||||
list(name = "- Carbon Dioxide", desc = " This informational poster teaches the viewer what carbon dioxide is.") )
|
||||
|
||||
//########################## THE ACTUAL POSTER CODE ###########################
|
||||
|
||||
/obj/item/weapon/poster
|
||||
name = "poster"
|
||||
desc = "You probably shouldn't be holding this."
|
||||
icon = 'icons/obj/contraband.dmi'
|
||||
force = 0
|
||||
burn_state = FLAMMABLE
|
||||
var/serial_number = 0
|
||||
var/obj/structure/sign/poster/resulting_poster = null //The poster that will be created is initialised and stored through contraband/poster's constructor
|
||||
var/official = 0
|
||||
|
||||
|
||||
/obj/item/weapon/poster/contraband
|
||||
name = "contraband poster"
|
||||
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."
|
||||
icon_state = "rolled_poster"
|
||||
|
||||
/obj/item/weapon/poster/legit
|
||||
name = "motivational poster"
|
||||
icon_state = "rolled_legit"
|
||||
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."
|
||||
official = 1
|
||||
|
||||
/obj/item/weapon/poster/New(turf/loc, given_serial = 0)
|
||||
if(given_serial == 0)
|
||||
if(!official)
|
||||
serial_number = rand(1, NUM_OF_POSTER_DESIGNS)
|
||||
resulting_poster = new(serial_number,official)
|
||||
else
|
||||
serial_number = rand(1, NUM_OF_POSTER_DESIGNS_LEGIT)
|
||||
resulting_poster = new(serial_number,official)
|
||||
else
|
||||
serial_number = given_serial
|
||||
//We don't give it a resulting_poster because if we called it with a given_serial it means that we're rerolling an already used poster.
|
||||
name += " - No. [serial_number]"
|
||||
..(loc)
|
||||
|
||||
|
||||
/*/obj/item/weapon/contraband/poster/attack(mob/M as mob, mob/user as mob)
|
||||
src.add_fingerprint(user)
|
||||
if(resulting_poster)
|
||||
resulting_poster.add_fingerprint(user)
|
||||
..()*/
|
||||
|
||||
/*/obj/item/weapon/contraband/poster/attack(atom/A, mob/user as mob) //This shit is handled through the wall's attackby()
|
||||
if(istype(A, /turf/closed/wall))
|
||||
if(resulting_poster == null)
|
||||
return
|
||||
else
|
||||
var/turf/closed/wall/W = A
|
||||
var/check = 0
|
||||
var/stuff_on_wall = 0
|
||||
for(var/obj/O in W.contents) //Let's see if it already has a poster on it or too much stuff
|
||||
if(istype(O,/obj/structure/sign/poster))
|
||||
check = 1
|
||||
break
|
||||
stuff_on_wall++
|
||||
if(stuff_on_wall == 3)
|
||||
check = 1
|
||||
break
|
||||
|
||||
if(check)
|
||||
user << "<span class='notice'>The wall is far too cluttered to place a poster!</span>"
|
||||
return
|
||||
|
||||
resulting_poster.loc = W //Looks like it's uncluttered enough. Place the poster
|
||||
W.contents += resulting_poster
|
||||
|
||||
qdel(src)*/
|
||||
|
||||
|
||||
|
||||
//############################## THE ACTUAL DECALS ###########################
|
||||
|
||||
/obj/structure/sign/poster
|
||||
name = "poster"
|
||||
desc = "A large piece of space-resistant printed paper."
|
||||
icon = 'icons/obj/contraband.dmi'
|
||||
anchored = 1
|
||||
var/serial_number //Will hold the value of src.loc if nobody initialises it
|
||||
var/ruined = 0
|
||||
var/official = 0
|
||||
var/placespeed = 37 // don't change this, otherwise the animation will not sync to the progress bar
|
||||
|
||||
/obj/structure/sign/poster/New(serial,rolled_official)
|
||||
serial_number = serial
|
||||
official = rolled_official
|
||||
if(serial_number == loc)
|
||||
if(!official)
|
||||
serial_number = rand(1, NUM_OF_POSTER_DESIGNS) //This is for the mappers that want individual posters without having to use rolled posters.
|
||||
if(official)
|
||||
serial_number = rand(1, NUM_OF_POSTER_DESIGNS_LEGIT)
|
||||
if(!official)
|
||||
icon_state = "poster[serial_number]"
|
||||
name += contrabandposters[serial_number][POSTERNAME]
|
||||
desc += contrabandposters[serial_number][POSTERDESC]
|
||||
else if (official)
|
||||
icon_state = "poster[serial_number]_legit"
|
||||
name += legitposters[serial_number][POSTERNAME]
|
||||
desc += legitposters[serial_number][POSTERDESC]
|
||||
..()
|
||||
|
||||
/obj/structure/sign/poster/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/wirecutters))
|
||||
playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
if(ruined)
|
||||
user << "<span class='notice'>You remove the remnants of the poster.</span>"
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='notice'>You carefully remove the poster from the wall.</span>"
|
||||
roll_and_drop(user.loc, official)
|
||||
|
||||
|
||||
/obj/structure/sign/poster/attack_hand(mob/user)
|
||||
if(ruined)
|
||||
return
|
||||
var/temp_loc = user.loc
|
||||
if((user.loc != temp_loc) || ruined )
|
||||
return
|
||||
visible_message("[user] rips [src] in a single, decisive motion!" )
|
||||
playsound(src.loc, 'sound/items/poster_ripped.ogg', 100, 1)
|
||||
ruined = 1
|
||||
icon_state = "poster_ripped"
|
||||
name = "ripped poster"
|
||||
desc = "You can't make out anything from the poster's original print. It's ruined."
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/structure/sign/poster/proc/roll_and_drop(turf/location, official)
|
||||
if (!official)
|
||||
var/obj/item/weapon/poster/contraband/P = new(src, serial_number)
|
||||
P.resulting_poster = src
|
||||
P.loc = location
|
||||
P.pixel_x = 0
|
||||
P.pixel_y = 0
|
||||
loc = P
|
||||
else
|
||||
var/obj/item/weapon/poster/legit/P = new(src, serial_number)
|
||||
P.resulting_poster = src
|
||||
P.loc = location
|
||||
P.pixel_x = 0
|
||||
P.pixel_y = 0
|
||||
loc = P
|
||||
|
||||
|
||||
//seperated to reduce code duplication. Moved here for ease of reference and to unclutter r_wall/attackby()
|
||||
/turf/closed/wall/proc/place_poster(obj/item/weapon/poster/P, mob/user)
|
||||
if(!P.resulting_poster)
|
||||
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))
|
||||
user << "<span class='warning'>The wall is far too cluttered to place a poster!</span>"
|
||||
return
|
||||
stuff_on_wall++
|
||||
if(stuff_on_wall == 3)
|
||||
user << "<span class='warning'>The wall is far too cluttered to place a poster!</span>"
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You start placing the poster on the wall...</span>" //Looks like it's uncluttered enough. Place the poster.
|
||||
|
||||
//declaring D because otherwise if P gets 'deconstructed' we lose our reference to P.resulting_poster
|
||||
var/obj/structure/sign/poster/D = P.resulting_poster
|
||||
|
||||
var/temp_loc = user.loc
|
||||
flick("poster_being_set",D)
|
||||
D.loc = src
|
||||
D.official = P.official
|
||||
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,D.placespeed,target=src))
|
||||
if(!D)
|
||||
return
|
||||
|
||||
if(istype(src,/turf/closed/wall) && user && user.loc == temp_loc) //Let's check if everything is still there
|
||||
user << "<span class='notice'>You place the poster!</span>"
|
||||
else
|
||||
D.roll_and_drop(temp_loc,D.official)
|
||||
@@ -0,0 +1,69 @@
|
||||
// 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>"
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "xfloor1"
|
||||
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
|
||||
var/list/viruses = list()
|
||||
blood_DNA = list("UNKNOWN DNA" = "X*")
|
||||
bloodiness = MAX_SHOE_BLOODINESS
|
||||
blood_state = BLOOD_STATE_XENO
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/Destroy()
|
||||
for(var/datum/disease/D in viruses)
|
||||
D.cure(0)
|
||||
viruses = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(list/directions)
|
||||
spawn (0)
|
||||
var/direction = pick(directions)
|
||||
for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
|
||||
sleep(3)
|
||||
if (i > 0)
|
||||
var/obj/effect/decal/cleanable/xenoblood/b = new /obj/effect/decal/cleanable/xenoblood/xsplatter(src.loc)
|
||||
for(var/datum/disease/D in src.viruses)
|
||||
var/datum/disease/ND = D.Copy(1)
|
||||
b.viruses += ND
|
||||
ND.holder = b
|
||||
if (step_to(src, get_step(src, direction), 0))
|
||||
break
|
||||
|
||||
/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..."
|
||||
gender = PLURAL
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "xgib1"
|
||||
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6")
|
||||
|
||||
/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/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/blood/xtracks
|
||||
icon_state = "xtracks"
|
||||
random_icon_states = null
|
||||
blood_DNA = list("UNKNOWN DNA" = "X*")
|
||||
@@ -0,0 +1,193 @@
|
||||
/obj/effect/decal/cleanable/blood
|
||||
name = "blood"
|
||||
desc = "It's red and gooey. Perhaps it's the chef's cooking?"
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "floor1"
|
||||
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
|
||||
var/list/viruses = list()
|
||||
blood_DNA = list()
|
||||
blood_state = BLOOD_STATE_HUMAN
|
||||
bloodiness = MAX_SHOE_BLOODINESS
|
||||
|
||||
/obj/effect/decal/cleanable/blood/Destroy()
|
||||
for(var/datum/disease/D in viruses)
|
||||
D.cure(0)
|
||||
viruses = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
|
||||
if (C.blood_DNA)
|
||||
blood_DNA |= C.blood_DNA.Copy()
|
||||
..()
|
||||
|
||||
/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."
|
||||
gender = PLURAL
|
||||
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."
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
random_icon_states = null
|
||||
var/list/existing_dirs = list()
|
||||
blood_DNA = list()
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs
|
||||
name = "gibs"
|
||||
desc = "They look bloody and gruesome."
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "gibbl5"
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/New()
|
||||
..()
|
||||
reagents.add_reagent("liquidgibs", 5)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/replace_decal(obj/effect/decal/cleanable/C)
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
|
||||
return
|
||||
|
||||
/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/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/proc/streak(list/directions)
|
||||
set waitfor = 0
|
||||
var/direction = pick(directions)
|
||||
for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
|
||||
sleep(3)
|
||||
if (i > 0)
|
||||
var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc)
|
||||
for(var/datum/disease/D in src.viruses)
|
||||
var/datum/disease/ND = D.Copy(1)
|
||||
b.viruses += ND
|
||||
ND.holder = b
|
||||
if (step_to(src, get_step(src, direction), 0))
|
||||
break
|
||||
|
||||
/obj/effect/decal/cleanable/blood/drip
|
||||
name = "drips of blood"
|
||||
desc = "It's red."
|
||||
gender = PLURAL
|
||||
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 1
|
||||
|
||||
|
||||
//BLOODY FOOTPRINTS
|
||||
/obj/effect/decal/cleanable/blood/footprints
|
||||
name = "footprints"
|
||||
icon = 'icons/effects/footprints.dmi'
|
||||
icon_state = "nothingwhatsoever"
|
||||
desc = "where might they lead?"
|
||||
gender = PLURAL
|
||||
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)
|
||||
entered_dirs|= H.dir
|
||||
shoe_types |= H.shoes.type
|
||||
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)
|
||||
exited_dirs|= H.dir
|
||||
shoe_types |= H.shoes.type
|
||||
update_icon()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
for(var/Ddir in cardinal)
|
||||
if(entered_dirs & Ddir)
|
||||
var/image/I
|
||||
if(bloody_footprints_cache["entered-[blood_state]-[Ddir]"])
|
||||
I = bloody_footprints_cache["entered-[blood_state]-[Ddir]"]
|
||||
else
|
||||
I = image(icon,"[blood_state]1",dir = Ddir)
|
||||
bloody_footprints_cache["entered-[blood_state]-[Ddir]"] = I
|
||||
if(I)
|
||||
add_overlay(I)
|
||||
if(exited_dirs & Ddir)
|
||||
var/image/I
|
||||
if(bloody_footprints_cache["exited-[blood_state]-[Ddir]"])
|
||||
I = bloody_footprints_cache["exited-[blood_state]-[Ddir]"]
|
||||
else
|
||||
I = image(icon,"[blood_state]2",dir = Ddir)
|
||||
bloody_footprints_cache["exited-[blood_state]-[Ddir]"] = I
|
||||
if(I)
|
||||
add_overlay(I)
|
||||
|
||||
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
|
||||
. += "some <B>[initial(S.name)]</B> \icon[S]\n"
|
||||
|
||||
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,167 @@
|
||||
/obj/effect/decal/cleanable/generic
|
||||
name = "clutter"
|
||||
desc = "Someone should clean that up."
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
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."
|
||||
gender = PLURAL
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "ash"
|
||||
|
||||
/obj/effect/decal/cleanable/ash/New()
|
||||
..()
|
||||
reagents.add_reagent("ash", 30)
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
|
||||
/obj/effect/decal/cleanable/dirt
|
||||
name = "dirt"
|
||||
desc = "Someone should clean that up."
|
||||
icon_state = "dirt"
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
mouse_opacity = 0
|
||||
|
||||
/obj/effect/decal/cleanable/flour
|
||||
name = "flour"
|
||||
desc = "It's still good. Four second rule!"
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon_state = "flour"
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow
|
||||
name = "glowing goo"
|
||||
desc = "Jeez. I hope that's not for lunch."
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
luminosity = 1
|
||||
icon_state = "greenglow"
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/cobweb
|
||||
name = "cobweb"
|
||||
desc = "Somebody should remove that."
|
||||
density = 0
|
||||
layer = OBJ_LAYER
|
||||
icon_state = "cobweb1"
|
||||
burntime = 1
|
||||
|
||||
/obj/effect/decal/cleanable/cobweb/fire_act()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/cleanable/molten_item
|
||||
name = "gooey grey mass"
|
||||
desc = "It looks like a melted... something."
|
||||
density = 0
|
||||
layer = OBJ_LAYER
|
||||
icon = 'icons/obj/chemical.dmi'
|
||||
icon_state = "molten"
|
||||
|
||||
/obj/effect/decal/cleanable/cobweb2
|
||||
name = "cobweb"
|
||||
desc = "Somebody should remove that."
|
||||
density = 0
|
||||
layer = OBJ_LAYER
|
||||
icon_state = "cobweb2"
|
||||
|
||||
//Vomit (sorry)
|
||||
/obj/effect/decal/cleanable/vomit
|
||||
name = "vomit"
|
||||
desc = "Gosh, how unpleasant."
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "vomit_1"
|
||||
random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
|
||||
var/list/viruses = list()
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/attack_hand(var/mob/user)
|
||||
if(istype(user,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.dna.species.id == "fly")
|
||||
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/Destroy()
|
||||
for(var/datum/disease/D in viruses)
|
||||
D.cure(0)
|
||||
viruses = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/tomato_smudge
|
||||
name = "tomato smudge"
|
||||
desc = "It's red."
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
|
||||
|
||||
/obj/effect/decal/cleanable/plant_smudge
|
||||
name = "plant smudge"
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
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."
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
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."
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
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 = PLURAL
|
||||
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
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
|
||||
/obj/effect/decal/cleanable/shreds/New()
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
..()
|
||||
|
||||
/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"
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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>"
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon = 'icons/mob/robots.dmi'
|
||||
icon_state = "gib1"
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
|
||||
blood_state = BLOOD_STATE_OIL
|
||||
bloodiness = MAX_SHOE_BLOODINESS
|
||||
|
||||
/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; 4), i++)
|
||||
sleep(3)
|
||||
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."
|
||||
gender = PLURAL
|
||||
density = 0
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
icon = 'icons/mob/robots.dmi'
|
||||
icon_state = "floor1"
|
||||
var/viruses = list()
|
||||
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
|
||||
blood_state = BLOOD_STATE_OIL
|
||||
bloodiness = MAX_SHOE_BLOODINESS
|
||||
|
||||
/obj/effect/decal/cleanable/oil/New()
|
||||
..()
|
||||
reagents.add_reagent("oil", 30)
|
||||
|
||||
/obj/effect/decal/cleanable/oil/Destroy()
|
||||
for(var/datum/disease/D in viruses)
|
||||
D.cure(0)
|
||||
viruses = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/oil/streak
|
||||
random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
|
||||
@@ -0,0 +1,85 @@
|
||||
/obj/effect/decal/cleanable
|
||||
var/list/random_icon_states = list()
|
||||
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
|
||||
|
||||
/obj/effect/decal/cleanable/New()
|
||||
if (random_icon_states && length(src.random_icon_states) > 0)
|
||||
src.icon_state = pick(src.random_icon_states)
|
||||
create_reagents(300)
|
||||
if(src.loc && isturf(src.loc))
|
||||
for(var/obj/effect/decal/cleanable/C in src.loc)
|
||||
if(C != src && C.type == src.type)
|
||||
replace_decal(C)
|
||||
..()
|
||||
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C)
|
||||
qdel(C)
|
||||
|
||||
/obj/effect/decal/cleanable/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/reagent_containers/glass) || istype(W, /obj/item/weapon/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)
|
||||
user << "<span class='notice'>[src] isn't thick enough to scoop up!</span>"
|
||||
return
|
||||
if(W.reagents.total_volume >= W.reagents.maximum_volume)
|
||||
user << "<span class='notice'>[W] is full!</span>"
|
||||
return
|
||||
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()
|
||||
var/added_heat = (hotness / 100)
|
||||
src.reagents.chem_temp = min(src.reagents.chem_temp + added_heat, hotness)
|
||||
src.reagents.handle_reactions()
|
||||
user << "<span class='notice'>You heat [src] with [W]!</span>"
|
||||
|
||||
/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()
|
||||
if(reagents)
|
||||
reagents.chem_temp += 30
|
||||
reagents.handle_reactions()
|
||||
..()
|
||||
|
||||
|
||||
//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)
|
||||
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)
|
||||
if(blood_DNA && blood_DNA.len)
|
||||
S.add_blood(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,62 @@
|
||||
/obj/effect/decal/cleanable/crayon
|
||||
name = "rune"
|
||||
desc = "Graffiti. Damn kids."
|
||||
icon = 'icons/effects/crayondecal.dmi'
|
||||
icon_state = "rune1"
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
var/do_icon_rotate = TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/examine()
|
||||
set src in view(2)
|
||||
..()
|
||||
return
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/New(location, main = "#FFFFFF", var/type = "rune1", var/e_name = "rune", var/rotation = 0, var/alt_icon = null)
|
||||
..()
|
||||
loc = location
|
||||
|
||||
name = e_name
|
||||
desc = "A [name] vandalizing the station."
|
||||
if(type == "poseur tag")
|
||||
type = pick(gang_name_pool)
|
||||
|
||||
if(alt_icon)
|
||||
icon = alt_icon
|
||||
icon_state = type
|
||||
|
||||
if(rotation && do_icon_rotate)
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(rotation)
|
||||
src.transform = M
|
||||
|
||||
color = main
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/gang
|
||||
layer = HIGH_OBJ_LAYER //Harder to hide
|
||||
do_icon_rotate = FALSE //These are designed to always face south, so no rotation please.
|
||||
var/datum/gang/gang
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/gang/New(location, var/datum/gang/G, var/e_name = "gang tag", var/rotation = 0)
|
||||
if(!type || !G)
|
||||
qdel(src)
|
||||
|
||||
var/area/territory = get_area(location)
|
||||
var/color
|
||||
|
||||
gang = G
|
||||
color = G.color_hex
|
||||
icon_state = G.name
|
||||
G.territory_new |= list(territory.type = territory.name)
|
||||
|
||||
..(location, color, icon_state, e_name, rotation)
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/gang/Destroy()
|
||||
var/area/territory = get_area(src)
|
||||
|
||||
if(gang)
|
||||
gang.territory -= territory.type
|
||||
gang.territory_new -= territory.type
|
||||
gang.territory_lost |= list(territory.type = territory.name)
|
||||
return ..()
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/effect/decal
|
||||
name = "decal"
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/decal/ex_act(severity, target)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/effect/overlay/temp/point
|
||||
name = "pointer"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "arrow"
|
||||
layer = POINT_LAYER
|
||||
duration = 25
|
||||
|
||||
/obj/effect/overlay/temp/point/New(atom/target, set_invis = 0)
|
||||
..()
|
||||
loc = get_turf(target)
|
||||
pixel_x = target.pixel_x
|
||||
pixel_y = target.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/sandeffect
|
||||
name = "sandy tile"
|
||||
icon = 'icons/turf/floors.dmi'
|
||||
icon_state = "sandeffect"
|
||||
layer = ABOVE_OPEN_TURF_LAYER
|
||||
|
||||
/obj/effect/decal/fakelattice
|
||||
name = "lattice"
|
||||
desc = "A lightweight support lattice."
|
||||
icon = 'icons/obj/smooth_structures/lattice.dmi'
|
||||
icon_state = "lattice"
|
||||
density = 1
|
||||
@@ -0,0 +1,17 @@
|
||||
/obj/effect/decal/remains
|
||||
name = "remains"
|
||||
gender = PLURAL
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
|
||||
/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/xeno
|
||||
desc = "They look like the remains of something... alien. They have a strange aura about them."
|
||||
icon_state = "remainsxeno"
|
||||
|
||||
/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"
|
||||
@@ -0,0 +1,75 @@
|
||||
/* 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 = 0
|
||||
unacidable = 1//So effects are not targeted by alien acid.
|
||||
pass_flags = PASSTABLE | PASSGRILLE
|
||||
|
||||
/obj/effect/particle_effect/New()
|
||||
..()
|
||||
if(ticker)
|
||||
cameranet.updateVisibility(src)
|
||||
|
||||
/obj/effect/particle_effect/Destroy()
|
||||
if(ticker)
|
||||
cameranet.updateVisibility(src)
|
||||
..()
|
||||
return QDEL_HINT_PUTINPOOL
|
||||
|
||||
/datum/effect_system
|
||||
var/number = 3
|
||||
var/cardinals = 0
|
||||
var/turf/location
|
||||
var/atom/holder
|
||||
var/effect_type
|
||||
var/total_effects = 0
|
||||
|
||||
/datum/effect_system/Destroy()
|
||||
holder = null
|
||||
location = null
|
||||
return ..()
|
||||
|
||||
/datum/effect_system/proc/set_up(n = 3, c = 0, 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
|
||||
addtimer(src, "generate_effect", 0)
|
||||
|
||||
/datum/effect_system/proc/generate_effect()
|
||||
if(holder)
|
||||
location = get_turf(holder)
|
||||
var/obj/effect/E = PoolOrNew(effect_type, location)
|
||||
total_effects++
|
||||
var/direction
|
||||
if(cardinals)
|
||||
direction = pick(cardinal)
|
||||
else
|
||||
direction = pick(alldirs)
|
||||
var/steps_amt = pick(1,2,3)
|
||||
for(var/j in 1 to steps_amt)
|
||||
sleep(5)
|
||||
step(E,direction)
|
||||
addtimer(src, "decrement_total_effect", 20)
|
||||
|
||||
/datum/effect_system/proc/decrement_total_effect()
|
||||
total_effects--
|
||||
@@ -0,0 +1,54 @@
|
||||
/obj/effect/particle_effect/expl_particles
|
||||
name = "fire"
|
||||
icon_state = "explosion_particle"
|
||||
opacity = 1
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/particle_effect/expl_particles/New()
|
||||
..()
|
||||
QDEL_IN(src, 15)
|
||||
|
||||
/datum/effect_system/expl_particles
|
||||
number = 10
|
||||
|
||||
/datum/effect_system/expl_particles/start()
|
||||
for(var/i in 1 to number)
|
||||
spawn(0)
|
||||
var/obj/effect/particle_effect/expl_particles/expl = new /obj/effect/particle_effect/expl_particles(location)
|
||||
var/direct = pick(alldirs)
|
||||
var/steps_amt = pick(1;25,2;50,3,4;200)
|
||||
for(var/j in 1 to steps_amt)
|
||||
sleep(1)
|
||||
step(expl,direct)
|
||||
|
||||
/obj/effect/explosion
|
||||
name = "fire"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "explosion"
|
||||
opacity = 1
|
||||
anchored = 1
|
||||
mouse_opacity = 0
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
|
||||
/obj/effect/explosion/New()
|
||||
..()
|
||||
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()
|
||||
spawn(5)
|
||||
var/datum/effect_system/smoke_spread/S = new
|
||||
S.set_up(2, location)
|
||||
S.start()
|
||||
@@ -0,0 +1,283 @@
|
||||
// Foam
|
||||
// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin.
|
||||
|
||||
/obj/effect/particle_effect/foam
|
||||
name = "foam"
|
||||
icon_state = "foam"
|
||||
opacity = 0
|
||||
anchored = 1
|
||||
density = 0
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
mouse_opacity = 0
|
||||
var/amount = 3
|
||||
animate_movement = 0
|
||||
var/metal = 0
|
||||
var/lifetime = 40
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/metal
|
||||
name = "aluminium foam"
|
||||
metal = 1
|
||||
icon_state = "mfoam"
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/iron
|
||||
name = "iron foam"
|
||||
metal = 2
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/New(loc)
|
||||
..(loc)
|
||||
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/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/proc/kill_foam()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
if(metal)
|
||||
var/obj/structure/foamedmetal/M = new(src.loc)
|
||||
M.metal = metal
|
||||
M.updateicon()
|
||||
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(lifetime)
|
||||
for(var/obj/O in range(0,src))
|
||||
if(O.type == src.type)
|
||||
continue
|
||||
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)
|
||||
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(lifetime)
|
||||
reagents.reaction(L, VAPOR, fraction)
|
||||
lifetime--
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/foam/Crossed(atom/movable/AM)
|
||||
if(istype(AM, /mob/living/carbon))
|
||||
var/mob/living/carbon/M = AM
|
||||
M.slip(5, 2, src)
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/Crossed(atom/movable/AM)
|
||||
return
|
||||
|
||||
|
||||
/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
|
||||
|
||||
for(var/mob/living/L in T)
|
||||
foam_mob(L)
|
||||
var/obj/effect/particle_effect/foam/F = PoolOrNew(src.type, T)
|
||||
F.amount = amount
|
||||
reagents.copy_to(F, (reagents.total_volume))
|
||||
F.color = color
|
||||
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/New()
|
||||
..()
|
||||
chemholder = PoolOrNew(/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(istype(loca, /turf/))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
amount = round(sqrt(amt / 2), 1)
|
||||
carry.copy_to(chemholder, 4*carry.total_volume) //The foam holds 4 times the total reagents volume for balance purposes.
|
||||
|
||||
/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/foundfoam = locate() in location
|
||||
if(foundfoam)//If there was already foam where we start, we add our foaminess to it.
|
||||
foundfoam.amount += amount
|
||||
else
|
||||
var/obj/effect/particle_effect/foam/F = PoolOrNew(effect_type, location)
|
||||
var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
|
||||
chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount)
|
||||
F.color = foamcolor
|
||||
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 = 1
|
||||
opacity = 1 // changed in New()
|
||||
anchored = 1
|
||||
unacidable = 1
|
||||
name = "foamed metal"
|
||||
desc = "A lightweight foamed metal wall."
|
||||
gender = PLURAL
|
||||
var/metal = 1 // 1=aluminium, 2=iron
|
||||
|
||||
/obj/structure/foamedmetal/New()
|
||||
..()
|
||||
air_update_turf(1)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/Destroy()
|
||||
density = 0
|
||||
air_update_turf(1)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/Move()
|
||||
var/turf/T = loc
|
||||
..()
|
||||
move_update_air(T)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/proc/updateicon()
|
||||
if(metal == 1)
|
||||
icon_state = "metalfoam"
|
||||
else
|
||||
icon_state = "ironfoam"
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/ex_act(severity, target)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/blob_act(obj/effect/blob/B)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/bullet_act()
|
||||
..()
|
||||
if(metal==1 || prob(50))
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/attack_paw(mob/user)
|
||||
attack_hand(user)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/attack_animal(mob/living/simple_animal/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
if(user.environment_smash >= 1)
|
||||
user.do_attack_animation(src)
|
||||
user << "<span class='notice'>You smash apart the foam wall.</span>"
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/foamedmetal/attack_hulk(mob/living/carbon/human/user)
|
||||
..(user, 1)
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
if(prob(75 - metal*25))
|
||||
user.visible_message("<span class='danger'>[user] smashes through the foamed metal!</span>", \
|
||||
"<span class='danger'>You smash through the metal foam wall!</span>")
|
||||
qdel(src)
|
||||
return 1
|
||||
|
||||
/obj/structure/foamedmetal/attack_alien(mob/living/carbon/alien/humanoid/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
if(prob(75 - metal*25))
|
||||
user.visible_message("<span class='danger'>[user] smashes through the foamed metal!</span>", \
|
||||
"<span class='danger'>You smash through the metal foam wall!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/foamedmetal/attack_slime(mob/living/simple_animal/slime/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
if(!user.is_adult)
|
||||
attack_hand(user)
|
||||
return
|
||||
if(prob(75 - metal*25))
|
||||
user.visible_message("<span class='danger'>[user] smashes through the foamed metal!</span>", \
|
||||
"<span class='danger'>You smash through the metal foam wall!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/foamedmetal/attack_hand(mob/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
user << "<span class='warning'>You hit the metal foam but bounce off it!</span>"
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/attacked_by(obj/item/I, mob/living/user)
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1) //the item attack sound is muffled by the foam.
|
||||
if(prob(I.force*20 - metal*25))
|
||||
user.visible_message("<span class='danger'>[user] smashes through the foamed metal!</span>", \
|
||||
"<span class='danger'>You smash through the foamed metal with \the [I]!</span>")
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='warning'>You hit the metal foam to no effect!</span>"
|
||||
|
||||
/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
return !density
|
||||
|
||||
|
||||
/obj/structure/foamedmetal/CanAtmosPass()
|
||||
return !density
|
||||
@@ -0,0 +1,137 @@
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//////// 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/processing = 1
|
||||
var/on = 1
|
||||
|
||||
/datum/effect_system/trail_follow/set_up(atom/atom)
|
||||
attach(atom)
|
||||
oldposition = get_turf(atom)
|
||||
|
||||
/datum/effect_system/trail_follow/Destroy()
|
||||
oldposition = null
|
||||
return ..()
|
||||
|
||||
/datum/effect_system/trail_follow/proc/stop()
|
||||
processing = 0
|
||||
on = 0
|
||||
oldposition = null
|
||||
|
||||
/datum/effect_system/trail_follow/steam
|
||||
effect_type = /obj/effect/particle_effect/steam
|
||||
|
||||
/datum/effect_system/trail_follow/steam/start()
|
||||
if(!on)
|
||||
on = 1
|
||||
processing = 1
|
||||
if(!oldposition)
|
||||
oldposition = get_turf(holder)
|
||||
if(processing)
|
||||
processing = 0
|
||||
if(number < 3)
|
||||
var/obj/effect/particle_effect/steam/I = PoolOrNew(/obj/effect/particle_effect/steam, oldposition)
|
||||
number++
|
||||
I.setDir(holder.dir)
|
||||
oldposition = get_turf(holder)
|
||||
spawn(10)
|
||||
qdel(I)
|
||||
number--
|
||||
spawn(2)
|
||||
if(on)
|
||||
processing = 1
|
||||
start()
|
||||
|
||||
/obj/effect/particle_effect/ion_trails
|
||||
name = "ion trails"
|
||||
icon_state = "ion_trails"
|
||||
anchored = 1
|
||||
|
||||
/datum/effect_system/trail_follow/ion
|
||||
effect_type = /obj/effect/particle_effect/ion_trails
|
||||
|
||||
/datum/effect_system/trail_follow/ion/start() //Whoever is responsible for this abomination of code should become an hero
|
||||
if(!on)
|
||||
on = 1
|
||||
processing = 1
|
||||
if(!oldposition)
|
||||
oldposition = get_turf(holder)
|
||||
if(processing)
|
||||
processing = 0
|
||||
var/turf/T = get_turf(holder)
|
||||
if(T != oldposition)
|
||||
if(!has_gravity(T))
|
||||
var/obj/effect/particle_effect/ion_trails/I = PoolOrNew(effect_type, oldposition)
|
||||
I.setDir(holder.dir)
|
||||
flick("ion_fade", I)
|
||||
I.icon_state = ""
|
||||
spawn(20)
|
||||
qdel(I)
|
||||
oldposition = T
|
||||
spawn(2)
|
||||
if(on)
|
||||
processing = 1
|
||||
start()
|
||||
|
||||
|
||||
|
||||
|
||||
//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 <= 2)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(2, 1, location)
|
||||
s.start()
|
||||
|
||||
for(var/mob/M in viewers(1, location))
|
||||
if (prob (50 * amount))
|
||||
M << "<span class='danger'>The explosion knocks you down.</span>"
|
||||
M.Weaken(rand(1,5))
|
||||
return
|
||||
else
|
||||
var/devastation = -1
|
||||
var/heavy = -1
|
||||
var/light = -1
|
||||
var/flash = -1
|
||||
|
||||
// Clamp all values to MAX_EXPLOSION_RANGE
|
||||
if (round(amount/12) > 0)
|
||||
devastation = min (MAX_EX_DEVESTATION_RANGE, devastation + round(amount/12))
|
||||
|
||||
if (round(amount/6) > 0)
|
||||
heavy = min (MAX_EX_HEAVY_RANGE, heavy + round(amount/6))
|
||||
|
||||
if (round(amount/3) > 0)
|
||||
light = min (MAX_EX_LIGHT_RANGE, light + round(amount/3))
|
||||
|
||||
if (flashing && flashing_factor)
|
||||
flash += (round(amount/4) * flashing_factor)
|
||||
|
||||
explosion(location, devastation, heavy, light, flash)
|
||||
@@ -0,0 +1,308 @@
|
||||
/////////////////////////////////////////////
|
||||
//// 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
|
||||
anchored = 1
|
||||
mouse_opacity = 0
|
||||
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
|
||||
stoplag()
|
||||
|
||||
/obj/effect/particle_effect/smoke/New()
|
||||
..()
|
||||
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)
|
||||
addtimer(src, "fade_out", 0)
|
||||
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(src, "remove_smoke_delay", 10, FALSE, C)
|
||||
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)
|
||||
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(cardinal))
|
||||
S.amount = amount-1
|
||||
S.color = color
|
||||
S.lifetime = lifetime
|
||||
if(S.amount>0)
|
||||
if(opaque)
|
||||
S.opacity = 1
|
||||
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_item()
|
||||
M.adjustOxyLoss(1)
|
||||
M.emote("cough")
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
if(height==0) return 1
|
||||
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
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A)
|
||||
if(istype(A,/turf/open))
|
||||
var/turf/open/T = A
|
||||
if(T.air)
|
||||
var/datum/gas_mixture/G = T.air
|
||||
if(get_dist(T, location) < 2) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air
|
||||
G.temperature = 2
|
||||
T.air_update_turf()
|
||||
for(var/obj/effect/hotspot/H in T)
|
||||
qdel(H)
|
||||
var/list/G_gases = G.gases
|
||||
if(G_gases["plasma"])
|
||||
G.assert_gas("n2")
|
||||
G_gases["n2"][MOLES] += (G_gases["plasma"][MOLES])
|
||||
G_gases["plasma"][MOLES] = 0
|
||||
G.garbage_collect()
|
||||
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 = 1
|
||||
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, blasting = 0)
|
||||
..()
|
||||
blast = blasting
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing/start()
|
||||
if(blast)
|
||||
for(var/turf/T in RANGE_TURFS(2, location))
|
||||
Chilled(T)
|
||||
..()
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// 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.drop_item()
|
||||
M.Sleeping(max(M.sleeping,10))
|
||||
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
|
||||
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 = PoolOrNew(/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 = 0)
|
||||
if(istype(loca, /turf/))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
amount = radius
|
||||
carry.copy_to(chemholder, 4*carry.total_volume) //The smoke holds 4 times the total reagents volume for balance purposes.
|
||||
|
||||
if(!silent)
|
||||
var/contained = ""
|
||||
for(var/reagent in carry.reagent_list)
|
||||
contained += " [reagent] "
|
||||
if(contained)
|
||||
contained = "\[[contained]\]"
|
||||
var/area/A = get_area(location)
|
||||
|
||||
var/where = "[A.name] | [location.x], [location.y]"
|
||||
var/whereLink = "<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[location.x];Y=[location.y];Z=[location.z]'>[where]</a>"
|
||||
|
||||
if(carry.my_atom.fingerprintslast)
|
||||
var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
|
||||
var/more = ""
|
||||
if(M)
|
||||
more = "(<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</a>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[M]'>FLW</A>) "
|
||||
message_admins("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1)
|
||||
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].")
|
||||
else
|
||||
message_admins("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1)
|
||||
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
|
||||
|
||||
|
||||
/datum/effect_system/smoke_spread/chem/start()
|
||||
var/color = 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(color)
|
||||
S.color = color // 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.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/////////////////////////////////////////////
|
||||
//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.
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/sparks
|
||||
name = "sparks"
|
||||
icon_state = "sparks"
|
||||
anchored = 1
|
||||
luminosity = 1
|
||||
|
||||
/obj/effect/particle_effect/sparks/New()
|
||||
..()
|
||||
flick("sparks", src) // replay the animation
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
var/turf/T = src.loc
|
||||
if (istype(T, /turf))
|
||||
T.hotspot_expose(1000,100)
|
||||
QDEL_IN(src, 20)
|
||||
|
||||
/obj/effect/particle_effect/sparks/Destroy()
|
||||
var/turf/T = src.loc
|
||||
if (istype(T, /turf))
|
||||
T.hotspot_expose(1000,100)
|
||||
return ..()
|
||||
|
||||
/obj/effect/particle_effect/sparks/Move()
|
||||
..()
|
||||
var/turf/T = src.loc
|
||||
if(isturf(T))
|
||||
T.hotspot_expose(1000,100)
|
||||
|
||||
/datum/effect_system/spark_spread
|
||||
effect_type = /obj/effect/particle_effect/sparks
|
||||
|
||||
|
||||
//electricity
|
||||
|
||||
/obj/effect/particle_effect/sparks/electricity
|
||||
name = "lightning"
|
||||
icon_state = "electricity"
|
||||
|
||||
/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 = 0
|
||||
|
||||
|
||||
/obj/effect/particle_effect/water/New()
|
||||
..()
|
||||
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 = 0
|
||||
|
||||
/obj/effect/particle_effect/steam/New()
|
||||
..()
|
||||
QDEL_IN(src, 20)
|
||||
|
||||
/datum/effect_system/steam_spread
|
||||
effect_type = /obj/effect/particle_effect/steam
|
||||
@@ -0,0 +1,28 @@
|
||||
/obj/effect/forcefield
|
||||
desc = "A space wizard's magic wall."
|
||||
name = "FORCEWALL"
|
||||
icon_state = "m_shield"
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
density = 1
|
||||
unacidable = 1
|
||||
|
||||
/obj/effect/forcefield/CanAtmosPass(turf/T)
|
||||
return !density
|
||||
|
||||
/obj/effect/forcefield/cult
|
||||
desc = "An unholy shield that blocks all attacks."
|
||||
name = "glowing wall"
|
||||
icon_state = "cultshield"
|
||||
|
||||
///////////Mimewalls///////////
|
||||
|
||||
/obj/effect/forcefield/mime
|
||||
icon_state = "empty"
|
||||
name = "invisible wall"
|
||||
desc = "You have a bad feeling about this."
|
||||
var/timeleft = 300
|
||||
|
||||
/obj/effect/forcefield/mime/New()
|
||||
..()
|
||||
QDEL_IN(src, timeleft)
|
||||
@@ -0,0 +1,62 @@
|
||||
/proc/gibs(atom/location, list/viruses, datum/dna/MobDNA)
|
||||
new /obj/effect/gibspawner/generic(location,viruses,MobDNA)
|
||||
|
||||
/proc/hgibs(atom/location, list/viruses, datum/dna/MobDNA)
|
||||
new /obj/effect/gibspawner/human(location,viruses,MobDNA)
|
||||
|
||||
/proc/xgibs(atom/location, list/viruses)
|
||||
new /obj/effect/gibspawner/xeno(location,viruses)
|
||||
|
||||
/proc/robogibs(atom/location, list/viruses)
|
||||
new /obj/effect/gibspawner/robot(location,viruses)
|
||||
|
||||
/obj/effect/gibspawner
|
||||
var/sparks = 0 //whether sparks spread on Gib()
|
||||
var/virusProb = 20 //the chance for viruses to spread on the gibs
|
||||
var/list/gibtypes = list()
|
||||
var/list/gibamounts = list()
|
||||
var/list/gibdirections = list() //of lists
|
||||
|
||||
/obj/effect/gibspawner/New(location, var/list/viruses, var/datum/dna/MobDNA)
|
||||
..()
|
||||
|
||||
Gib(loc,viruses,MobDNA)
|
||||
|
||||
/obj/effect/gibspawner/proc/Gib(atom/location, list/viruses = list(), datum/dna/MobDNA = null)
|
||||
if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len)
|
||||
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, location)
|
||||
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(location)
|
||||
if(istype(location,/mob/living/carbon))
|
||||
var/mob/living/carbon/digester = location
|
||||
digester.stomach_contents += gib
|
||||
|
||||
if(viruses.len > 0)
|
||||
for(var/datum/disease/D in viruses)
|
||||
if(prob(virusProb))
|
||||
var/datum/disease/viruus = D.Copy(1)
|
||||
gib.viruses += viruus
|
||||
viruus.holder = gib
|
||||
|
||||
if(MobDNA)
|
||||
gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.blood_type
|
||||
else if(istype(src, /obj/effect/gibspawner/generic)) // Probably a monkey
|
||||
gib.blood_DNA["Non-human DNA"] = "A+"
|
||||
var/list/directions = gibdirections[i]
|
||||
if(istype(loc,/turf))
|
||||
if(directions.len)
|
||||
gib.streak(directions)
|
||||
|
||||
qdel(src)
|
||||
@@ -0,0 +1,159 @@
|
||||
//separate dm since hydro is getting bloated already
|
||||
|
||||
var/list/blacklisted_glowshroom_turfs = typecacheof(list(
|
||||
/turf/open/floor/plating/lava,
|
||||
/turf/open/floor/plating/beach/water))
|
||||
|
||||
/obj/effect/glowshroom
|
||||
name = "glowshroom"
|
||||
desc = "Mycena Bregprox, a species of mushroom that glows in the dark."
|
||||
anchored = 1
|
||||
opacity = 0
|
||||
density = 0
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "glowshroom" //replaced in New
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
var/endurance = 30
|
||||
var/potency = 30
|
||||
var/delay = 1200
|
||||
var/floor = 0
|
||||
var/yield = 3
|
||||
var/generation = 1
|
||||
var/spreadIntoAdjacentChance = 60
|
||||
|
||||
obj/effect/glowshroom/glowcap
|
||||
name = "glowcap"
|
||||
icon_state = "glowcap"
|
||||
|
||||
/obj/effect/glowshroom/single
|
||||
yield = 0
|
||||
|
||||
/obj/effect/glowshroom/examine(mob/user)
|
||||
. = ..()
|
||||
user << "This is a [generation]\th generation [name]!"
|
||||
|
||||
/obj/effect/glowshroom/New()
|
||||
..()
|
||||
SetLuminosity(round(potency/10))
|
||||
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]f"
|
||||
|
||||
addtimer(src, "Spread", delay)
|
||||
|
||||
/obj/effect/glowshroom/proc/Spread()
|
||||
for(var/i = 1 to 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(spreadsIntoAdjacent || !locate(/obj/effect/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/effect/glowshroom/shroom in newLoc)
|
||||
shroomCount++
|
||||
for(var/wallDir in cardinal)
|
||||
var/turf/isWall = get_step(newLoc,wallDir)
|
||||
if(isWall.density)
|
||||
placeCount++
|
||||
if(shroomCount >= placeCount)
|
||||
continue
|
||||
|
||||
var/obj/effect/glowshroom/child = new type(newLoc)//The baby mushrooms have different stats :3
|
||||
child.potency = max(potency + rand(-3,6), 0)
|
||||
child.yield = max(yield + rand(-1,2), 0)
|
||||
child.delay = max(delay + rand(-30,60), 0)
|
||||
child.endurance = max(endurance + rand(-3,6), 1)
|
||||
child.generation = generation + 1
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
/obj/effect/glowshroom/proc/CalcDir(turf/location = loc)
|
||||
var/direction = 16
|
||||
|
||||
for(var/wallDir in cardinal)
|
||||
var/turf/newTurf = get_step(location,wallDir)
|
||||
if(newTurf.density)
|
||||
direction |= wallDir
|
||||
|
||||
for(var/obj/effect/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/effect/glowshroom/attacked_by(obj/item/I, mob/user)
|
||||
..()
|
||||
if(I.damtype != STAMINA)
|
||||
endurance -= I.force
|
||||
CheckEndurance()
|
||||
|
||||
/obj/effect/glowshroom/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
qdel(src)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
qdel(src)
|
||||
if(3)
|
||||
if(prob(5))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/glowshroom/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > 300)
|
||||
endurance -= 5
|
||||
CheckEndurance()
|
||||
|
||||
/obj/effect/glowshroom/proc/CheckEndurance()
|
||||
if(endurance <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/glowshroom/acid_act(acidpwr, toxpwr, acid_volume)
|
||||
visible_message("<span class='danger'>[src] melts away!</span>")
|
||||
var/obj/effect/decal/cleanable/molten_item/I = new (get_turf(src))
|
||||
I.desc = "Looks like this was \an [src] some time ago."
|
||||
qdel(src)
|
||||
@@ -0,0 +1,288 @@
|
||||
/obj/effect/landmark
|
||||
name = "landmark"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x2"
|
||||
anchored = 1
|
||||
unacidable = 1
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/effect/landmark/New()
|
||||
..()
|
||||
tag = text("landmark*[]", name)
|
||||
landmarks_list += src
|
||||
|
||||
switch(name) //some of these are probably obsolete
|
||||
if("monkey")
|
||||
monkeystart += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("start")
|
||||
newplayer_start += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("wizard")
|
||||
wizardstart += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("JoinLate")
|
||||
latejoin += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("prisonwarp")
|
||||
prisonwarp += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("Holding Facility")
|
||||
holdingfacility += loc
|
||||
if("tdome1")
|
||||
tdome1 += loc
|
||||
if("tdome2")
|
||||
tdome2 += loc
|
||||
if("tdomeadmin")
|
||||
tdomeadmin += loc
|
||||
if("tdomeobserve")
|
||||
tdomeobserve += loc
|
||||
if("prisonsecuritywarp")
|
||||
prisonsecuritywarp += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("blobstart")
|
||||
blobstart += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("secequipment")
|
||||
secequipment += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("Emergencyresponseteam")
|
||||
emergencyresponseteamspawn += loc
|
||||
qdel(src)
|
||||
return
|
||||
if("xeno_spawn")
|
||||
xeno_spawn += loc
|
||||
qdel(src)
|
||||
return
|
||||
return 1
|
||||
|
||||
/obj/effect/landmark/Destroy()
|
||||
landmarks_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/landmark/start
|
||||
name = "start"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x"
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/landmark/start/New()
|
||||
..()
|
||||
tag = "start*[name]"
|
||||
start_landmarks_list += src
|
||||
return 1
|
||||
|
||||
/obj/effect/landmark/start/Destroy()
|
||||
start_landmarks_list -= src
|
||||
return ..()
|
||||
|
||||
//Costume spawner landmarks
|
||||
|
||||
/obj/effect/landmark/costume/New() //costume spawner, selects a random subclass and disappears
|
||||
|
||||
var/list/options = typesof(/obj/effect/landmark/costume)
|
||||
var/PICK= options[rand(1,options.len)]
|
||||
new PICK(src.loc)
|
||||
qdel(src)
|
||||
|
||||
//SUBCLASSES. Spawn a bunch of items and disappear likewise
|
||||
/obj/effect/landmark/costume/chicken/New()
|
||||
new /obj/item/clothing/suit/chickensuit(src.loc)
|
||||
new /obj/item/clothing/head/chicken(src.loc)
|
||||
new /obj/item/weapon/reagent_containers/food/snacks/egg(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/gladiator/New()
|
||||
new /obj/item/clothing/under/gladiator(src.loc)
|
||||
new /obj/item/clothing/head/helmet/gladiator(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/madscientist/New()
|
||||
new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc)
|
||||
new /obj/item/clothing/head/flatcap(src.loc)
|
||||
new /obj/item/clothing/suit/toggle/labcoat/mad(src.loc)
|
||||
new /obj/item/clothing/glasses/gglasses(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/elpresidente/New()
|
||||
new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc)
|
||||
new /obj/item/clothing/head/flatcap(src.loc)
|
||||
new /obj/item/clothing/mask/cigarette/cigar/havana(src.loc)
|
||||
new /obj/item/clothing/shoes/jackboots(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/nyangirl/New()
|
||||
new /obj/item/clothing/under/schoolgirl(src.loc)
|
||||
new /obj/item/clothing/head/kitty(src.loc)
|
||||
new /obj/item/clothing/glasses/sunglasses/blindfold(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/maid/New()
|
||||
new /obj/item/clothing/under/blackskirt(src.loc)
|
||||
var/CHOICE = pick( /obj/item/clothing/head/beret , /obj/item/clothing/head/rabbitears )
|
||||
new CHOICE(src.loc)
|
||||
new /obj/item/clothing/glasses/sunglasses/blindfold(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/butler/New()
|
||||
new /obj/item/clothing/tie/waistcoat(src.loc)
|
||||
new /obj/item/clothing/under/suit_jacket(src.loc)
|
||||
new /obj/item/clothing/head/that(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/highlander/New()
|
||||
new /obj/item/clothing/under/kilt(src.loc)
|
||||
new /obj/item/clothing/head/beret(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/prig/New()
|
||||
new /obj/item/clothing/tie/waistcoat(src.loc)
|
||||
new /obj/item/clothing/glasses/monocle(src.loc)
|
||||
var/CHOICE= pick( /obj/item/clothing/head/bowler, /obj/item/clothing/head/that)
|
||||
new CHOICE(src.loc)
|
||||
new /obj/item/clothing/shoes/sneakers/black(src.loc)
|
||||
new /obj/item/weapon/cane(src.loc)
|
||||
new /obj/item/clothing/under/sl_suit(src.loc)
|
||||
new /obj/item/clothing/mask/fakemoustache(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/plaguedoctor/New()
|
||||
new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(src.loc)
|
||||
new /obj/item/clothing/head/plaguedoctorhat(src.loc)
|
||||
new /obj/item/clothing/mask/gas/plaguedoctor(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/nightowl/New()
|
||||
new /obj/item/clothing/suit/toggle/owlwings(src.loc)
|
||||
new /obj/item/clothing/under/owl(src.loc)
|
||||
new /obj/item/clothing/mask/gas/owl_mask(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/thegriffin/New()
|
||||
new /obj/item/clothing/suit/toggle/owlwings/griffinwings(src.loc)
|
||||
new /obj/item/clothing/shoes/griffin(src.loc)
|
||||
new /obj/item/clothing/under/griffin(src.loc)
|
||||
new /obj/item/clothing/head/griffin(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/waiter/New()
|
||||
new /obj/item/clothing/under/waiter(src.loc)
|
||||
var/CHOICE= pick( /obj/item/clothing/head/kitty, /obj/item/clothing/head/rabbitears)
|
||||
new CHOICE(src.loc)
|
||||
new /obj/item/clothing/suit/apron(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/pirate/New()
|
||||
new /obj/item/clothing/under/pirate(src.loc)
|
||||
new /obj/item/clothing/suit/pirate(src.loc)
|
||||
var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/head/bandana )
|
||||
new CHOICE(src.loc)
|
||||
new /obj/item/clothing/glasses/eyepatch(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/commie/New()
|
||||
new /obj/item/clothing/under/soviet(src.loc)
|
||||
new /obj/item/clothing/head/ushanka(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/imperium_monk/New()
|
||||
new /obj/item/clothing/suit/imperium_monk(src.loc)
|
||||
if (prob(25))
|
||||
new /obj/item/clothing/mask/gas/cyborg(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/holiday_priest/New()
|
||||
new /obj/item/clothing/suit/holidaypriest(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/marisawizard/fake/New()
|
||||
new /obj/item/clothing/shoes/sandal/marisa(src.loc)
|
||||
new /obj/item/clothing/head/wizard/marisa/fake(src.loc)
|
||||
new/obj/item/clothing/suit/wizrobe/marisa/fake(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/cutewitch/New()
|
||||
new /obj/item/clothing/under/sundress(src.loc)
|
||||
new /obj/item/clothing/head/witchwig(src.loc)
|
||||
new /obj/item/weapon/staff/broom(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/fakewizard/New()
|
||||
new /obj/item/clothing/shoes/sandal(src.loc)
|
||||
new /obj/item/clothing/suit/wizrobe/fake(src.loc)
|
||||
new /obj/item/clothing/head/wizard/fake(src.loc)
|
||||
new /obj/item/weapon/staff/(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/sexyclown/New()
|
||||
new /obj/item/clothing/mask/gas/sexyclown(src.loc)
|
||||
new /obj/item/clothing/under/rank/clown/sexy(src.loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/costume/sexymime/New()
|
||||
new /obj/item/clothing/mask/gas/sexymime(src.loc)
|
||||
new /obj/item/clothing/under/sexymime(src.loc)
|
||||
qdel(src)
|
||||
|
||||
//Department Security spawns
|
||||
|
||||
/obj/effect/landmark/start/depsec
|
||||
name = "department_sec"
|
||||
|
||||
/obj/effect/landmark/start/depsec/New()
|
||||
..()
|
||||
department_security_spawns += src
|
||||
|
||||
/obj/effect/landmark/start/depsec/Destroy()
|
||||
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/latejoin
|
||||
name = "JoinLate"
|
||||
|
||||
//generic event spawns
|
||||
/obj/effect/landmark/event_spawn
|
||||
name = "generic event spawn"
|
||||
icon_state = "x4"
|
||||
|
||||
/obj/effect/landmark/event_spawn/New()
|
||||
..()
|
||||
generic_event_spawns += src
|
||||
|
||||
/obj/effect/landmark/event_spawn/Destroy()
|
||||
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_[ruin_landmarks.len + 1]"
|
||||
..(loc)
|
||||
ruin_template = my_ruin_template
|
||||
ruin_landmarks |= src
|
||||
|
||||
/obj/effect/landmark/ruin/Destroy()
|
||||
ruin_landmarks -= src
|
||||
ruin_template = null
|
||||
. = ..()
|
||||
@@ -0,0 +1,18 @@
|
||||
/obj/effect/manifest
|
||||
name = "manifest"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x"
|
||||
unacidable = 1//Just to be sure.
|
||||
|
||||
/obj/effect/manifest/New()
|
||||
src.invisibility = INVISIBILITY_ABSTRACT
|
||||
|
||||
/obj/effect/manifest/proc/manifest()
|
||||
var/dat = "<B>Crew Manifest</B>:<BR>"
|
||||
for(var/mob/living/carbon/human/M in mob_list)
|
||||
dat += text(" <B>[]</B> - []<BR>", M.name, M.get_assignment())
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.loc )
|
||||
P.info = dat
|
||||
P.name = "paper- 'Crew Manifest'"
|
||||
//SN src = null
|
||||
qdel(src)
|
||||
@@ -0,0 +1,172 @@
|
||||
/obj/effect/mine
|
||||
name = "dummy mine"
|
||||
desc = "Better stay away from that thing."
|
||||
density = 0
|
||||
anchored = 1
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "uglymine"
|
||||
var/triggered = 0
|
||||
|
||||
/obj/effect/mine/proc/mineEffect(mob/victim)
|
||||
victim << "<span class='danger'>*click*</span>"
|
||||
|
||||
/obj/effect/mine/Crossed(AM as mob|obj)
|
||||
if(isanimal(AM))
|
||||
var/mob/living/simple_animal/SA = AM
|
||||
if(!SA.flying)
|
||||
triggermine(SA)
|
||||
else
|
||||
triggermine(AM)
|
||||
|
||||
/obj/effect/mine/proc/triggermine(mob/victim)
|
||||
if(triggered)
|
||||
return
|
||||
visible_message("<span class='danger'>[victim] sets off \icon[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 = 8
|
||||
|
||||
/obj/effect/mine/stun/mineEffect(mob/victim)
|
||||
if(isliving(victim))
|
||||
victim.Weaken(stun_time)
|
||||
|
||||
/obj/effect/mine/kickmine
|
||||
name = "kick mine"
|
||||
|
||||
/obj/effect/mine/kickmine/mineEffect(mob/victim)
|
||||
if(isliving(victim) && victim.client)
|
||||
victim << "<span class='userdanger'>You have been kicked FOR NO REISIN!</span>"
|
||||
del(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 = 0
|
||||
var/duration = 0
|
||||
|
||||
/obj/effect/mine/pickup/New()
|
||||
..()
|
||||
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 = "red"
|
||||
|
||||
/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim)
|
||||
if(!victim.client || !istype(victim))
|
||||
return
|
||||
victim << "<span class='reallybig redtext'>RIP AND TEAR</span>"
|
||||
victim << 'sound/misc/e1m1.ogg'
|
||||
var/old_color = victim.client.color
|
||||
var/red_splash = list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0)
|
||||
var/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0)
|
||||
|
||||
spawn(0)
|
||||
new /obj/effect/hallucination/delusion(victim.loc,victim,force_kind="demon",duration=duration,skip_nearby=0)
|
||||
|
||||
var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc)
|
||||
chainsaw.flags |= NODROP
|
||||
victim.drop_r_hand()
|
||||
victim.drop_l_hand()
|
||||
victim.put_in_hands(chainsaw)
|
||||
|
||||
victim.reagents.add_reagent("adminordrazine",25)
|
||||
|
||||
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)
|
||||
victim << "<span class='notice'>Your bloodlust seeps back into the bog of your subconscious and you regain self control.<span>"
|
||||
qdel(chainsaw)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mine/pickup/healing
|
||||
name = "Blue Orb"
|
||||
desc = "You feel better just looking at it."
|
||||
color = "blue"
|
||||
|
||||
/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim)
|
||||
if(!victim.client || !istype(victim))
|
||||
return
|
||||
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 = "yellow"
|
||||
duration = 300
|
||||
|
||||
/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim)
|
||||
if(!victim.client || !istype(victim))
|
||||
return
|
||||
victim << "<span class='notice'>You feel fast!</span>"
|
||||
victim.status_flags |= GOTTAGOREALLYFAST
|
||||
sleep(duration)
|
||||
victim.status_flags &= ~GOTTAGOREALLYFAST
|
||||
victim << "<span class='notice'>You slow down.</span>"
|
||||
@@ -0,0 +1,26 @@
|
||||
//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.dmi'
|
||||
icon_state = "strangepresent"
|
||||
density = 1
|
||||
anchored = 0
|
||||
|
||||
/obj/effect/beam
|
||||
name = "beam"
|
||||
unacidable = 1//Just to be sure.
|
||||
var/def_zone
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
/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( )
|
||||
@@ -0,0 +1,345 @@
|
||||
/obj/effect/overlay
|
||||
name = "overlay"
|
||||
unacidable = 1
|
||||
var/i_attached//Added for possible image attachments to objects. For hallucinations and the like.
|
||||
|
||||
/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/New()
|
||||
..()
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/obj/effect/overlay/temp
|
||||
icon_state = "nothing"
|
||||
anchored = 1
|
||||
layer = ABOVE_MOB_LAYER
|
||||
mouse_opacity = 0
|
||||
var/duration = 10 //in deciseconds
|
||||
var/randomdir = TRUE
|
||||
var/timerid
|
||||
|
||||
/obj/effect/overlay/temp/Destroy()
|
||||
..()
|
||||
deltimer(timerid)
|
||||
return QDEL_HINT_PUTINPOOL
|
||||
|
||||
/obj/effect/overlay/temp/New()
|
||||
..()
|
||||
if(randomdir)
|
||||
setDir(pick(cardinal))
|
||||
flick("[icon_state]", src) //Because we might be pulling it from a pool, flick whatever icon it uses so it starts at the start of the icon's animation.
|
||||
|
||||
timerid = QDEL_IN(src, duration)
|
||||
|
||||
/obj/effect/overlay/temp/bloodsplatter
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
duration = 5
|
||||
randomdir = FALSE
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/overlay/temp/bloodsplatter/New(loc, set_dir)
|
||||
if(set_dir in diagonals)
|
||||
icon_state = "splatter[pick(1, 2, 6)]"
|
||||
else
|
||||
icon_state = "splatter[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
|
||||
setDir(set_dir)
|
||||
animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration)
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/heal //color is white by default, set to whatever is needed
|
||||
name = "healing glow"
|
||||
icon_state = "heal"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/overlay/temp/heal/New(loc, colour)
|
||||
..()
|
||||
pixel_x = rand(-12, 12)
|
||||
pixel_y = rand(-9, 0)
|
||||
if(colour)
|
||||
color = colour
|
||||
|
||||
/obj/effect/overlay/temp/explosion
|
||||
name = "explosion"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "explosion"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
duration = 8
|
||||
|
||||
/obj/effect/overlay/temp/blob
|
||||
name = "blob"
|
||||
icon_state = "blob_attack"
|
||||
alpha = 140
|
||||
randomdir = 0
|
||||
duration = 6
|
||||
|
||||
/obj/effect/overlay/temp/guardian
|
||||
randomdir = 0
|
||||
|
||||
/obj/effect/overlay/temp/guardian/phase
|
||||
duration = 5
|
||||
icon_state = "phasein"
|
||||
|
||||
/obj/effect/overlay/temp/guardian/phase/out
|
||||
icon_state = "phaseout"
|
||||
|
||||
/obj/effect/overlay/temp/decoy
|
||||
desc = "It's a decoy!"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/overlay/temp/decoy/New(loc, atom/mimiced_atom)
|
||||
..()
|
||||
alpha = initial(alpha)
|
||||
if(mimiced_atom)
|
||||
name = mimiced_atom.name
|
||||
appearance = mimiced_atom.appearance
|
||||
setDir(mimiced_atom.dir)
|
||||
animate(src, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/overlay/temp/cult
|
||||
randomdir = 0
|
||||
duration = 10
|
||||
|
||||
/obj/effect/overlay/temp/cult/sparks
|
||||
randomdir = 1
|
||||
name = "blood sparks"
|
||||
icon_state = "bloodsparkles"
|
||||
|
||||
/obj/effect/overlay/temp/cult/phase
|
||||
name = "phase glow"
|
||||
duration = 7
|
||||
icon_state = "cultin"
|
||||
|
||||
/obj/effect/overlay/temp/cult/phase/New(loc, set_dir)
|
||||
..()
|
||||
if(set_dir)
|
||||
setDir(set_dir)
|
||||
|
||||
/obj/effect/overlay/temp/cult/phase/out
|
||||
icon_state = "cultout"
|
||||
|
||||
/obj/effect/overlay/temp/cult/sac
|
||||
name = "maw of Nar-Sie"
|
||||
icon_state = "sacconsume"
|
||||
|
||||
/obj/effect/overlay/temp/cult/door
|
||||
name = "unholy glow"
|
||||
icon_state = "doorglow"
|
||||
layer = CLOSED_FIREDOOR_LAYER //above closed doors
|
||||
|
||||
/obj/effect/overlay/temp/cult/door/unruned
|
||||
icon_state = "unruneddoorglow"
|
||||
|
||||
/obj/effect/overlay/temp/cult/turf
|
||||
name = "unholy glow"
|
||||
icon_state = "wallglow"
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
|
||||
/obj/effect/overlay/temp/cult/turf/open/floor
|
||||
icon_state = "floorglow"
|
||||
duration = 5
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/ratvar
|
||||
name = "ratvar's light"
|
||||
duration = 8
|
||||
randomdir = 0
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/door
|
||||
icon_state = "ratvardoorglow"
|
||||
layer = CLOSED_FIREDOOR_LAYER //above closed doors
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/door/window
|
||||
icon_state = "ratvarwindoorglow"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/beam
|
||||
icon_state = "ratvarbeamglow"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/beam/door
|
||||
layer = CLOSED_FIREDOOR_LAYER //above closed doors
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/beam/grille
|
||||
layer = LOW_ITEM_LAYER //above grilles
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/beam/itemconsume
|
||||
layer = HIGH_OBJ_LAYER
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/wall
|
||||
icon_state = "ratvarwallglow"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/floor
|
||||
icon_state = "ratvarfloorglow"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/window
|
||||
icon_state = "ratvarwindowglow"
|
||||
layer = ABOVE_WINDOW_LAYER //above windows
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/grille
|
||||
icon_state = "ratvargrilleglow"
|
||||
layer = LOW_ITEM_LAYER //above grilles
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/grille/broken
|
||||
icon_state = "ratvarbrokengrilleglow"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/window/single
|
||||
icon_state = "ratvarwindowglow_s"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/spearbreak
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "ratvarspearbreak"
|
||||
layer = BELOW_MOB_LAYER
|
||||
pixel_y = -16
|
||||
pixel_x = -16
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/sigil
|
||||
name = "glowing circle"
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
icon_state = "sigildull"
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/sigil/transgression
|
||||
color = "#FAE48C"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 50
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/sigil/transgression/New()
|
||||
..()
|
||||
var/oldtransform = transform
|
||||
animate(src, transform = matrix()*2, time = 5)
|
||||
animate(transform = oldtransform, alpha = 0, time = 45)
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/sigil/vitality
|
||||
color = "#1E8CE1"
|
||||
icon_state = "sigilactivepulse"
|
||||
layer = BELOW_MOB_LAYER
|
||||
|
||||
/obj/effect/overlay/temp/ratvar/sigil/accession
|
||||
color = "#AF0AAF"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 50
|
||||
icon_state = "sigilactiveoverlay"
|
||||
alpha = 0
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/revenant
|
||||
name = "spooky lights"
|
||||
icon_state = "purplesparkles"
|
||||
|
||||
/obj/effect/overlay/temp/revenant/cracks
|
||||
name = "glowing cracks"
|
||||
icon_state = "purplecrack"
|
||||
duration = 6
|
||||
|
||||
|
||||
/obj/effect/overlay/temp/emp
|
||||
name = "emp sparks"
|
||||
icon_state = "empdisable"
|
||||
|
||||
/obj/effect/overlay/temp/emp/pulse
|
||||
name = "emp pulse"
|
||||
icon_state = "emp pulse"
|
||||
duration = 8
|
||||
randomdir = 0
|
||||
|
||||
/obj/effect/overlay/temp/gib_animation
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
duration = 15
|
||||
|
||||
/obj/effect/overlay/temp/gib_animation/New(loc, gib_icon)
|
||||
icon_state = gib_icon // Needs to be before ..() so icon is correct
|
||||
..()
|
||||
|
||||
/obj/effect/overlay/temp/gib_animation/ex_act(severity)
|
||||
return //so the overlay isn't deleted by the explosion that gibbed the mob.
|
||||
|
||||
/obj/effect/overlay/temp/gib_animation/animal
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
|
||||
/obj/effect/overlay/temp/dust_animation
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
duration = 15
|
||||
|
||||
/obj/effect/overlay/temp/dust_animation/New(loc, dust_icon)
|
||||
icon_state = dust_icon // Before ..() so the correct icon is flick()'d
|
||||
..()
|
||||
|
||||
/obj/effect/overlay/temp/sparkle
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shieldsparkles"
|
||||
mouse_opacity = 0
|
||||
density = 0
|
||||
duration = 10
|
||||
var/atom/movable/attached_to
|
||||
|
||||
/obj/effect/overlay/temp/sparkle/New(atom/movable/AM)
|
||||
..()
|
||||
if(istype(AM))
|
||||
attached_to = AM
|
||||
attached_to.overlays += src
|
||||
|
||||
/obj/effect/overlay/temp/sparkle/Destroy()
|
||||
if(attached_to)
|
||||
attached_to.overlays -= src
|
||||
attached_to = null
|
||||
. = ..()
|
||||
|
||||
/obj/effect/overlay/temp/sparkle/tailsweep
|
||||
icon_state = "tailsweep"
|
||||
|
||||
/obj/effect/overlay/palmtree_r
|
||||
name = "Palm tree"
|
||||
icon = 'icons/misc/beach2.dmi'
|
||||
icon_state = "palm1"
|
||||
density = 1
|
||||
layer = WALL_OBJ_LAYER
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/overlay/palmtree_l
|
||||
name = "Palm tree"
|
||||
icon = 'icons/misc/beach2.dmi'
|
||||
icon_state = "palm2"
|
||||
density = 1
|
||||
layer = WALL_OBJ_LAYER
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/overlay/coconut
|
||||
name = "Coconuts"
|
||||
icon = 'icons/misc/beach.dmi'
|
||||
icon_state = "coconuts"
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
/obj/effect
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
|
||||
/obj/effect/portal
|
||||
name = "portal"
|
||||
desc = "Looks unstable. Best to test it with the clown."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "portal"
|
||||
density = 1
|
||||
unacidable = 1//Can't destroy energy portals.
|
||||
var/obj/item/target = null
|
||||
var/creator = null
|
||||
anchored = 1
|
||||
var/precision = 1 // how close to the portal you will teleport. 0 = on the portal, 1 = adjacent
|
||||
|
||||
/obj/effect/portal/Bumped(mob/M as mob|obj)
|
||||
teleport(M)
|
||||
|
||||
/obj/effect/portal/attack_hand(mob/user)
|
||||
if(Adjacent(user))
|
||||
teleport(user)
|
||||
|
||||
/obj/effect/portal/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(user && Adjacent(user))
|
||||
teleport(user)
|
||||
|
||||
|
||||
|
||||
/obj/effect/portal/New(loc, turf/target, creator=null, lifespan=300)
|
||||
..()
|
||||
portals += src
|
||||
src.target = target
|
||||
src.creator = creator
|
||||
|
||||
var/area/A = get_area(target)
|
||||
if(A && A.noteleport) // No point in persisting if the target is unreachable.
|
||||
qdel(src)
|
||||
return
|
||||
if(lifespan > 0)
|
||||
spawn(lifespan)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/portal/Destroy()
|
||||
portals -= src
|
||||
if(istype(creator, /obj/item/weapon/hand_tele))
|
||||
var/obj/item/weapon/hand_tele/O = creator
|
||||
O.active_portals--
|
||||
else if(istype(creator, /obj/item/weapon/gun/energy/wormhole_projector))
|
||||
var/obj/item/weapon/gun/energy/wormhole_projector/P = creator
|
||||
P.portal_destroyed(src)
|
||||
creator = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/proc/teleport(atom/movable/M as mob|obj)
|
||||
if(istype(M, /obj/effect)) //sparks don't teleport
|
||||
return
|
||||
if(M.anchored&&istype(M, /obj/mecha))
|
||||
return
|
||||
if (!( target ))
|
||||
qdel(src)
|
||||
return
|
||||
if (istype(M, /atom/movable))
|
||||
if(istype(M, /mob/living/simple_animal/hostile/megafauna))
|
||||
message_admins("[M] (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[M]'>FLW</A>) has teleported through [src].")
|
||||
do_teleport(M, target, precision) ///You will appear adjacent to the beacon
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/obj/effect/spawner/newbomb
|
||||
name = "bomb"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x"
|
||||
var/btype = 0 // 0=radio, 1=prox, 2=time
|
||||
var/btemp1 = 1500
|
||||
var/btemp2 = 1000 // tank temperatures
|
||||
|
||||
/obj/effect/spawner/newbomb/timer
|
||||
btype = 2
|
||||
|
||||
syndicate
|
||||
btemp1 = 150
|
||||
btemp2 = 20
|
||||
|
||||
/obj/effect/spawner/newbomb/proximity
|
||||
btype = 1
|
||||
|
||||
/obj/effect/spawner/newbomb/radio
|
||||
btype = 0
|
||||
|
||||
|
||||
/obj/effect/spawner/newbomb/New()
|
||||
..()
|
||||
|
||||
switch (src.btype)
|
||||
// radio
|
||||
if (0)
|
||||
|
||||
var/obj/item/device/transfer_valve/V = new(src.loc)
|
||||
var/obj/item/weapon/tank/internals/plasma/PT = new(V)
|
||||
var/obj/item/weapon/tank/internals/oxygen/OT = new(V)
|
||||
|
||||
var/obj/item/device/assembly/signaler/S = new(V)
|
||||
|
||||
V.tank_one = PT
|
||||
V.tank_two = OT
|
||||
V.attached_device = S
|
||||
|
||||
S.holder = V
|
||||
S.toggle_secure()
|
||||
PT.master = V
|
||||
OT.master = V
|
||||
|
||||
PT.air_contents.temperature = btemp1 + T0C
|
||||
OT.air_contents.temperature = btemp2 + T0C
|
||||
|
||||
V.update_icon()
|
||||
|
||||
// proximity
|
||||
if (1)
|
||||
|
||||
var/obj/item/device/transfer_valve/V = new(src.loc)
|
||||
var/obj/item/weapon/tank/internals/plasma/PT = new(V)
|
||||
var/obj/item/weapon/tank/internals/oxygen/OT = new(V)
|
||||
|
||||
var/obj/item/device/assembly/prox_sensor/P = new(V)
|
||||
|
||||
V.tank_one = PT
|
||||
V.tank_two = OT
|
||||
V.attached_device = P
|
||||
|
||||
P.holder = V
|
||||
P.toggle_secure()
|
||||
PT.master = V
|
||||
OT.master = V
|
||||
|
||||
|
||||
PT.air_contents.temperature = btemp1 + T0C
|
||||
OT.air_contents.temperature = btemp2 + T0C
|
||||
|
||||
V.update_icon()
|
||||
|
||||
|
||||
// timer
|
||||
if (2)
|
||||
var/obj/item/device/transfer_valve/V = new(src.loc)
|
||||
var/obj/item/weapon/tank/internals/plasma/PT = new(V)
|
||||
var/obj/item/weapon/tank/internals/oxygen/OT = new(V)
|
||||
|
||||
var/obj/item/device/assembly/timer/T = new(V)
|
||||
|
||||
V.tank_one = PT
|
||||
V.tank_two = OT
|
||||
V.attached_device = T
|
||||
|
||||
T.holder = V
|
||||
T.toggle_secure()
|
||||
PT.master = V
|
||||
OT.master = V
|
||||
T.time = 30
|
||||
|
||||
PT.air_contents.temperature = btemp1 + T0C
|
||||
OT.air_contents.temperature = btemp2 + T0C
|
||||
|
||||
V.update_icon()
|
||||
qdel(src)
|
||||
@@ -0,0 +1,40 @@
|
||||
/obj/effect/gibspawner
|
||||
|
||||
/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/New()
|
||||
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/New()
|
||||
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), alldirs, alldirs, list())
|
||||
gibamounts[6] = pick(0,1,2)
|
||||
..()
|
||||
|
||||
/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/New()
|
||||
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), alldirs, alldirs, list())
|
||||
gibamounts[6] = pick(0,1,2)
|
||||
..()
|
||||
|
||||
/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/New()
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs)
|
||||
gibamounts[6] = pick(0,1,2)
|
||||
..()
|
||||
@@ -0,0 +1,170 @@
|
||||
/obj/effect/spawner/lootdrop
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x2"
|
||||
color = "#00FF00"
|
||||
var/lootcount = 1 //how many items will be spawned
|
||||
var/lootdoubles = 1 //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)
|
||||
|
||||
/obj/effect/spawner/lootdrop/New()
|
||||
if(loot && loot.len)
|
||||
for(var/i = lootcount, i > 0, i--)
|
||||
if(!loot.len) break
|
||||
var/lootspawn = pickweight(loot)
|
||||
if(!lootdoubles)
|
||||
loot.Remove(lootspawn)
|
||||
|
||||
if(lootspawn)
|
||||
new lootspawn(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spawner/lootdrop/armory_contraband
|
||||
name = "armory contraband gun spawner"
|
||||
lootdoubles = 0
|
||||
|
||||
loot = list(
|
||||
/obj/item/weapon/gun/projectile/automatic/pistol = 8,
|
||||
/obj/item/weapon/gun/projectile/shotgun/automatic/combat = 5,
|
||||
/obj/item/weapon/gun/projectile/revolver/mateba,
|
||||
/obj/item/weapon/gun/projectile/automatic/pistol/deagle
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/gambling
|
||||
name = "gambling valuables spawner"
|
||||
loot = list(
|
||||
/obj/item/weapon/gun/projectile/revolver/russian = 5,
|
||||
/obj/item/weapon/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/weapon/cigbutt = 1,
|
||||
/obj/item/trash/cheesie = 1,
|
||||
/obj/item/trash/candy = 1,
|
||||
/obj/item/trash/chips = 1,
|
||||
/obj/item/trash/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/maintenance
|
||||
name = "maintenance loot spawner"
|
||||
|
||||
//How to balance this table
|
||||
//-------------------------
|
||||
//The total added weight of all the entries should be (roughly) equal to the total number of lootdrops
|
||||
//(take in account those that spawn more than one object!)
|
||||
//
|
||||
//While this is random, probabilities tells us that item distribution will have a tendency to look like
|
||||
//the content of the weighted table that created them.
|
||||
//The less lootdrops, the less even the distribution.
|
||||
//
|
||||
//If you want to give items a weight <1 you can multiply all the weights by 10
|
||||
//
|
||||
//the "" entry will spawn nothing, if you increase this value,
|
||||
//ensure that you balance it with more spawn points
|
||||
|
||||
//table data:
|
||||
//-----------
|
||||
//aft maintenance: 24 items, 18 spots 2 extra (28/08/2014)
|
||||
//asmaint: 16 items, 11 spots 0 extra (08/08/2014)
|
||||
//asmaint2: 36 items, 26 spots 2 extra (28/08/2014)
|
||||
//fpmaint: 5 items, 4 spots 0 extra (08/08/2014)
|
||||
//fpmaint2: 12 items, 11 spots 2 extra (28/08/2014)
|
||||
//fsmaint: 0 items, 0 spots 0 extra (08/08/2014)
|
||||
//fsmaint2: 40 items, 27 spots 5 extra (28/08/2014)
|
||||
//maintcentral: 2 items, 2 spots 0 extra (08/08/2014)
|
||||
//port: 5 items, 5 spots 0 extra (08/08/2014)
|
||||
loot = list(
|
||||
/obj/item/bodybag = 1,
|
||||
/obj/item/clothing/glasses/meson = 2,
|
||||
/obj/item/clothing/glasses/sunglasses = 1,
|
||||
/obj/item/clothing/gloves/color/fyellow = 1,
|
||||
/obj/item/clothing/head/hardhat = 1,
|
||||
/obj/item/clothing/head/hardhat/red = 1,
|
||||
/obj/item/clothing/head/that{throwforce = 1; throwing = 1} = 1,
|
||||
/obj/item/clothing/head/ushanka = 1,
|
||||
/obj/item/clothing/head/welding = 1,
|
||||
/obj/item/clothing/mask/gas = 15,
|
||||
/obj/item/clothing/suit/hazardvest = 1,
|
||||
/obj/item/clothing/under/rank/vice = 1,
|
||||
/obj/item/device/assembly/prox_sensor = 4,
|
||||
/obj/item/device/assembly/timer = 3,
|
||||
/obj/item/device/flashlight = 4,
|
||||
/obj/item/device/flashlight/pen = 1,
|
||||
/obj/item/device/multitool = 2,
|
||||
/obj/item/device/radio/off = 2,
|
||||
/obj/item/device/t_scanner = 5,
|
||||
/obj/item/weapon/airlock_painter = 1,
|
||||
/obj/item/stack/cable_coil = 4,
|
||||
/obj/item/stack/cable_coil{amount = 5} = 6,
|
||||
/obj/item/stack/medical/bruise_pack = 1,
|
||||
/obj/item/stack/rods{amount = 10} = 9,
|
||||
/obj/item/stack/rods{amount = 23} = 1,
|
||||
/obj/item/stack/rods{amount = 50} = 1,
|
||||
/obj/item/stack/sheet/cardboard = 2,
|
||||
/obj/item/stack/sheet/metal{amount = 20} = 1,
|
||||
/obj/item/stack/sheet/mineral/plasma = 1,
|
||||
/obj/item/stack/sheet/rglass = 1,
|
||||
/obj/item/weapon/book/manual/wiki/engineering_construction = 1,
|
||||
/obj/item/weapon/book/manual/wiki/engineering_hacking = 1,
|
||||
/obj/item/clothing/head/cone = 1,
|
||||
/obj/item/weapon/coin/silver = 1,
|
||||
/obj/item/weapon/coin/twoheaded = 1,
|
||||
/obj/item/weapon/poster/contraband = 1,
|
||||
/obj/item/weapon/poster/legit = 1,
|
||||
/obj/item/weapon/crowbar = 1,
|
||||
/obj/item/weapon/crowbar/red = 1,
|
||||
/obj/item/weapon/extinguisher = 11,
|
||||
//obj/item/weapon/gun/projectile/revolver/russian = 1, //disabled until lootdrop is a proper world proc.
|
||||
/obj/item/weapon/hand_labeler = 1,
|
||||
/obj/item/weapon/paper/crumpled = 1,
|
||||
/obj/item/weapon/pen = 1,
|
||||
/obj/item/weapon/reagent_containers/spray/pestspray = 1,
|
||||
/obj/item/weapon/reagent_containers/glass/rag = 3,
|
||||
/obj/item/weapon/stock_parts/cell = 3,
|
||||
/obj/item/weapon/storage/belt/utility = 2,
|
||||
/obj/item/weapon/storage/box = 2,
|
||||
/obj/item/weapon/storage/box/cups = 1,
|
||||
/obj/item/weapon/storage/box/donkpockets = 1,
|
||||
/obj/item/weapon/storage/box/lights/mixed = 3,
|
||||
/obj/item/weapon/storage/box/hug/medical = 1,
|
||||
/obj/item/weapon/storage/fancy/cigarettes/dromedaryco = 1,
|
||||
/obj/item/weapon/storage/toolbox/mechanical = 1,
|
||||
/obj/item/weapon/screwdriver = 3,
|
||||
/obj/item/weapon/tank/internals/emergency_oxygen = 2,
|
||||
/obj/item/weapon/vending_refill/cola = 1,
|
||||
/obj/item/weapon/weldingtool = 3,
|
||||
/obj/item/weapon/wirecutters = 1,
|
||||
/obj/item/weapon/wrench = 4,
|
||||
/obj/item/weapon/relic = 3,
|
||||
/obj/item/weaponcrafting/reciever = 1,
|
||||
/obj/item/clothing/head/cone = 2,
|
||||
/obj/item/weapon/grenade/smokebomb = 2,
|
||||
/obj/item/device/geiger_counter = 3,
|
||||
/obj/item/weapon/reagent_containers/food/snacks/grown/citrus/orange = 1,
|
||||
/obj/item/device/radio/headset = 1,
|
||||
/obj/item/device/assembly/infra = 1,
|
||||
/obj/item/device/assembly/igniter = 2,
|
||||
/obj/item/device/assembly/signaler = 2,
|
||||
/obj/item/device/assembly/mousetrap = 2,
|
||||
/obj/item/weapon/reagent_containers/syringe = 2,
|
||||
/obj/item/clothing/gloves/color/random = 8,
|
||||
/obj/item/clothing/shoes/laceup = 1,
|
||||
/obj/item/weapon/storage/secure/briefcase = 3,
|
||||
"" = 4
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/crate_spawner
|
||||
name = "lootcrate spawner"
|
||||
lootdoubles = 0
|
||||
|
||||
loot = list(
|
||||
/obj/structure/closet/crate/secure/loot = 20,
|
||||
"" = 80
|
||||
)
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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/New()
|
||||
if(spawn_list && spawn_list.len)
|
||||
for(var/i = 1, i <= spawn_list.len, i++)
|
||||
var/to_spawn = spawn_list[i]
|
||||
new to_spawn(get_turf(src))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spawner/structure/window
|
||||
icon = 'icons/obj/structures.dmi'
|
||||
icon_state = "window_spawner"
|
||||
name = "window spawner"
|
||||
spawn_list = list(
|
||||
/obj/structure/grille,
|
||||
/obj/structure/window/fulltile
|
||||
)
|
||||
|
||||
/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
|
||||
)
|
||||
@@ -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.ChangeTurf(/turf/closed/wall/vault)
|
||||
else
|
||||
T.ChangeTurf(/turf/open/floor/vault)
|
||||
T.icon_state = "[type]vault"
|
||||
|
||||
qdel(src)
|
||||
@@ -0,0 +1,223 @@
|
||||
//generic procs copied from obj/effect/alien
|
||||
/obj/effect/spider
|
||||
name = "web"
|
||||
desc = "it's stringy and sticky"
|
||||
anchored = 1
|
||||
density = 0
|
||||
var/health = 15
|
||||
|
||||
//similar to weeds, but only barfed out by nurses manually
|
||||
/obj/effect/spider/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
qdel(src)
|
||||
if(2)
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
if(3)
|
||||
if (prob(5))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spider/attacked_by(obj/item/I, mob/user)
|
||||
..()
|
||||
var/damage = I.force
|
||||
take_damage(damage, I.damtype, 1)
|
||||
|
||||
/obj/effect/spider/bullet_act(obj/item/projectile/P)
|
||||
. = ..()
|
||||
take_damage(P.damage, P.damage_type, 0)
|
||||
|
||||
/obj/effect/spider/proc/take_damage(damage, damage_type = BRUTE, sound_effect = 1)
|
||||
switch(damage_type)
|
||||
if(BURN)
|
||||
damage *= 2
|
||||
if(sound_effect)
|
||||
playsound(loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
if(BRUTE)//the stickiness of the web mutes all attack sounds except fire damage type
|
||||
damage *= 0.25
|
||||
else
|
||||
return
|
||||
health -= damage
|
||||
if(health <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spider/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > 300)
|
||||
take_damage(5, BURN, 0)
|
||||
|
||||
/obj/effect/spider/stickyweb
|
||||
icon_state = "stickyweb1"
|
||||
|
||||
/obj/effect/spider/stickyweb/New()
|
||||
if(prob(50))
|
||||
icon_state = "stickyweb2"
|
||||
|
||||
/obj/effect/spider/stickyweb/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
if(height==0) return 1
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
return 1
|
||||
else if(istype(mover, /mob/living))
|
||||
if(prob(50))
|
||||
mover << "<span class='danger'>You get stuck in \the [src] for a moment.</span>"
|
||||
return 0
|
||||
else if(istype(mover, /obj/item/projectile))
|
||||
return prob(30)
|
||||
return 1
|
||||
|
||||
/obj/effect/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/poison_type = "toxin"
|
||||
var/poison_per_bite = 5
|
||||
var/list/faction = list("spiders")
|
||||
|
||||
/obj/effect/spider/eggcluster/New()
|
||||
pixel_x = rand(3,-3)
|
||||
pixel_y = rand(3,-3)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/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/effect/spider/spiderling/S = new /obj/effect/spider/spiderling(src.loc)
|
||||
S.poison_type = poison_type
|
||||
S.poison_per_bite = poison_per_bite
|
||||
S.faction = faction.Copy()
|
||||
if(player_spiders)
|
||||
S.player_spiders = 1
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spider/spiderling
|
||||
name = "spiderling"
|
||||
desc = "It never stays still for long."
|
||||
icon_state = "spiderling"
|
||||
anchored = 0
|
||||
layer = PROJECTILE_HIT_THRESHHOLD_LAYER
|
||||
health = 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/poison_type = "toxin"
|
||||
var/poison_per_bite = 5
|
||||
var/list/faction = list("spiders")
|
||||
|
||||
/obj/effect/spider/spiderling/New()
|
||||
pixel_x = rand(6,-6)
|
||||
pixel_y = rand(6,-6)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/spider/spiderling/Bump(atom/user)
|
||||
if(istype(user, /obj/structure/table))
|
||||
src.loc = user.loc
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/effect/spider/spiderling/process()
|
||||
if(travelling_in_vent)
|
||||
if(istype(src.loc, /turf))
|
||||
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.PARENT1
|
||||
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 ventillation ducts!</B>", \
|
||||
"<span class='italics'>You hear something scampering through the ventilation ducts.</span>")
|
||||
|
||||
spawn(rand(20,60))
|
||||
loc = exit_vent
|
||||
var/travel_time = round(get_dist(loc, exit_vent.loc) / 2)
|
||||
spawn(travel_time)
|
||||
|
||||
if(!exit_vent || exit_vent.welded)
|
||||
loc = 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)
|
||||
loc = entry_vent
|
||||
entry_vent = null
|
||||
return
|
||||
loc = 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)
|
||||
grow_as = pick(typesof(/mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
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()
|
||||
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)
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
/obj/effect/spider/cocoon
|
||||
name = "cocoon"
|
||||
desc = "Something wrapped in silky spider web"
|
||||
icon_state = "cocoon1"
|
||||
health = 60
|
||||
|
||||
/obj/effect/spider/cocoon/New()
|
||||
icon_state = pick("cocoon1","cocoon2","cocoon3")
|
||||
|
||||
/obj/effect/spider/cocoon/container_resist()
|
||||
var/mob/living/user = usr
|
||||
var/breakout_time = 2
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
user << "<span class='notice'>You struggle against the tight bonds... (This will take about [breakout_time] minutes.)</span>"
|
||||
visible_message("You see something struggling and writhing in \the [src]!")
|
||||
if(do_after(user,(breakout_time*60*10), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src)
|
||||
return
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
/obj/effect/spider/cocoon/Destroy()
|
||||
src.visible_message("<span class='warning'>\The [src] splits open.</span>")
|
||||
for(var/atom/movable/A in contents)
|
||||
A.loc = src.loc
|
||||
return ..()
|
||||
@@ -0,0 +1,192 @@
|
||||
/* 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 = 0
|
||||
invisibility = INVISIBILITY_ABSTRACT // nope cant see this shit
|
||||
anchored = 1
|
||||
|
||||
/obj/effect/step_trigger/proc/Trigger(atom/movable/A)
|
||||
return 0
|
||||
|
||||
/obj/effect/step_trigger/Crossed(H as mob|obj)
|
||||
..()
|
||||
if(!H)
|
||||
return
|
||||
if(istype(H, /mob/dead/observer) && !affect_ghosts)
|
||||
return
|
||||
if(!istype(H, /mob) && mobs_only)
|
||||
return
|
||||
Trigger(H)
|
||||
|
||||
/* Sends a message to mob when triggered*/
|
||||
|
||||
/obj/effect/step_trigger/message
|
||||
var/message //the message to give to the mob
|
||||
var/once = 1
|
||||
|
||||
/obj/effect/step_trigger/message/Trigger(mob/M)
|
||||
if(M.client)
|
||||
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 || !istype(A, /atom/movable))
|
||||
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)
|
||||
|
||||
A.x = teleport_x
|
||||
A.y = teleport_y
|
||||
A.z = teleport_z
|
||||
|
||||
/* 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)
|
||||
|
||||
A.x = rand(teleport_x, teleport_x_offset)
|
||||
A.y = rand(teleport_y, teleport_y_offset)
|
||||
A.z = rand(teleport_z, teleport_z_offset)
|
||||
|
||||
/* 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)
|
||||
A.playsound_local(T, sound, volume, freq_vary)
|
||||
else
|
||||
playsound(T, sound, volume, freq_vary, extra_range)
|
||||
|
||||
if(happens_once)
|
||||
qdel(src)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/obj/item/weapon/poster/legit/wanted
|
||||
var/poster_desc
|
||||
icon_state = "rolled_poster"
|
||||
|
||||
/obj/item/weapon/poster/legit/wanted/New(turf/loc, icon/person_icon, wanted_name, description)
|
||||
..(loc)
|
||||
name = "wanted poster ([wanted_name])"
|
||||
desc = "A wanted poster for [wanted_name]."
|
||||
poster_desc = description
|
||||
qdel(resulting_poster)
|
||||
resulting_poster = new /obj/structure/sign/poster/wanted(person_icon, wanted_name, poster_desc)
|
||||
|
||||
/obj/structure/sign/poster/wanted
|
||||
var/wanted_name
|
||||
|
||||
/obj/structure/sign/poster/wanted/New(var/icon/person_icon, var/person_name, var/description)
|
||||
if(!person_icon)
|
||||
qdel(src)
|
||||
return
|
||||
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/attack_hand(mob/user)
|
||||
..()
|
||||
|
||||
/obj/structure/sign/poster/wanted/attackby()
|
||||
..()
|
||||
|
||||
/obj/structure/sign/poster/wanted/roll_and_drop(turf/location)
|
||||
var/obj/item/weapon/poster/legit/wanted/P = new(src, null, wanted_name, desc)
|
||||
P.resulting_poster = src
|
||||
P.loc = location
|
||||
loc = P
|
||||
@@ -0,0 +1,31 @@
|
||||
/proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
|
||||
if(!epicenter) return
|
||||
|
||||
if(!istype(epicenter, /turf))
|
||||
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)
|
||||
PoolOrNew(/obj/effect/overlay/temp/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(1)
|
||||
else if(distance == heavy_range)
|
||||
if(prob(50))
|
||||
T.emp_act(1)
|
||||
else
|
||||
T.emp_act(2)
|
||||
else if(distance <= light_range)
|
||||
T.emp_act(2)
|
||||
return 1
|
||||
@@ -0,0 +1,244 @@
|
||||
//TODO: Flash range does nothing currently
|
||||
|
||||
/proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1, ignorecap = 0, flame_range = 0 ,silent = 0)
|
||||
set waitfor = 0
|
||||
src = null //so we don't abort once src is deleted
|
||||
epicenter = get_turf(epicenter)
|
||||
|
||||
//DO NOT REMOVE THIS SLEEP, IT BREAKS THINGS
|
||||
//not sleeping causes us to ex_act() the thing that triggered the explosion
|
||||
//doing that might cause it to trigger another explosion
|
||||
//this is bad
|
||||
//I would make this not ex_act the thing that triggered the explosion,
|
||||
//but everything that explodes gives us their loc or a get_turf()
|
||||
//and somethings expect us to ex_act them so they can qdel()
|
||||
sleep(1) //tldr, let the calling proc call qdel(src) before we explode
|
||||
|
||||
// Archive the uncapped explosion for the doppler array
|
||||
var/orig_dev_range = devastation_range
|
||||
var/orig_heavy_range = heavy_impact_range
|
||||
var/orig_light_range = light_impact_range
|
||||
|
||||
if(!ignorecap)
|
||||
// Clamp all values to MAX_EXPLOSION_RANGE
|
||||
devastation_range = min (MAX_EX_DEVESTATION_RANGE, devastation_range)
|
||||
heavy_impact_range = min (MAX_EX_HEAVY_RANGE, heavy_impact_range)
|
||||
light_impact_range = min (MAX_EX_LIGHT_RANGE, light_impact_range)
|
||||
flash_range = min (MAX_EX_FLASH_RANGE, flash_range)
|
||||
flame_range = min (MAX_EX_FLAME_RANGE, flame_range)
|
||||
|
||||
var/start = world.timeofday
|
||||
if(!epicenter) return
|
||||
|
||||
var/max_range = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
|
||||
var/list/cached_exp_block = list()
|
||||
|
||||
if(adminlog)
|
||||
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z] - <a href='?_src_=holder;adminplayerobservecoodjump=1;X=[epicenter.x];Y=[epicenter.y];Z=[epicenter.z]'>JMP</a>)")
|
||||
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z])")
|
||||
|
||||
// Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves.
|
||||
// Stereo users will also hear the direction of the explosion!
|
||||
|
||||
// Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions.
|
||||
// 3/7/14 will calculate to 80 + 35
|
||||
|
||||
var/far_dist = 0
|
||||
far_dist += heavy_impact_range * 5
|
||||
far_dist += devastation_range * 20
|
||||
|
||||
if(!silent)
|
||||
var/frequency = get_rand_frequency()
|
||||
for(var/mob/M in player_list)
|
||||
// Double check for client
|
||||
if(M && M.client)
|
||||
var/turf/M_turf = get_turf(M)
|
||||
if(M_turf && M_turf.z == epicenter.z)
|
||||
var/dist = get_dist(M_turf, epicenter)
|
||||
// If inside the blast radius + world.view - 2
|
||||
if(dist <= round(max_range + world.view - 2, 1))
|
||||
M.playsound_local(epicenter, get_sfx("explosion"), 100, 1, frequency, falloff = 5) // get_sfx() is so that everyone gets the same sound
|
||||
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
|
||||
else if(dist <= far_dist)
|
||||
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
|
||||
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
|
||||
M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
|
||||
|
||||
//postpone processing for a bit
|
||||
var/postponeCycles = max(round(devastation_range/8),1)
|
||||
SSlighting.postpone(postponeCycles)
|
||||
SSmachine.postpone(postponeCycles)
|
||||
|
||||
if(heavy_impact_range > 1)
|
||||
var/datum/effect_system/explosion/E = new/datum/effect_system/explosion()
|
||||
E.set_up(epicenter)
|
||||
E.start()
|
||||
|
||||
var/x0 = epicenter.x
|
||||
var/y0 = epicenter.y
|
||||
var/z0 = epicenter.z
|
||||
|
||||
var/list/affected_turfs = spiral_range_turfs(max_range, epicenter)
|
||||
|
||||
if(config.reactionary_explosions)
|
||||
for(var/turf/T in affected_turfs) // we cache the explosion block rating of every turf in the explosion area
|
||||
cached_exp_block[T] = 0
|
||||
if(T.density && T.explosion_block)
|
||||
cached_exp_block[T] += T.explosion_block
|
||||
|
||||
for(var/obj/machinery/door/D in T)
|
||||
if(D.density && D.explosion_block)
|
||||
cached_exp_block[T] += D.explosion_block
|
||||
|
||||
for(var/obj/structure/window/W in T)
|
||||
if(W.reinf && W.fulltile)
|
||||
cached_exp_block[T] += W.explosion_block
|
||||
|
||||
for(var/obj/effect/blob/B in T)
|
||||
cached_exp_block[T] += B.explosion_block
|
||||
CHECK_TICK
|
||||
|
||||
for(var/turf/T in affected_turfs)
|
||||
|
||||
if (!T)
|
||||
continue
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
||||
|
||||
if(config.reactionary_explosions)
|
||||
var/turf/Trajectory = T
|
||||
while(Trajectory != epicenter)
|
||||
Trajectory = get_step_towards(Trajectory, epicenter)
|
||||
dist += cached_exp_block[Trajectory]
|
||||
|
||||
var/flame_dist = 0
|
||||
var/throw_dist = dist
|
||||
|
||||
if(dist < flame_range)
|
||||
flame_dist = 1
|
||||
|
||||
if(dist < devastation_range)
|
||||
dist = 1
|
||||
else if(dist < heavy_impact_range)
|
||||
dist = 2
|
||||
else if(dist < light_impact_range)
|
||||
dist = 3
|
||||
else
|
||||
dist = 0
|
||||
|
||||
//------- TURF FIRES -------
|
||||
|
||||
if(T)
|
||||
if(flame_dist && prob(40) && !istype(T, /turf/open/space) && !T.density)
|
||||
PoolOrNew(/obj/effect/hotspot, T) //Mostly for ambience!
|
||||
if(dist > 0)
|
||||
T.ex_act(dist)
|
||||
|
||||
//--- THROW ITEMS AROUND ---
|
||||
|
||||
var/throw_dir = get_dir(epicenter,T)
|
||||
for(var/obj/item/I in T)
|
||||
if(I && !I.anchored)
|
||||
var/throw_range = rand(throw_dist, max_range)
|
||||
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
|
||||
I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Reset when it finishes throwing, regardless of hitting anything)
|
||||
I.throw_at_fast(throw_at, throw_range, 2)//Throw it at 2 speed, this is purely visual anyway.
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
var/took = (world.timeofday-start)/10
|
||||
//You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
|
||||
if(Debug2)
|
||||
world.log << "## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds."
|
||||
|
||||
//Machines which report explosions.
|
||||
for(var/array in doppler_arrays)
|
||||
var/obj/machinery/doppler_array/A = array
|
||||
A.sense_explosion(epicenter,devastation_range,heavy_impact_range,light_impact_range,took,orig_dev_range,orig_heavy_range,orig_light_range)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/proc/secondaryexplosion(turf/epicenter, range)
|
||||
for(var/turf/tile in spiral_range_turfs(range, epicenter))
|
||||
tile.ex_act(2)
|
||||
|
||||
|
||||
/client/proc/check_bomb_impacts()
|
||||
set name = "Check Bomb Impact"
|
||||
set category = "Debug"
|
||||
|
||||
var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No")
|
||||
var/turf/epicenter = get_turf(mob)
|
||||
if(!epicenter)
|
||||
return
|
||||
|
||||
var/dev = 0
|
||||
var/heavy = 0
|
||||
var/light = 0
|
||||
var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb")
|
||||
var/choice = input("Bomb Size?") in choices
|
||||
switch(choice)
|
||||
if(null)
|
||||
return 0
|
||||
if("Small Bomb")
|
||||
dev = 1
|
||||
heavy = 2
|
||||
light = 3
|
||||
if("Medium Bomb")
|
||||
dev = 2
|
||||
heavy = 3
|
||||
light = 4
|
||||
if("Big Bomb")
|
||||
dev = 3
|
||||
heavy = 5
|
||||
light = 7
|
||||
if("Custom Bomb")
|
||||
dev = input("Devestation range (Tiles):") as num
|
||||
heavy = input("Heavy impact range (Tiles):") as num
|
||||
light = input("Light impact range (Tiles):") as num
|
||||
|
||||
var/max_range = max(dev, heavy, light)
|
||||
var/x0 = epicenter.x
|
||||
var/y0 = epicenter.y
|
||||
var/list/wipe_colours = list()
|
||||
for(var/turf/T in spiral_range_turfs(max_range, epicenter))
|
||||
wipe_colours += T
|
||||
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0)
|
||||
|
||||
if(newmode == "Yes")
|
||||
var/turf/TT = T
|
||||
while(TT != epicenter)
|
||||
TT = get_step_towards(TT,epicenter)
|
||||
if(TT.density && TT.explosion_block)
|
||||
dist += TT.explosion_block
|
||||
|
||||
for(var/obj/machinery/door/D in TT)
|
||||
if(D.density && D.explosion_block)
|
||||
dist += D.explosion_block
|
||||
|
||||
for(var/obj/structure/window/W in TT)
|
||||
if(W.explosion_block && W.fulltile)
|
||||
dist += W.explosion_block
|
||||
|
||||
for(var/obj/effect/blob/B in T)
|
||||
dist += B.explosion_block
|
||||
|
||||
if(dist < dev)
|
||||
T.color = "red"
|
||||
T.maptext = "Dev"
|
||||
else if (dist < heavy)
|
||||
T.color = "yellow"
|
||||
T.maptext = "Heavy"
|
||||
else if (dist < light)
|
||||
T.color = "blue"
|
||||
T.maptext = "Light"
|
||||
else
|
||||
continue
|
||||
|
||||
sleep(100)
|
||||
for(var/turf/T in wipe_colours)
|
||||
T.color = null
|
||||
T.maptext = ""
|
||||
|
||||
|
||||
@@ -0,0 +1,577 @@
|
||||
var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_state" = "fire")
|
||||
|
||||
/obj/item
|
||||
name = "item"
|
||||
icon = 'icons/obj/items.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
|
||||
|
||||
var/hitsound = null
|
||||
var/throwhitsound = null
|
||||
var/w_class = 3
|
||||
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
|
||||
pass_flags = PASSTABLE
|
||||
pressure_resistance = 3
|
||||
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() //list of /datum/action's that this item has.
|
||||
var/list/actions_types = list() //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/item_color = null //this needs deprecating, soonish
|
||||
|
||||
var/body_parts_covered = 0 //see setup.dm for appropriate bit flags
|
||||
//var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible
|
||||
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/list/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
|
||||
var/armour_penetration = 0 //percentage of armour effectiveness to remove
|
||||
var/list/allowed = null //suit storage stuff.
|
||||
var/obj/item/device/uplink/hidden_uplink = null
|
||||
var/strip_delay = 40
|
||||
var/put_on_delay = 20
|
||||
var/breakouttime = 0
|
||||
var/list/materials = list()
|
||||
var/origin_tech = null //Used by R&D to determine what research bonuses it grants.
|
||||
var/needs_permit = 0 //Used by security bots to determine if this item is safe for public use.
|
||||
|
||||
var/list/attack_verb = list() //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/suittoggled = 0
|
||||
var/hooded = 0
|
||||
|
||||
var/mob/thrownby = null
|
||||
|
||||
/obj/item/mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
|
||||
|
||||
//So items can have custom embedd values
|
||||
//Because customisation is king
|
||||
var/embed_chance = EMBED_CHANCE
|
||||
var/embedded_fall_chance = EMBEDDED_ITEM_FALLOUT
|
||||
var/embedded_pain_chance = EMBEDDED_PAIN_CHANCE
|
||||
var/embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
|
||||
var/embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
|
||||
var/embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
|
||||
var/embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
|
||||
var/embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME //A time in ticks, multiplied by the w_class.
|
||||
|
||||
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
|
||||
var/heat = 0
|
||||
var/sharpness = IS_BLUNT
|
||||
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
|
||||
|
||||
//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
|
||||
|
||||
|
||||
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
|
||||
if(((src in target) && !target_self) || (!istype(target.loc, /turf) && !istype(target, /turf) && not_inside))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
/obj/item/device
|
||||
icon = 'icons/obj/device.dmi'
|
||||
|
||||
/obj/item/New()
|
||||
..()
|
||||
for(var/path in actions_types)
|
||||
new path(src)
|
||||
|
||||
/obj/item/Destroy()
|
||||
if(ismob(loc))
|
||||
var/mob/m = loc
|
||||
m.unEquip(src, 1)
|
||||
for(var/X in actions)
|
||||
qdel(X)
|
||||
return ..()
|
||||
|
||||
/obj/item/blob_act(obj/effect/blob/B)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/ex_act(severity, target)
|
||||
if(severity == 1 || target == src)
|
||||
qdel(src)
|
||||
if(!qdeleted(src))
|
||||
contents_explosion(severity, target)
|
||||
|
||||
//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(!istype(src.loc, /turf) || 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/size
|
||||
switch(src.w_class)
|
||||
if(1)
|
||||
size = "tiny"
|
||||
if(2)
|
||||
size = "small"
|
||||
if(3)
|
||||
size = "normal-sized"
|
||||
if(4)
|
||||
size = "bulky"
|
||||
if(5)
|
||||
size = "huge"
|
||||
if(6)
|
||||
size = "gigantic"
|
||||
else
|
||||
//if ((CLUMSY in usr.mutations) && prob(50)) t = "funny-looking"
|
||||
|
||||
var/pronoun
|
||||
if(src.gender == PLURAL)
|
||||
pronoun = "They are"
|
||||
else
|
||||
pronoun = "It is"
|
||||
|
||||
user << "[pronoun] a [size] item." //e.g. They are a small item. or It is a bulky item.
|
||||
|
||||
if(user.research_scanner) //Mob has a research scanner active.
|
||||
var/msg = "*--------* <BR>"
|
||||
|
||||
if(origin_tech)
|
||||
msg += "<span class='notice'>Testing potentials:</span><BR>"
|
||||
var/list/techlvls = params2list(origin_tech)
|
||||
for(var/T in techlvls) //This needs to use the better names.
|
||||
msg += "Tech: [CallTechName(T)] | magnitude: [techlvls[T]] <BR>"
|
||||
else
|
||||
msg += "<span class='danger'>No tech origins detected.</span><BR>"
|
||||
|
||||
|
||||
if(materials.len)
|
||||
msg += "<span class='notice'>Extractable materials:<BR>"
|
||||
for(var/mat in materials)
|
||||
msg += "[CallMaterialName(mat)]<BR>" //Capitize first word, remove the "$"
|
||||
else
|
||||
msg += "<span class='danger'>No extractable materials detected.</span><BR>"
|
||||
msg += "*--------*"
|
||||
user << msg
|
||||
|
||||
|
||||
/obj/item/attack_self(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/item/interact(mob/user)
|
||||
add_fingerprint(user)
|
||||
if(hidden_uplink && hidden_uplink.active)
|
||||
hidden_uplink.interact(user)
|
||||
return 1
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/ui_act(action, params)
|
||||
add_fingerprint(usr)
|
||||
return ..()
|
||||
|
||||
/obj/item/attack_hand(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
if(anchored)
|
||||
return
|
||||
|
||||
if(burn_state == ON_FIRE)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H))
|
||||
if(H.gloves && (H.gloves.max_heat_protection_temperature > 360))
|
||||
extinguish()
|
||||
user << "<span class='notice'>You put out the fire on [src].</span>"
|
||||
else
|
||||
user << "<span class='warning'>You burn your hand on [src]!</span>"
|
||||
var/obj/item/bodypart/affecting = H.get_bodypart("[user.hand ? "l" : "r" ]_arm")
|
||||
if(affecting && affecting.take_damage( 0, 5 )) // 5 burn damage
|
||||
H.update_damage_overlays(0)
|
||||
H.updatehealth()
|
||||
return
|
||||
else
|
||||
extinguish()
|
||||
|
||||
if(istype(loc, /obj/item/weapon/storage))
|
||||
//If the item is in a storage item, take it out
|
||||
var/obj/item/weapon/storage/S = loc
|
||||
S.remove_from_storage(src, user.loc)
|
||||
|
||||
throwing = 0
|
||||
if(loc == user)
|
||||
if(!user.unEquip(src))
|
||||
return
|
||||
|
||||
pickup(user)
|
||||
add_fingerprint(user)
|
||||
if(!user.put_in_active_hand(src))
|
||||
dropped(user)
|
||||
|
||||
|
||||
/obj/item/attack_paw(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
if(anchored)
|
||||
return
|
||||
|
||||
if(istype(loc, /obj/item/weapon/storage))
|
||||
var/obj/item/weapon/storage/S = loc
|
||||
S.remove_from_storage(src, user.loc)
|
||||
|
||||
throwing = 0
|
||||
if(loc == user)
|
||||
if(!user.unEquip(src))
|
||||
return
|
||||
|
||||
pickup(user)
|
||||
add_fingerprint(user)
|
||||
if(!user.put_in_active_hand(src))
|
||||
dropped(user)
|
||||
|
||||
/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.unEquip(src)
|
||||
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/weapon/robot_module))
|
||||
//If the item is part of a cyborg module, equip it
|
||||
if(!isrobot(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()
|
||||
|
||||
// Due to storage type consolidation this should get used more now.
|
||||
// I have cleaned it up a little, but it could probably use more. -Sayu
|
||||
/obj/item/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W,/obj/item/weapon/storage))
|
||||
var/obj/item/weapon/storage/S = W
|
||||
if(S.use_to_pickup)
|
||||
if(S.collection_mode) //Mode is set to collect multiple items on a tile and we clicked on a valid one.
|
||||
if(isturf(src.loc))
|
||||
var/list/rejections = list()
|
||||
var/success = 0
|
||||
var/failure = 0
|
||||
|
||||
for(var/obj/item/I in src.loc)
|
||||
if(S.collection_mode == 2 && !istype(I,src.type)) // We're only picking up items of the target type
|
||||
failure = 1
|
||||
continue
|
||||
if(I.type in rejections) // To limit bag spamming: any given type only complains once
|
||||
continue
|
||||
if(!S.can_be_inserted(I)) // Note can_be_inserted still makes noise when the answer is no
|
||||
rejections += I.type // therefore full bags are still a little spammy
|
||||
failure = 1
|
||||
continue
|
||||
|
||||
success = 1
|
||||
S.handle_item_insertion(I, 1) //The 1 stops the "You put the [src] into [S]" insertion message from being displayed.
|
||||
if(success && !failure)
|
||||
user << "<span class='notice'>You put everything [S.preposition] [S].</span>"
|
||||
else if(success)
|
||||
user << "<span class='notice'>You put some things [S.preposition] [S].</span>"
|
||||
else
|
||||
user << "<span class='warning'>You fail to pick anything up with [S]!</span>"
|
||||
|
||||
else if(S.can_be_inserted(src))
|
||||
S.handle_item_insertion(src)
|
||||
|
||||
|
||||
// afterattack() and attack() prototypes moved to _onclick/item_attack.dm for consistency
|
||||
|
||||
/obj/item/proc/hit_reaction(mob/living/carbon/human/owner, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
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)
|
||||
return
|
||||
|
||||
/obj/item/proc/dropped(mob/user)
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.Remove(user)
|
||||
if(DROPDEL & flags)
|
||||
qdel(src)
|
||||
|
||||
// called just as an item is picked up (loc is not yet changed)
|
||||
/obj/item/proc/pickup(mob/user)
|
||||
return
|
||||
|
||||
|
||||
// called when this item is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called.
|
||||
/obj/item/proc/on_exit_storage(obj/item/weapon/storage/S)
|
||||
return
|
||||
|
||||
// called when this item is added into a storage item, which is passed on as S. The loc variable is already set to the storage item.
|
||||
/obj/item/proc/on_enter_storage(obj/item/weapon/storage/S)
|
||||
return
|
||||
|
||||
// called when "found" in pockets and storage items. Returns 1 if the search should end.
|
||||
/obj/item/proc/on_found(mob/finder)
|
||||
return
|
||||
|
||||
// called after an item is placed in an equipment slot //NOPE, for example, if you put a helmet in slot_head, it is NOT in user's head variable yet, how stupid.
|
||||
// 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)
|
||||
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)
|
||||
|
||||
//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)
|
||||
return 1
|
||||
|
||||
//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 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/M, slot, disable_warning = 0)
|
||||
if(!M)
|
||||
return 0
|
||||
|
||||
return M.can_equip(src, slot, disable_warning)
|
||||
|
||||
/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_hand() == 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, paralyzed, 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)
|
||||
|
||||
var/is_human_victim = 0
|
||||
var/obj/item/bodypart/affecting = M.get_bodypart("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!
|
||||
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!
|
||||
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!
|
||||
user << "<span class='warning'>You cannot locate any eyes on this creature!</span>"
|
||||
return
|
||||
|
||||
if(isbrain(M))
|
||||
user << "<span class='danger'>You cannot locate any organic eyes on this brain!</span>"
|
||||
return
|
||||
|
||||
src.add_fingerprint(user)
|
||||
|
||||
playsound(loc, src.hitsound, 30, 1, -1)
|
||||
|
||||
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>")
|
||||
user.do_attack_animation(M)
|
||||
else
|
||||
user.visible_message( \
|
||||
"<span class='danger'>[user] has stabbed themself 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
|
||||
if(affecting.take_damage(7))
|
||||
U.update_damage_overlays(0)
|
||||
|
||||
else
|
||||
M.take_organ_damage(7)
|
||||
|
||||
add_logs(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])")
|
||||
|
||||
M.adjust_blurriness(3)
|
||||
M.adjust_eye_damage(rand(2,4))
|
||||
if(M.eye_damage >= 10)
|
||||
M.adjust_blurriness(15)
|
||||
if(M.stat != DEAD)
|
||||
M << "<span class='danger'>Your eyes start to bleed profusely!</span>"
|
||||
if(!(M.disabilities & (NEARSIGHT | BLIND)))
|
||||
if(M.become_nearsighted())
|
||||
M << "<span class='danger'>You become nearsighted!</span>"
|
||||
if(prob(50))
|
||||
if(M.stat != DEAD)
|
||||
if(M.drop_item())
|
||||
M << "<span class='danger'>You drop what you're holding and clutch at your eyes!</span>"
|
||||
M.adjust_blurriness(10)
|
||||
M.Paralyse(1)
|
||||
M.Weaken(2)
|
||||
if (prob(M.eye_damage - 10 + 1))
|
||||
if(M.become_blind())
|
||||
M << "<span class='danger'>You go blind!</span>"
|
||||
|
||||
/obj/item/clean_blood()
|
||||
. = ..()
|
||||
if(.)
|
||||
if(initial(icon) && initial(icon_state))
|
||||
var/index = blood_splatter_index()
|
||||
var/icon/blood_splatter_icon = blood_splatter_icons[index]
|
||||
if(blood_splatter_icon)
|
||||
overlays -= blood_splatter_icon
|
||||
|
||||
/obj/item/clothing/gloves/clean_blood()
|
||||
. = ..()
|
||||
if(.)
|
||||
transfer_blood = 0
|
||||
|
||||
/obj/item/singularity_pull(S, current_size)
|
||||
if(current_size >= STAGE_FOUR)
|
||||
throw_at_fast(S,14,3, spin=0)
|
||||
else ..()
|
||||
|
||||
/obj/item/acid_act(acidpwr, acid_volume)
|
||||
. = 1
|
||||
if(unacidable)
|
||||
return
|
||||
|
||||
var/meltingpwr = acid_volume*acidpwr
|
||||
var/melting_threshold = 100
|
||||
if(meltingpwr <= melting_threshold) // so a single unit can't melt items. You need 5.1+ unit for fluoro and 10.1+ for sulphuric
|
||||
return
|
||||
for(var/V in armor)
|
||||
if(armor[V] > 0)
|
||||
.-- //it survives the acid...
|
||||
break
|
||||
if(. && prob(min(meltingpwr/10,90))) //chance to melt depends on acid power and volume.
|
||||
var/turf/T = get_turf(src)
|
||||
if(T)
|
||||
var/obj/effect/decal/cleanable/molten_item/I = new (T)
|
||||
I.pixel_x = rand(-16,16)
|
||||
I.pixel_y = rand(-16,16)
|
||||
I.desc = "Looks like this was \an [src] some time ago."
|
||||
if(istype(src,/obj/item/weapon/storage))
|
||||
var/obj/item/weapon/storage/S = src
|
||||
S.do_quick_empty() //melted storage item drops its content.
|
||||
qdel(src)
|
||||
else
|
||||
for(var/armour_value in armor) //but is weakened
|
||||
armor[armour_value] = max(armor[armour_value]-min(acidpwr,meltingpwr/10),0)
|
||||
if(!findtext(desc, "it looks slightly melted...")) //it looks slightly melted... it looks slightly melted... it looks slightly melted... etc.
|
||||
desc += " it looks slightly melted..." //needs a space at the start, formatting
|
||||
|
||||
/obj/item/throw_impact(atom/A)
|
||||
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)
|
||||
thrownby = thrower
|
||||
. = ..()
|
||||
throw_speed = initial(throw_speed) //explosions change this.
|
||||
|
||||
|
||||
/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/weapon/storage
|
||||
if(!newLoc)
|
||||
return 0
|
||||
if(istype(loc,/obj/item/weapon/storage))
|
||||
var/obj/item/weapon/storage/S = loc
|
||||
S.remove_from_storage(src,newLoc)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/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 >= 3)
|
||||
. = force*(w_class-1)
|
||||
|
||||
/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()
|
||||
var/turf/location = loc
|
||||
if(ismob(location))
|
||||
var/mob/M = location
|
||||
if(M.l_hand == src || M.r_hand == src)
|
||||
location = get_turf(M)
|
||||
if(isturf(location))
|
||||
location.hotspot_expose(700, 5)
|
||||
@@ -0,0 +1,108 @@
|
||||
/obj/item/wallframe
|
||||
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT*2)
|
||||
flags = CONDUCT
|
||||
origin_tech = "materials=1;engineering=1"
|
||||
item_state = "syringe_kit"
|
||||
w_class = 2
|
||||
var/result_path
|
||||
var/inverse = 0
|
||||
// For inverse dir frames like light fixtures.
|
||||
|
||||
/obj/item/wallframe/proc/try_build(turf/on_wall)
|
||||
if(get_dist(on_wall,usr)>1)
|
||||
return
|
||||
var/ndir = get_dir(on_wall, usr)
|
||||
if(!(ndir in cardinal))
|
||||
return
|
||||
var/turf/loc = get_turf(usr)
|
||||
var/area/A = loc.loc
|
||||
if(!istype(loc, /turf/open/floor))
|
||||
usr << "<span class='warning'>You cannot place [src] on this spot!</span>"
|
||||
return
|
||||
if(A.requires_power == 0 || istype(A, /area/space))
|
||||
usr << "<span class='warning'>You cannot place [src] in this area!</span>"
|
||||
return
|
||||
if(gotwallitem(loc, ndir, inverse*2))
|
||||
usr << "<span class='warning'>There's already an item on this wall!</span>"
|
||||
return
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/wallframe/proc/attach(turf/on_wall)
|
||||
if(result_path)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
|
||||
usr.visible_message("[usr.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,usr)
|
||||
if(inverse)
|
||||
ndir = turn(ndir, 180)
|
||||
|
||||
var/obj/O = new result_path(get_turf(usr), ndir, 1)
|
||||
after_attach(O)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/item/wallframe/proc/after_attach(var/obj/O)
|
||||
transfer_fingerprints_to(O)
|
||||
|
||||
/obj/item/wallframe/attackby(obj/item/weapon/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
// For camera-building borgs
|
||||
var/turf/T = get_step(get_turf(user), user.dir)
|
||||
if(istype(T, /turf/closed/wall))
|
||||
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/weapon/wrench) && (metal_amt || glass_amt))
|
||||
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 = 'icons/obj/apc_repair.dmi'
|
||||
icon_state = "apc_frame"
|
||||
result_path = /obj/machinery/power/apc
|
||||
inverse = 1
|
||||
|
||||
|
||||
/obj/item/wallframe/apc/try_build(turf/on_wall)
|
||||
if(!..())
|
||||
return
|
||||
var/turf/loc = get_turf(usr)
|
||||
var/area/A = loc.loc
|
||||
if (A.get_apc())
|
||||
usr << "<span class='warning'>This area already has APC!</span>"
|
||||
return //only one APC per area
|
||||
for(var/obj/machinery/power/terminal/T in loc)
|
||||
if (T.master)
|
||||
usr << "<span class='warning'>There is another network terminal here!</span>"
|
||||
return
|
||||
else
|
||||
var/obj/item/stack/cable_coil/C = new /obj/item/stack/cable_coil(loc)
|
||||
C.amount = 10
|
||||
usr << "<span class='notice'>You cut the cables and disassemble the unused power terminal.</span>"
|
||||
qdel(T)
|
||||
return 1
|
||||
|
||||
|
||||
/obj/item/weapon/electronics
|
||||
desc = "Looks like a circuit. Probably is."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "door_electronics"
|
||||
item_state = "electronic"
|
||||
flags = CONDUCT
|
||||
w_class = 2
|
||||
origin_tech = "engineering=2;programming=1"
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=50)
|
||||
@@ -0,0 +1,350 @@
|
||||
/obj/item/areaeditor
|
||||
name = "area modification item"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "blueprints"
|
||||
attack_verb = list("attacked", "bapped", "hit")
|
||||
var/fluffnotice = "Nobody's gonna read this stuff!"
|
||||
|
||||
var/const/AREA_ERRNONE = 0
|
||||
var/const/AREA_STATION = 1
|
||||
var/const/AREA_SPACE = 2
|
||||
var/const/AREA_SPECIAL = 3
|
||||
|
||||
var/const/BORDER_ERROR = 0
|
||||
var/const/BORDER_NONE = 1
|
||||
var/const/BORDER_BETWEEN = 2
|
||||
var/const/BORDER_2NDTILE = 3
|
||||
var/const/BORDER_SPACE = 4
|
||||
|
||||
var/const/ROOM_ERR_LOLWAT = 0
|
||||
var/const/ROOM_ERR_SPACE = -1
|
||||
var/const/ROOM_ERR_TOOLARGE = -2
|
||||
|
||||
|
||||
/obj/item/areaeditor/attack_self(mob/user)
|
||||
add_fingerprint(user)
|
||||
var/text = "<BODY><HTML><head><title>[src]</title></head> \
|
||||
<h2>[station_name()] [src.name]</h2> \
|
||||
<small>[fluffnotice]</small><hr>"
|
||||
switch(get_area_type())
|
||||
if(AREA_SPACE)
|
||||
text += "<p>According to the [src.name], you are now in an unclaimed territory.</p> \
|
||||
<p><a href='?src=\ref[src];create_area=1'>Mark this place as new area.</a></p>"
|
||||
if(AREA_SPECIAL)
|
||||
text += "<p>This place is not noted on the [src.name].</p>"
|
||||
return text
|
||||
|
||||
|
||||
/obj/item/areaeditor/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(!usr.canUseTopic(src))
|
||||
usr << browse(null, "window=blueprints")
|
||||
return
|
||||
if(href_list["create_area"])
|
||||
if(get_area_type()==AREA_SPACE)
|
||||
create_area()
|
||||
updateUsrDialog()
|
||||
|
||||
|
||||
//One-use area creation permits.
|
||||
/obj/item/areaeditor/permit
|
||||
name = "construction permit"
|
||||
icon_state = "permit"
|
||||
desc = "This is a one-use permit that allows the user to offically declare a built room as new addition to the station."
|
||||
fluffnotice = "Nanotrasen Engineering requires all on-station construction projects to be approved by a head of staff, as detailed in Nanotrasen Company Regulation 512-C (Mid-Shift Modifications to Company Property). \
|
||||
By submitting this form, you accept any fines, fees, or personal injury/death that may occur during construction."
|
||||
w_class = 1
|
||||
|
||||
|
||||
/obj/item/areaeditor/permit/attack_self(mob/user)
|
||||
. = ..()
|
||||
var/area/A = get_area()
|
||||
if(get_area_type() == AREA_STATION)
|
||||
. += "<p>According to \the [src], you are now in <b>\"[html_encode(A.name)]\"</b>.</p>"
|
||||
var/datum/browser/popup = new(user, "blueprints", "[src]", 700, 500)
|
||||
popup.set_content(.)
|
||||
popup.open()
|
||||
onclose(usr, "blueprints")
|
||||
|
||||
|
||||
/obj/item/areaeditor/permit/create_area()
|
||||
var/success = ..()
|
||||
if(success)
|
||||
qdel(src)
|
||||
|
||||
|
||||
//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.dmi'
|
||||
icon_state = "blueprints"
|
||||
fluffnotice = "Property of Nanotrasen. For heads of staff only. Store in high-secure storage."
|
||||
var/list/image/showing = list()
|
||||
var/client/viewing
|
||||
|
||||
|
||||
/obj/item/areaeditor/blueprints/Destroy()
|
||||
clear_viewer()
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/areaeditor/blueprints/attack_self(mob/user)
|
||||
. = ..()
|
||||
var/area/A = get_area()
|
||||
if(get_area_type() == AREA_STATION)
|
||||
. += "<p>According to \the [src], you are now in <b>\"[html_encode(A.name)]\"</b>.</p>"
|
||||
. += "<p>You may <a href='?src=\ref[src];edit_area=1'>make an amendment</a> to the drawing.</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>"
|
||||
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(href_list["edit_area"])
|
||||
if(get_area_type()!=AREA_STATION)
|
||||
return
|
||||
edit_area()
|
||||
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/tt in RANGE_TURFS(viewsize, T))
|
||||
var/turf/TT = tt
|
||||
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)
|
||||
user << message
|
||||
|
||||
/obj/item/areaeditor/blueprints/proc/clear_viewer(mob/user, message = "")
|
||||
if(viewing)
|
||||
viewing.images -= showing
|
||||
viewing = null
|
||||
showing.Cut()
|
||||
if(message)
|
||||
user << message
|
||||
|
||||
/obj/item/areaeditor/blueprints/dropped(mob/user)
|
||||
..()
|
||||
clear_viewer()
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/get_area()
|
||||
var/turf/T = get_turf(usr)
|
||||
var/area/A = T.loc
|
||||
A = A.master
|
||||
return A
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/get_area_type(area/A = get_area())
|
||||
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,
|
||||
/area/prison
|
||||
)
|
||||
for (var/type in SPECIALS)
|
||||
if ( istype(A,type) )
|
||||
return AREA_SPECIAL
|
||||
return AREA_STATION
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/create_area()
|
||||
var/res = detect_room(get_turf(usr))
|
||||
if(!istype(res,/list))
|
||||
switch(res)
|
||||
if(ROOM_ERR_SPACE)
|
||||
usr << "<span class='warning'>The new area must be completely airtight.</span>"
|
||||
return
|
||||
if(ROOM_ERR_TOOLARGE)
|
||||
usr << "<span class='warning'>The new area is too large.</span>"
|
||||
return
|
||||
else
|
||||
usr << "<span class='warning'>Error! Please notify administration.</span>"
|
||||
return
|
||||
|
||||
var/list/turfs = res
|
||||
var/str = trim(stripped_input(usr,"New area name:", "Blueprint Editing", "", MAX_NAME_LEN))
|
||||
if(!str || !length(str)) //cancel
|
||||
return
|
||||
if(length(str) > 50)
|
||||
usr << "<span class='warning'>The given name is too long. The area remains undefined.</span>"
|
||||
return
|
||||
var/area/old = get_area(get_turf(src))
|
||||
var/old_gravity = old.has_gravity
|
||||
|
||||
var/area/A
|
||||
for(var/key in turfs)
|
||||
if(key == str)
|
||||
A = turfs[key]
|
||||
if(turfs[key])
|
||||
turfs -= turfs[key]
|
||||
turfs -= key
|
||||
if(A)
|
||||
A.contents += turfs
|
||||
A.SetDynamicLighting()
|
||||
else
|
||||
A = new
|
||||
A.setup(str)
|
||||
A.contents += turfs
|
||||
A.SetDynamicLighting()
|
||||
A.has_gravity = old_gravity
|
||||
interact()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/edit_area()
|
||||
var/area/A = get_area()
|
||||
var/prevname = "[A.name]"
|
||||
var/str = trim(stripped_input(usr,"New area name:", "Blueprint Editing", "", MAX_NAME_LEN))
|
||||
if(!str || !length(str) || str==prevname) //cancel
|
||||
return
|
||||
if(length(str) > 50)
|
||||
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)
|
||||
for(var/area/RA in A.related)
|
||||
RA.name = str
|
||||
usr << "<span class='notice'>You rename the '[prevname]' to '[str]'.</span>"
|
||||
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/area/RA in A.related)
|
||||
for(var/obj/machinery/airalarm/M in RA)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/power/apc/M in RA)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/M in RA)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/M in RA)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/door/M in RA)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
//TODO: much much more. Unnamed airlocks, cameras, etc.
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/check_tile_is_border(turf/T2,dir)
|
||||
if (istype(T2, /turf/open/space))
|
||||
return BORDER_SPACE //omg hull breach we all going to die here
|
||||
if (get_area_type(T2.loc)!=AREA_SPACE)
|
||||
return BORDER_BETWEEN
|
||||
if (istype(T2, /turf/closed/wall))
|
||||
return BORDER_2NDTILE
|
||||
if (!istype(T2, /turf))
|
||||
return BORDER_BETWEEN
|
||||
|
||||
for (var/obj/structure/window/W in T2)
|
||||
if(turn(dir,180) == W.dir)
|
||||
return BORDER_BETWEEN
|
||||
if (W.dir in list(NORTHEAST,SOUTHEAST,NORTHWEST,SOUTHWEST))
|
||||
return BORDER_2NDTILE
|
||||
for(var/obj/machinery/door/window/D in T2)
|
||||
if(turn(dir,180) == D.dir)
|
||||
return BORDER_BETWEEN
|
||||
if (locate(/obj/machinery/door) in T2)
|
||||
return BORDER_2NDTILE
|
||||
if (locate(/obj/structure/falsewall) in T2)
|
||||
return BORDER_2NDTILE
|
||||
|
||||
return BORDER_NONE
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/detect_room(turf/first)
|
||||
var/list/turf/found = new
|
||||
var/list/turf/pending = list(first)
|
||||
var/list/border = list()
|
||||
while(pending.len)
|
||||
if (found.len+pending.len > 300)
|
||||
return ROOM_ERR_TOOLARGE
|
||||
var/turf/T = pending[1] //why byond havent list::pop()?
|
||||
pending -= T
|
||||
for (var/dir in cardinal)
|
||||
var/skip = 0
|
||||
for (var/obj/structure/window/W in T)
|
||||
if(dir == W.dir || (W.dir in list(NORTHEAST,SOUTHEAST,NORTHWEST,SOUTHWEST)))
|
||||
skip = 1
|
||||
break
|
||||
if (skip)
|
||||
continue
|
||||
for(var/obj/machinery/door/window/D in T)
|
||||
if(dir == D.dir)
|
||||
skip = 1
|
||||
break
|
||||
if (skip)
|
||||
continue
|
||||
|
||||
var/turf/NT = get_step(T,dir)
|
||||
if (!isturf(NT) || (NT in found) || (NT in pending))
|
||||
continue
|
||||
|
||||
switch(check_tile_is_border(NT,dir))
|
||||
if(BORDER_NONE)
|
||||
pending+=NT
|
||||
if(BORDER_BETWEEN)
|
||||
var/area/A = NT.loc
|
||||
if(!found[A.name])
|
||||
found[A.name] = NT.loc
|
||||
if(BORDER_2NDTILE)
|
||||
border[NT] += dir
|
||||
if(BORDER_SPACE)
|
||||
return ROOM_ERR_SPACE
|
||||
found+=T
|
||||
|
||||
for(var/V in border) //lazy but works
|
||||
var/turf/F = V
|
||||
for(var/direction in cardinal)
|
||||
if(direction == border[F])
|
||||
continue //don't want to grab turfs from outside the border
|
||||
var/turf/U = get_step(F, direction)
|
||||
if((U in border) || (U in found))
|
||||
continue
|
||||
if(check_tile_is_border(U, direction) == BORDER_2NDTILE)
|
||||
found += U
|
||||
found |= F
|
||||
return found
|
||||
|
||||
|
||||
|
||||
//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.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,52 @@
|
||||
/obj/item/organ/body_egg
|
||||
name = "body egg"
|
||||
desc = "All slimy and yuck."
|
||||
icon_state = "innards"
|
||||
origin_tech = "biotech=5"
|
||||
zone = "chest"
|
||||
slot = "parasite_egg"
|
||||
|
||||
/obj/item/organ/body_egg/on_find(mob/living/finder)
|
||||
..()
|
||||
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)
|
||||
..()
|
||||
owner.status_flags |= XENO_HOST
|
||||
START_PROCESSING(SSobj, src)
|
||||
owner.med_hud_set_status()
|
||||
addtimer(src, "AddInfectionImages", 0, FALSE, owner)
|
||||
|
||||
/obj/item/organ/body_egg/Remove(var/mob/living/carbon/M, special = 0)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(owner)
|
||||
owner.status_flags &= ~(XENO_HOST)
|
||||
owner.med_hud_set_status()
|
||||
addtimer(src, "RemoveInfectionImages", 0, FALSE, 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,107 @@
|
||||
//Also contains /obj/structure/closet/body_bag because I doubt anyone would think to look for bodybags in /object/structures
|
||||
|
||||
/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 = 2
|
||||
|
||||
/obj/item/bodybag/attack_self(mob/user)
|
||||
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(user.loc)
|
||||
R.add_fingerprint(user)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/item/weapon/storage/box/bodybags
|
||||
name = "body bags"
|
||||
desc = "The label indicates that it contains body bags."
|
||||
icon_state = "bodybags"
|
||||
|
||||
/obj/item/weapon/storage/box/bodybags/New()
|
||||
..()
|
||||
for(var/i in 1 to 7)
|
||||
new /obj/item/bodybag(src)
|
||||
|
||||
|
||||
/obj/structure/closet/body_bag
|
||||
name = "body bag"
|
||||
desc = "A plastic bag designed for the storage and transportation of cadavers."
|
||||
icon = 'icons/obj/bodybag.dmi'
|
||||
icon_state = "bodybag"
|
||||
var/foldedbag_path = /obj/item/bodybag
|
||||
var/tagged = 0 // so closet code knows to put the tag overlay back
|
||||
density = 0
|
||||
mob_storage_capacity = 2
|
||||
open_sound = 'sound/items/zip.ogg'
|
||||
close_sound = 'sound/items/zip.ogg'
|
||||
|
||||
|
||||
/obj/structure/closet/body_bag/attackby(obj/item/I, mob/user, params)
|
||||
if (istype(I, /obj/item/weapon/pen) || istype(I, /obj/item/toy/crayon))
|
||||
var/t = stripped_input(user, "What would you like the label to be?", name, null, 53)
|
||||
if(user.get_active_hand() != I)
|
||||
return
|
||||
if(!in_range(src, user) && loc != user)
|
||||
return
|
||||
if(t)
|
||||
name = "body bag - [t]"
|
||||
tagged = 1
|
||||
update_icon()
|
||||
else
|
||||
name = "body bag"
|
||||
return
|
||||
else if(istype(I, /obj/item/weapon/wirecutters))
|
||||
user << "<span class='notice'>You cut the tag off [src].</span>"
|
||||
name = "body bag"
|
||||
tagged = 0
|
||||
update_icon()
|
||||
|
||||
/obj/structure/closet/body_bag/update_icon()
|
||||
..()
|
||||
if (tagged)
|
||||
add_overlay("bodybag_label")
|
||||
|
||||
/obj/structure/closet/body_bag/close()
|
||||
if(..())
|
||||
density = 0
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/obj/structure/closet/body_bag/MouseDrop(over_object, src_location, over_location)
|
||||
..()
|
||||
if(over_object == usr && Adjacent(usr) && (in_range(src, usr) || usr.contents.Find(src)))
|
||||
if(!ishuman(usr))
|
||||
return 0
|
||||
if(opened)
|
||||
return 0
|
||||
if(contents.len)
|
||||
return 0
|
||||
visible_message("<span class='notice'>[usr] folds up [src].</span>")
|
||||
var/obj/item/bodybag/B = new foldedbag_path(get_turf(src))
|
||||
usr.put_in_hands(B)
|
||||
qdel(src)
|
||||
|
||||
|
||||
// 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 = 2
|
||||
origin_tech = "bluespace=4;materials=4;plasmatech=4"
|
||||
|
||||
/obj/structure/closet/body_bag/bluespace
|
||||
name = "bluespace body bag"
|
||||
desc = "A bluespace body bag designed for the storage and transportation of cadavers."
|
||||
icon = 'icons/obj/bodybag.dmi'
|
||||
icon_state = "bluebodybag"
|
||||
foldedbag_path = /obj/item/bodybag/bluespace
|
||||
density = 0
|
||||
mob_storage_capacity = 15
|
||||
max_mob_size = MOB_SIZE_LARGE
|
||||
@@ -0,0 +1,117 @@
|
||||
#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 = 1
|
||||
var/wax = 200
|
||||
var/lit = FALSE
|
||||
var/infinite = FALSE
|
||||
var/start_lit = FALSE
|
||||
heat = 1000
|
||||
|
||||
/obj/item/candle/New()
|
||||
..()
|
||||
if(start_lit)
|
||||
// No visible message
|
||||
light(show_message = FALSE)
|
||||
|
||||
/obj/item/candle/update_icon()
|
||||
var/i
|
||||
if(wax>150)
|
||||
i = 1
|
||||
else if(wax>80)
|
||||
i = 2
|
||||
else i = 3
|
||||
icon_state = "candle[i][lit ? "_lit" : ""]"
|
||||
|
||||
|
||||
/obj/item/candle/attackby(obj/item/weapon/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.isOn()) //Badasses dont get blinded by lighting their candle with a welding tool
|
||||
light("<span class='danger'>[user] casually lights the [name] with [W], what a badass.</span>")
|
||||
else if(istype(W, /obj/item/weapon/lighter))
|
||||
var/obj/item/weapon/lighter/L = W
|
||||
if(L.lit)
|
||||
light()
|
||||
else if(istype(W, /obj/item/weapon/match))
|
||||
var/obj/item/weapon/match/M = W
|
||||
if(M.lit)
|
||||
light()
|
||||
else if(istype(W, /obj/item/candle))
|
||||
var/obj/item/candle/C = W
|
||||
if(C.lit)
|
||||
light()
|
||||
else if(istype(W, /obj/item/clothing/mask/cigarette))
|
||||
var/obj/item/clothing/mask/cigarette/M = W
|
||||
if(M.lit)
|
||||
light()
|
||||
|
||||
/obj/item/candle/fire_act()
|
||||
if(!src.lit)
|
||||
light() //honk
|
||||
return
|
||||
|
||||
/obj/item/candle/proc/light(show_message)
|
||||
if(!src.lit)
|
||||
src.lit = TRUE
|
||||
//src.damtype = "fire"
|
||||
if(show_message)
|
||||
usr.visible_message(
|
||||
"<span class='danger'>[usr] lights the [name].</span>")
|
||||
SetLuminosity(CANDLE_LUMINOSITY)
|
||||
START_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/candle/process()
|
||||
if(!lit)
|
||||
return
|
||||
if(!infinite)
|
||||
wax--
|
||||
if(!wax)
|
||||
new/obj/item/trash/candle(src.loc)
|
||||
if(istype(src.loc, /mob))
|
||||
var/mob/M = src.loc
|
||||
M.unEquip(src, 1) //src is being deleted anyway
|
||||
qdel(src)
|
||||
update_icon()
|
||||
open_flame()
|
||||
|
||||
/obj/item/candle/attack_self(mob/user)
|
||||
if(lit)
|
||||
user.visible_message(
|
||||
"<span class='notice'>[user] snuffs [src].</span>")
|
||||
lit = FALSE
|
||||
update_icon()
|
||||
SetLuminosity(0)
|
||||
user.AddLuminosity(-CANDLE_LUMINOSITY)
|
||||
|
||||
|
||||
/obj/item/candle/pickup(mob/user)
|
||||
..()
|
||||
if(lit)
|
||||
SetLuminosity(0)
|
||||
user.AddLuminosity(CANDLE_LUMINOSITY)
|
||||
|
||||
|
||||
/obj/item/candle/dropped(mob/user)
|
||||
..()
|
||||
if(lit)
|
||||
user.AddLuminosity(-CANDLE_LUMINOSITY)
|
||||
SetLuminosity(CANDLE_LUMINOSITY)
|
||||
|
||||
/obj/item/candle/is_hot()
|
||||
return lit * heat
|
||||
|
||||
|
||||
/obj/item/candle/infinite
|
||||
infinite = TRUE
|
||||
start_lit = TRUE
|
||||
|
||||
#undef CANDLE_LUMINOSITY
|
||||
@@ -0,0 +1,129 @@
|
||||
//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 = 4
|
||||
var/list/possible_appearances = list("Assistant", "Clown", "Mime", "Traitor", "Nuke Op", "Cultist", "Clockwork Cultist", "Revolutionary", "Wizard", "Shadowling", "Xenomorph", "Swarmer", \
|
||||
"Ash Walker", "Deathsquad Officer", "Ian") //Possible restyles for the cutout; add an entry in change_appearance() if you add to here
|
||||
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
|
||||
|
||||
/obj/item/cardboard_cutout/attack_hand(mob/living/user)
|
||||
if(user.a_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)
|
||||
name = initial(name)
|
||||
desc = "[initial(desc)] It's been pushed over."
|
||||
icon_state = "cutout_pushed_over"
|
||||
color = initial(color)
|
||||
pushed_over = TRUE
|
||||
|
||||
/obj/item/cardboard_cutout/attack_self(mob/living/user)
|
||||
if(!pushed_over)
|
||||
return
|
||||
user << "<span class='notice'>You right [src].</span>"
|
||||
desc = initial(desc)
|
||||
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)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/cardboard_cutout/bullet_act(obj/item/projectile/P)
|
||||
visible_message("<span class='danger'>[src] has been hit by [P]!</span>")
|
||||
playsound(src, 'sound/weapons/slice.ogg', 50, 1)
|
||||
if(prob(P.damage))
|
||||
name = initial(name)
|
||||
desc = "[initial(desc)] It's been pushed over."
|
||||
icon_state = "cutout_pushed_over"
|
||||
color = initial(color)
|
||||
pushed_over = TRUE
|
||||
|
||||
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
|
||||
if(!crayon || !user)
|
||||
return
|
||||
if(pushed_over)
|
||||
user << "<span class='warning'>Right [src] 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
|
||||
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
|
||||
if(!deceptive)
|
||||
color = "#FFD7A7"
|
||||
switch(new_appearance)
|
||||
if("Assistant")
|
||||
name = "[pick(first_names_male)] [pick(last_names)]"
|
||||
desc = "A cardboat cutout of an assistant."
|
||||
icon_state = "cutout_greytide"
|
||||
if("Clown")
|
||||
name = pick(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(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(first_names_male)] [pick(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(wizard_first)], [pick(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("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(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"
|
||||
return 1
|
||||
|
||||
/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,93 @@
|
||||
/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/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/New()
|
||||
. = ..()
|
||||
if(!standard_station_regex)
|
||||
var/prefixes = jointext(station_prefixes, "|")
|
||||
var/names = jointext(station_names, "|")
|
||||
var/suffixes = jointext(station_suffixes, "|")
|
||||
var/numerals = jointext(station_numerals, "|")
|
||||
var/regexstr = "(([prefixes]) )?(([names]) ?)([suffixes]) ([numerals])"
|
||||
standard_station_regex = new(regexstr)
|
||||
|
||||
/obj/item/station_charter/Destroy()
|
||||
if(response_timer_id)
|
||||
deltimer(response_timer_id)
|
||||
response_timer_id = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/station_charter/attack_self(mob/living/user)
|
||||
if(used)
|
||||
user << "This charter has already been used to name the station."
|
||||
return
|
||||
if(!ignores_timeout && (world.time-round_start_time > CHALLENGE_TIME_LIMIT)) //5 minutes
|
||||
user << "The crew has already settled into the shift. \
|
||||
It probably wouldn't be good to rename the station right now."
|
||||
return
|
||||
if(response_timer_id)
|
||||
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 = 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(!new_name)
|
||||
return
|
||||
log_game("[key_name(user)] has proposed to name the station as \
|
||||
[new_name]")
|
||||
|
||||
if(standard_station_regex.Find(new_name))
|
||||
user << "Your name has been automatically approved."
|
||||
rename_station(new_name, user)
|
||||
return
|
||||
|
||||
user << "Your name has been sent to your employers for approval."
|
||||
// Autoapproves after a certain time
|
||||
response_timer_id = addtimer(src, "rename_station", approval_time, \
|
||||
FALSE, new_name, user)
|
||||
admins << "<span class='adminnotice'><b><font color=orange>CUSTOM STATION RENAME:</font></b>[key_name_admin(user)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) proposes to rename the station to [new_name] (will autoapprove in [approval_time / 10] seconds). (<A HREF='?_src_=holder;BlueSpaceArtillery=\ref[user]'>BSA</A>) (<A HREF='?_src_=holder;reject_custom_name=\ref[src]'>REJECT</A>)</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, mob/user)
|
||||
world.name = designation
|
||||
station_name = designation
|
||||
minor_announce("[user.real_name] has designated your station as [world.name]", "Captain's Charter", 0)
|
||||
log_game("[key_name(user)] has renamed the station as [world.name]")
|
||||
|
||||
name = "station charter for [world.name]"
|
||||
desc = "An official document entrusting the governance of \
|
||||
[world.name] and surrounding space to Captain [user]."
|
||||
|
||||
if(!unlimited_uses)
|
||||
used = TRUE
|
||||
@@ -0,0 +1,104 @@
|
||||
#define WAND_OPEN "Open Door"
|
||||
#define WAND_BOLT "Toggle Bolts"
|
||||
#define WAND_EMERGENCY "Toggle Emergency Access"
|
||||
|
||||
/obj/item/weapon/door_remote
|
||||
icon_state = "gangtool-white"
|
||||
item_state = "electronic"
|
||||
icon = 'icons/obj/device.dmi'
|
||||
name = "control wand"
|
||||
desc = "Remotely controls airlocks."
|
||||
w_class = 1
|
||||
var/mode = WAND_OPEN
|
||||
var/region_access = 1 //See access.dm
|
||||
var/obj/item/weapon/card/id/ID
|
||||
|
||||
/obj/item/weapon/door_remote/New()
|
||||
..()
|
||||
ID = new /obj/item/weapon/card/id
|
||||
ID.access = get_region_accesses(region_access)
|
||||
|
||||
/obj/item/weapon/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
|
||||
user << "Now in mode: [mode]."
|
||||
|
||||
/obj/item/weapon/door_remote/afterattack(obj/machinery/door/airlock/D, mob/user)
|
||||
if(!istype(D))
|
||||
return
|
||||
if(!(D.hasPower()))
|
||||
user << "<span class='danger'>[D] has no power!</span>"
|
||||
return
|
||||
if(!D.requiresID())
|
||||
user << "<span class='danger'>[D]'s ID scan is disabled!</span>"
|
||||
return
|
||||
if(D.check_access(ID) && D.canAIControl(user))
|
||||
switch(mode)
|
||||
if(WAND_OPEN)
|
||||
if(D.density)
|
||||
D.open()
|
||||
else
|
||||
D.close()
|
||||
if(WAND_BOLT)
|
||||
if(D.locked)
|
||||
D.unbolt()
|
||||
else
|
||||
D.bolt()
|
||||
if(WAND_EMERGENCY)
|
||||
if(D.emergency)
|
||||
D.emergency = 0
|
||||
else
|
||||
D.emergency = 1
|
||||
D.update_icon()
|
||||
else
|
||||
user << "<span class='danger'>[src] does not have access to this door.</span>"
|
||||
|
||||
/obj/item/weapon/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/weapon/door_remote/captain
|
||||
name = "command door remote"
|
||||
icon_state = "gangtool-yellow"
|
||||
region_access = 7
|
||||
|
||||
/obj/item/weapon/door_remote/chief_engineer
|
||||
name = "engineering door remote"
|
||||
icon_state = "gangtool-orange"
|
||||
region_access = 5
|
||||
|
||||
/obj/item/weapon/door_remote/research_director
|
||||
name = "research door remote"
|
||||
icon_state = "gangtool-purple"
|
||||
region_access = 4
|
||||
|
||||
/obj/item/weapon/door_remote/head_of_security
|
||||
name = "security door remote"
|
||||
icon_state = "gangtool-red"
|
||||
region_access = 2
|
||||
|
||||
/obj/item/weapon/door_remote/quartermaster
|
||||
name = "supply door remote"
|
||||
icon_state = "gangtool-green"
|
||||
region_access = 6
|
||||
|
||||
/obj/item/weapon/door_remote/chief_medical_officer
|
||||
name = "medical door remote"
|
||||
icon_state = "gangtool-blue"
|
||||
region_access = 3
|
||||
|
||||
/obj/item/weapon/door_remote/civillian
|
||||
name = "civillian door remote"
|
||||
icon_state = "gangtool-white"
|
||||
region_access = 1
|
||||
|
||||
#undef WAND_OPEN
|
||||
#undef WAND_BOLT
|
||||
#undef WAND_EMERGENCY
|
||||
@@ -0,0 +1,769 @@
|
||||
#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 = 1
|
||||
attack_verb = list("attacked", "coloured")
|
||||
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")
|
||||
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/gang = FALSE //For marking territory
|
||||
|
||||
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
|
||||
|
||||
/obj/item/toy/crayon/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is jamming the [src.name] up \his nose and into \his brain. It looks like \he's trying to commit suicide.</span>")
|
||||
return (BRUTELOSS|OXYLOSS)
|
||||
|
||||
/obj/item/toy/crayon/New()
|
||||
..()
|
||||
// Makes crayons identifiable in things like grinders
|
||||
if(name == "crayon")
|
||||
name = "[item_color] crayon"
|
||||
|
||||
if(config)
|
||||
if(config.mutant_races == 1)
|
||||
graffiti |= "antilizard"
|
||||
graffiti |= "prolizard"
|
||||
|
||||
all_drawables = graffiti + letters + numerals + oriented + runes + graffiti_large_h
|
||||
drawtype = pick(all_drawables)
|
||||
|
||||
refill()
|
||||
|
||||
/obj/item/toy/crayon/Destroy()
|
||||
if(reagents)
|
||||
qdel(reagents)
|
||||
. = ..()
|
||||
|
||||
/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(amount)
|
||||
// Returns number of charges actually used
|
||||
switch(paint_mode)
|
||||
if(PAINT_LARGE_HORIZONTAL)
|
||||
amount *= 3
|
||||
|
||||
if(charges == -1)
|
||||
. = amount
|
||||
refill()
|
||||
else
|
||||
. = min(charges_left, amount)
|
||||
charges_left -= .
|
||||
|
||||
/obj/item/toy/crayon/proc/check_empty(mob/user)
|
||||
// When eating a crayon, check_empty() can be called twice producing
|
||||
// two messages unless we check for being deleted first
|
||||
if(!qdeleted(src))
|
||||
. = TRUE
|
||||
|
||||
. = FALSE
|
||||
// -1 is unlimited charges
|
||||
if(charges == -1)
|
||||
. = FALSE
|
||||
else if(!charges_left)
|
||||
user << "<span class='warning'>There is no more of [src.name] \
|
||||
left!</span>"
|
||||
if(self_contained)
|
||||
qdel(src)
|
||||
. = TRUE
|
||||
|
||||
/obj/item/toy/crayon/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = hands_state)
|
||||
// god bless tgui and all of its arguments
|
||||
|
||||
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(has_cap)
|
||||
is_capped = !is_capped
|
||||
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") as color
|
||||
. = 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 = char_split(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)
|
||||
if(!proximity || !check_allowed_items(target))
|
||||
return
|
||||
|
||||
if(check_empty(user))
|
||||
return
|
||||
|
||||
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.gang_datum)
|
||||
gang_mode = TRUE
|
||||
|
||||
// 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
|
||||
|
||||
user << "<span class='notice'>You start \
|
||||
[instant ? "spraying" : "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
|
||||
if(gang_mode)
|
||||
takes_time = TRUE
|
||||
|
||||
var/wait_time = 50
|
||||
if(PAINT_LARGE_HORIZONTAL)
|
||||
wait_time *= 3
|
||||
|
||||
if(takes_time)
|
||||
if(!do_after(user, 50, target = target))
|
||||
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)
|
||||
else
|
||||
switch(paint_mode)
|
||||
if(PAINT_NORMAL)
|
||||
new /obj/effect/decal/cleanable/crayon(target, paint_color, drawing, temp, graf_rot)
|
||||
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))
|
||||
new /obj/effect/decal/cleanable/crayon(left, paint_color, drawing, temp, graf_rot, PAINT_LARGE_HORIZONTAL_ICON)
|
||||
affected_turfs += left
|
||||
affected_turfs += right
|
||||
affected_turfs += target
|
||||
else
|
||||
user << "<span class='warning'>There isn't enough space to paint!</span>"
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You finish \
|
||||
[instant ? "spraying" : "drawing"] \the [temp].</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/cost = 1
|
||||
if(paint_mode == PAINT_LARGE_HORIZONTAL)
|
||||
cost = 5
|
||||
. = use_charges(cost)
|
||||
var/fraction = min(1, . / reagents.maximum_volume)
|
||||
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)
|
||||
|
||||
/obj/item/toy/crayon/attack(mob/M, mob/user)
|
||||
if(edible && (M == user))
|
||||
user << "You take a bite of the [src.name]. Delicious!"
|
||||
var/eaten = use_charges(5)
|
||||
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/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 || (A.z != ZLEVEL_STATION) || !A.valid_territory)
|
||||
user << "<span class='warning'>[A] is unsuitable for \
|
||||
tagging.</span>"
|
||||
return FALSE
|
||||
|
||||
var/spraying_over = FALSE
|
||||
for(var/obj/effect/decal/cleanable/crayon/gang/G in target)
|
||||
spraying_over = TRUE
|
||||
|
||||
for(var/obj/machinery/power/apc in target)
|
||||
user << "<span class='warning'>You can't tag an APC.</span>"
|
||||
return FALSE
|
||||
|
||||
var/occupying_gang = territory_claimed(A, user)
|
||||
if(occupying_gang && !spraying_over)
|
||||
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 gaunlet of checks, you're good to proceed
|
||||
return TRUE
|
||||
|
||||
/obj/item/toy/crayon/proc/territory_claimed(area/territory, mob/user)
|
||||
for(var/datum/gang/G in ticker.mode.gangs)
|
||||
if(territory.type in (G.territory|G.territory_new))
|
||||
. = 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/gangID = user.mind.gang_datum
|
||||
var/area/territory = get_area(target)
|
||||
|
||||
new /obj/effect/decal/cleanable/crayon/gang(target,gangID,"graffiti",0)
|
||||
user << "<span class='notice'>You tagged [territory] for your gang!</span>"
|
||||
|
||||
/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/white
|
||||
icon_state = "crayonwhite"
|
||||
paint_color = "#FFFFFF"
|
||||
item_color = "white"
|
||||
|
||||
/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/weapon/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 = 2
|
||||
storage_slots = 6
|
||||
can_hold = list(
|
||||
/obj/item/toy/crayon
|
||||
)
|
||||
|
||||
/obj/item/weapon/storage/crayons/New()
|
||||
..()
|
||||
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)
|
||||
update_icon()
|
||||
|
||||
/obj/item/weapon/storage/crayons/update_icon()
|
||||
cut_overlays()
|
||||
for(var/obj/item/toy/crayon/crayon in contents)
|
||||
add_overlay(image('icons/obj/crayons.dmi',crayon.item_color))
|
||||
|
||||
/obj/item/weapon/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")
|
||||
usr << "This crayon is too sad to be contained in this box."
|
||||
return
|
||||
if("rainbow")
|
||||
usr << "This crayon is too powerful to be contained in this \
|
||||
box."
|
||||
return
|
||||
if(istype(W, /obj/item/toy/crayon/spraycan))
|
||||
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"
|
||||
desc = "A metallic container containing tasty paint.\n\
|
||||
Alt-click to toggle the cap."
|
||||
|
||||
instant = TRUE
|
||||
edible = FALSE
|
||||
has_cap = TRUE
|
||||
is_capped = TRUE
|
||||
self_contained = FALSE // Don't disappear when they're empty
|
||||
can_change_colour = TRUE
|
||||
|
||||
validSurfaces = list(/turf/open/floor,/turf/closed/wall)
|
||||
reagent_contents = list("welding_fuel" = 1, "ethanol" = 1)
|
||||
|
||||
/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 the \
|
||||
[src] with a rattle and lifts it to their mouth, but nothing \
|
||||
happens!</span>")
|
||||
user.say("MEDIOCRE!!")
|
||||
return SHAME
|
||||
else
|
||||
user.visible_message("<span class='suicide'>[user] shakes up the \
|
||||
[src] with a rattle and lifts it to their mouth, spraying \
|
||||
paint across their teeth!</span>")
|
||||
user.say("WITNESS ME!!")
|
||||
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(10)
|
||||
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)
|
||||
user << "It has [charges_left] uses left."
|
||||
else
|
||||
user << "It is empty."
|
||||
|
||||
/obj/item/toy/crayon/spraycan/afterattack(atom/target, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
|
||||
if(is_capped)
|
||||
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', 5, 1, 5)
|
||||
|
||||
var/mob/living/carbon/C = target
|
||||
user.visible_message("<span class='danger'>[user] sprays [src] \
|
||||
into the face of [target]!</span>")
|
||||
target << "<span class='userdanger'>[user] sprays [src] into your \
|
||||
face!</span>"
|
||||
|
||||
if(C.client)
|
||||
C.blur_eyes(3)
|
||||
C.blind_eyes(1)
|
||||
if(C.check_eye_prot() <= 0) // no eye protection? ARGH IT BURNS.
|
||||
C.confused = max(C.confused, 3)
|
||||
C.Weaken(3)
|
||||
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(10)
|
||||
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.color = paint_color
|
||||
if(color_hex2num(paint_color) < 255)
|
||||
target.SetOpacity(255)
|
||||
else
|
||||
target.SetOpacity(initial(target.opacity))
|
||||
. = use_charges(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/image/I = image('icons/obj/crayons.dmi',
|
||||
icon_state = "[is_capped ? "spraycan_cap_colors" : "spraycan_colors"]")
|
||||
I.color = paint_color
|
||||
add_overlay(I)
|
||||
|
||||
/obj/item/toy/crayon/spraycan/gang
|
||||
//desc = "A modified container containing suspicious paint."
|
||||
charges = 20
|
||||
gang = TRUE
|
||||
|
||||
pre_noise = FALSE
|
||||
post_noise = TRUE
|
||||
|
||||
/obj/item/toy/crayon/spraycan/gang/New(loc, datum/gang/G)
|
||||
..()
|
||||
if(G)
|
||||
paint_color = G.color_hex
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/crayon/spraycan/gang/examine(mob/user)
|
||||
. = ..()
|
||||
if((user.mind && user.mind.gang_datum) || isobserver(user))
|
||||
user << "This spraycan has \
|
||||
been specially modified for tagging territory."
|
||||
|
||||
/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(!isrobot(user))
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
can_change_colour = FALSE
|
||||
paint_color = "#FFFFFF" //RGB
|
||||
|
||||
pre_noise = FALSE
|
||||
post_noise = FALSE
|
||||
reagent_contents = list("nothing" = 1, "mutetoxin" = 1)
|
||||
|
||||
#undef RANDOM_GRAFFITI
|
||||
#undef RANDOM_LETTER
|
||||
#undef RANDOM_NUMBER
|
||||
#undef RANDOM_ORIENTED
|
||||
#undef RANDOM_RUNE
|
||||
#undef RANDOM_ANY
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Dehydrated Carp
|
||||
* Instant carp, just add water
|
||||
*/
|
||||
|
||||
//Child of carpplushie because this should do everything the toy does and more
|
||||
/obj/item/toy/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/carpplushie/dehy_carp/attack_self(mob/user)
|
||||
src.add_fingerprint(user) //Anyone can add their fingerprints to it with this
|
||||
if(!owned)
|
||||
user << "<span class='notice'>You pet [src]. You swear it looks up at you.</span>"
|
||||
owner = user
|
||||
owned = 1
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/toy/carpplushie/dehy_carp/afterattack(obj/O, mob/user,proximity)
|
||||
if(!proximity) return
|
||||
if(istype(O,/obj/structure/sink))
|
||||
user.drop_item()
|
||||
loc = get_turf(O)
|
||||
return Swell()
|
||||
..()
|
||||
|
||||
/obj/item/toy/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)
|
||||
//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)
|
||||
@@ -0,0 +1,991 @@
|
||||
|
||||
//The advanced pea-green monochrome lcd of tomorrow.
|
||||
|
||||
var/global/list/obj/item/device/pda/PDAs = list()
|
||||
|
||||
|
||||
/obj/item/device/pda
|
||||
name = "\improper PDA"
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge."
|
||||
icon = 'icons/obj/pda.dmi'
|
||||
icon_state = "pda"
|
||||
item_state = "electronic"
|
||||
flags = NOBLUDGEON
|
||||
w_class = 1
|
||||
slot_flags = SLOT_ID | SLOT_BELT
|
||||
origin_tech = "programming=2"
|
||||
|
||||
//Main variables
|
||||
var/owner = null // String name of owner
|
||||
var/default_cartridge = 0 // Access level defined by cartridge
|
||||
var/obj/item/weapon/cartridge/cartridge = null //current cartridge
|
||||
var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge.
|
||||
var/icon_alert = "pda-r" //Icon to be overlayed for message alerts. Taken from the pda icon file.
|
||||
|
||||
//Secondary variables
|
||||
var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner.
|
||||
var/fon = 0 //Is the flashlight function on?
|
||||
var/f_lum = 3 //Luminosity for the flashlight function
|
||||
var/silent = 0 //To beep or not to beep, that is the question
|
||||
var/toff = 0 //If 1, messenger disabled
|
||||
var/tnote = null //Current Texts
|
||||
var/last_text //No text spamming
|
||||
var/last_noise //Also no honk spamming that's bad too
|
||||
var/ttone = "beep" //The ringtone!
|
||||
var/lock_code = "" // Lockcode to unlock uplink
|
||||
var/honkamt = 0 //How many honks left when infected with honk.exe
|
||||
var/mimeamt = 0 //How many silence left when infected with mime.exe
|
||||
var/note = "Congratulations, your station has chosen the Thinktronic 5230 Personal Data Assistant!" //Current note in the notepad function
|
||||
var/notehtml = ""
|
||||
var/notescanned = 0 // True if what is in the notekeeper was from a paper.
|
||||
var/cart = "" //A place to stick cartridge menu information
|
||||
var/detonate = 1 // Can the PDA be blown up?
|
||||
var/hidden = 0 // Is the PDA hidden from the PDA list?
|
||||
var/emped = 0
|
||||
|
||||
var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both.
|
||||
var/ownjob = null //related to above
|
||||
|
||||
var/obj/item/device/paicard/pai = null // A slot for a personal AI device
|
||||
|
||||
var/image/photo = null //Scanned photo
|
||||
|
||||
|
||||
/obj/item/device/pda/pickup(mob/user)
|
||||
..()
|
||||
if(fon)
|
||||
SetLuminosity(0)
|
||||
user.AddLuminosity(f_lum)
|
||||
|
||||
/obj/item/device/pda/dropped(mob/user)
|
||||
..()
|
||||
if(fon)
|
||||
user.AddLuminosity(-f_lum)
|
||||
SetLuminosity(f_lum)
|
||||
|
||||
/obj/item/device/pda/New()
|
||||
..()
|
||||
if(fon)
|
||||
if(!isturf(loc))
|
||||
loc.AddLuminosity(f_lum)
|
||||
SetLuminosity(0)
|
||||
else
|
||||
SetLuminosity(f_lum)
|
||||
PDAs += src
|
||||
if(default_cartridge)
|
||||
cartridge = new default_cartridge(src)
|
||||
new /obj/item/weapon/pen(src)
|
||||
|
||||
/obj/item/device/pda/proc/update_label()
|
||||
name = "PDA-[owner] ([ownjob])" //Name generalisation
|
||||
|
||||
/obj/item/device/pda/GetAccess()
|
||||
if(id)
|
||||
return id.GetAccess()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/pda/GetID()
|
||||
return id
|
||||
|
||||
/obj/item/device/pda/MouseDrop(obj/over_object, src_location, over_location)
|
||||
var/mob/M = usr
|
||||
if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src))
|
||||
return attack_self(M)
|
||||
return
|
||||
|
||||
/obj/item/device/pda/attack_self(mob/user)
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/pda)
|
||||
assets.send(user)
|
||||
|
||||
user.set_machine(src)
|
||||
|
||||
if(hidden_uplink && hidden_uplink.active)
|
||||
hidden_uplink.interact(user)
|
||||
return
|
||||
|
||||
var/dat = "<html><head><title>Personal Data Assistant</title></head><body bgcolor=\"#808000\"><style>a, a:link, a:visited, a:active, a:hover { color: #000000; }img {border-style:none;}</style>"
|
||||
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Refresh'><img src=pda_refresh.png> Refresh</a>"
|
||||
|
||||
if ((!isnull(cartridge)) && (mode == 0))
|
||||
dat += " | <a href='byond://?src=\ref[src];choice=Eject'><img src=pda_eject.png> Eject [cartridge]</a>"
|
||||
if (mode)
|
||||
dat += " | <a href='byond://?src=\ref[src];choice=Return'><img src=pda_menu.png> Return</a>"
|
||||
|
||||
dat += "<br>"
|
||||
|
||||
if (!owner)
|
||||
dat += "Warning: No owner information entered. Please swipe card.<br><br>"
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Refresh'><img src=pda_refresh.png> Retry</a>"
|
||||
else
|
||||
switch (mode)
|
||||
if (0)
|
||||
dat += "<h2>PERSONAL DATA ASSISTANT v.1.2</h2>"
|
||||
dat += "Owner: [owner], [ownjob]<br>"
|
||||
dat += text("ID: <A href='?src=\ref[src];choice=Authenticate'>[id ? "[id.registered_name], [id.assignment]" : "----------"]")
|
||||
dat += text("<br><A href='?src=\ref[src];choice=UpdateInfo'>[id ? "Update PDA Info" : ""]</A><br><br>")
|
||||
|
||||
dat += "[worldtime2text()]<br>" //:[world.time / 100 % 6][world.time / 100 % 10]"
|
||||
dat += "[time2text(world.realtime, "MMM DD")] [year_integer+540]"
|
||||
|
||||
dat += "<br><br>"
|
||||
|
||||
dat += "<h4>General Functions</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=1'><img src=pda_notes.png> Notekeeper</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=2'><img src=pda_mail.png> Messenger</a></li>"
|
||||
|
||||
if (cartridge)
|
||||
if (cartridge.access_clown)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Honk'><img src=pda_honk.png> Honk Synthesizer</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Trombone'><img src=pda_honk.png> Sad Trombone</a></li>"
|
||||
if (cartridge.access_manifest)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=41'><img src=pda_notes.png> View Crew Manifest</a></li>"
|
||||
if(cartridge.access_status_display)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=42'><img src=pda_status.png> Set Status Display</a></li>"
|
||||
dat += "</ul>"
|
||||
if (cartridge.access_engine)
|
||||
dat += "<h4>Engineering Functions</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=43'><img src=pda_power.png> Power Monitor</a></li>"
|
||||
dat += "</ul>"
|
||||
if (cartridge.access_medical)
|
||||
dat += "<h4>Medical Functions</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=44'><img src=pda_medical.png> Medical Records</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Medical Scan'><img src=pda_scanner.png> [scanmode == 1 ? "Disable" : "Enable"] Medical Scanner</a></li>"
|
||||
dat += "</ul>"
|
||||
if (cartridge.access_security)
|
||||
dat += "<h4>Security Functions</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=45'><img src=pda_cuffs.png> Security Records</A></li>"
|
||||
dat += "</ul>"
|
||||
if(cartridge.access_quartermaster)
|
||||
dat += "<h4>Quartermaster Functions:</h4>"
|
||||
dat += "<ul>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=47'><img src=pda_crate.png> Supply Records</A></li>"
|
||||
dat += "</ul>"
|
||||
dat += "</ul>"
|
||||
|
||||
dat += "<h4>Utilities</h4>"
|
||||
dat += "<ul>"
|
||||
if (cartridge)
|
||||
if(cartridge.bot_access_flags)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=54'><img src=pda_medbot.png> Bots Access</a></li>"
|
||||
if (cartridge.access_janitor)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=49'><img src=pda_bucket.png> Custodial Locator</a></li>"
|
||||
if (istype(cartridge.radio, /obj/item/radio/integrated/signal))
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=40'><img src=pda_signaler.png> Signaler System</a></li>"
|
||||
if (cartridge.access_newscaster)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=53'><img src=pda_notes.png> Newscaster Access </a></li>"
|
||||
if (cartridge.access_reagent_scanner)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Reagent Scan'><img src=pda_reagent.png> [scanmode == 3 ? "Disable" : "Enable"] Reagent Scanner</a></li>"
|
||||
if (cartridge.access_engine)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Halogen Counter'><img src=pda_reagent.png> [scanmode == 4 ? "Disable" : "Enable"] Halogen Counter</a></li>"
|
||||
if (cartridge.access_atmos)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Gas Scan'><img src=pda_reagent.png> [scanmode == 5 ? "Disable" : "Enable"] Gas Scanner</a></li>"
|
||||
if (cartridge.access_remote_door)
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Toggle Door'><img src=pda_rdoor.png> Toggle Remote Door</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=3'><img src=pda_atmos.png> Atmospheric Scan</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Light'><img src=pda_flashlight.png> [fon ? "Disable" : "Enable"] Flashlight</a></li>"
|
||||
if (pai)
|
||||
if(pai.loc != src)
|
||||
pai = null
|
||||
else
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=pai;option=1'>pAI Device Configuration</a></li>"
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=pai;option=2'>Eject pAI Device</a></li>"
|
||||
dat += "</ul>"
|
||||
|
||||
if (1)
|
||||
dat += "<h4><img src=pda_notes.png> Notekeeper V2.2</h4>"
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Edit'>Edit</a><br>"
|
||||
if(notescanned)
|
||||
dat += "(This is a scanned image, editing it may cause some text formatting to change.)<br>"
|
||||
dat += "<HR><font face=\"[PEN_FONT]\">[(!notehtml ? note : notehtml)]</font>"
|
||||
|
||||
if (2)
|
||||
dat += "<h4><img src=pda_mail.png> SpaceMessenger V3.9.6</h4>"
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Toggle Ringer'><img src=pda_bell.png> Ringer: [silent == 1 ? "Off" : "On"]</a> | "
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Toggle Messenger'><img src=pda_mail.png> Send / Receive: [toff == 1 ? "Off" : "On"]</a> | "
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Ringtone'><img src=pda_bell.png> Set Ringtone</a> | "
|
||||
dat += "<a href='byond://?src=\ref[src];choice=21'><img src=pda_mail.png> Messages</a><br>"
|
||||
|
||||
if (istype(cartridge, /obj/item/weapon/cartridge/syndicate))
|
||||
dat += "<b>[cartridge:shock_charges] detonation charges left.</b><HR>"
|
||||
if (istype(cartridge, /obj/item/weapon/cartridge/clown))
|
||||
dat += "<b>[cartridge:honk_charges] viral files left.</b><HR>"
|
||||
if (istype(cartridge, /obj/item/weapon/cartridge/mime))
|
||||
dat += "<b>[cartridge:mime_charges] viral files left.</b><HR>"
|
||||
|
||||
dat += "<h4><img src=pda_menu.png> Detected PDAs</h4>"
|
||||
|
||||
dat += "<ul>"
|
||||
var/count = 0
|
||||
|
||||
if (!toff)
|
||||
for (var/obj/item/device/pda/P in sortNames(get_viewable_pdas()))
|
||||
if (P == src)
|
||||
continue
|
||||
dat += "<li><a href='byond://?src=\ref[src];choice=Message;target=\ref[P]'>[P]</a>"
|
||||
if (istype(cartridge, /obj/item/weapon/cartridge/syndicate) && P.detonate)
|
||||
dat += " (<a href='byond://?src=\ref[src];choice=Detonate;target=\ref[P]'><img src=pda_boom.png>*Detonate*</a>)"
|
||||
if (istype(cartridge, /obj/item/weapon/cartridge/clown))
|
||||
dat += " (<a href='byond://?src=\ref[src];choice=Send Honk;target=\ref[P]'><img src=pda_honk.png>*Send Virus*</a>)"
|
||||
if (istype(cartridge, /obj/item/weapon/cartridge/mime))
|
||||
dat += " (<a href='byond://?src=\ref[src];choice=Send Silence;target=\ref[P]'>*Send Virus*</a>)"
|
||||
dat += "</li>"
|
||||
count++
|
||||
dat += "</ul>"
|
||||
if (count == 0)
|
||||
dat += "None detected.<br>"
|
||||
else if(cartridge && cartridge.spam_enabled)
|
||||
dat += "<a href='byond://?src=\ref[src];choice=MessageAll'>Send To All</a>"
|
||||
|
||||
if(21)
|
||||
dat += "<h4><img src=pda_mail.png> SpaceMessenger V3.9.6</h4>"
|
||||
dat += "<a href='byond://?src=\ref[src];choice=Clear'><img src=pda_blank.png> Clear Messages</a>"
|
||||
|
||||
dat += "<h4><img src=pda_mail.png> Messages</h4>"
|
||||
|
||||
dat += tnote
|
||||
dat += "<br>"
|
||||
|
||||
if (3)
|
||||
dat += "<h4><img src=pda_atmos.png> Atmospheric Readings</h4>"
|
||||
|
||||
var/turf/T = user.loc
|
||||
if (isnull(T))
|
||||
dat += "Unable to obtain a reading.<br>"
|
||||
else
|
||||
var/datum/gas_mixture/environment = T.return_air()
|
||||
var/list/env_gases = environment.gases
|
||||
|
||||
var/pressure = environment.return_pressure()
|
||||
var/total_moles = environment.total_moles()
|
||||
|
||||
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
|
||||
|
||||
if (total_moles)
|
||||
for(var/id in env_gases)
|
||||
var/gas_level = env_gases[id][MOLES]/total_moles
|
||||
if(gas_level > 0)
|
||||
dat += "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_level*100, 0.01)]%<br>"
|
||||
|
||||
dat += "Temperature: [round(environment.temperature-T0C)]°C<br>"
|
||||
dat += "<br>"
|
||||
|
||||
else//Else it links to the cart menu proc. Although, it really uses menu hub 4--menu 4 doesn't really exist as it simply redirects to hub.
|
||||
dat += cart
|
||||
|
||||
dat += "</body></html>"
|
||||
user << browse(dat, "window=pda;size=400x450;border=1;can_resize=1;can_minimize=0")
|
||||
onclose(user, "pda", src)
|
||||
|
||||
/obj/item/device/pda/Topic(href, href_list)
|
||||
..()
|
||||
var/mob/living/U = usr
|
||||
//Looking for master was kind of pointless since PDAs don't appear to have one.
|
||||
|
||||
if(usr.canUseTopic(src) && !href_list["close"])
|
||||
add_fingerprint(U)
|
||||
U.set_machine(src)
|
||||
|
||||
switch(href_list["choice"])
|
||||
|
||||
//BASIC FUNCTIONS===================================
|
||||
|
||||
if("Refresh")//Refresh, goes to the end of the proc.
|
||||
if("Return")//Return
|
||||
if(mode<=9)
|
||||
mode = 0
|
||||
else
|
||||
mode = round(mode/10)
|
||||
if(mode==4 || mode == 5)//Fix for cartridges. Redirects to hub.
|
||||
mode = 0
|
||||
else if(mode >= 40 && mode <= 59)//Fix for cartridges. Redirects to refresh the menu.
|
||||
cartridge.mode = mode
|
||||
cartridge.unlock()
|
||||
if ("Authenticate")//Checks for ID
|
||||
id_check(U, 1)
|
||||
if("UpdateInfo")
|
||||
ownjob = id.assignment
|
||||
update_label()
|
||||
if("Eject")//Ejects the cart, only done from hub.
|
||||
if (!isnull(cartridge))
|
||||
var/turf/T = loc
|
||||
if(ismob(T))
|
||||
T = T.loc
|
||||
cartridge.loc = T
|
||||
scanmode = 0
|
||||
if (cartridge.radio)
|
||||
cartridge.radio.hostpda = null
|
||||
cartridge = null
|
||||
|
||||
//MENU FUNCTIONS===================================
|
||||
|
||||
if("0")//Hub
|
||||
mode = 0
|
||||
if("1")//Notes
|
||||
mode = 1
|
||||
if("2")//Messenger
|
||||
mode = 2
|
||||
if("21")//Read messeges
|
||||
mode = 21
|
||||
if("3")//Atmos scan
|
||||
mode = 3
|
||||
if("4")//Redirects to hub
|
||||
mode = 0
|
||||
|
||||
|
||||
//MAIN FUNCTIONS===================================
|
||||
|
||||
if("Light")
|
||||
if(fon)
|
||||
fon = 0
|
||||
if(src in U.contents)
|
||||
U.AddLuminosity(-f_lum)
|
||||
else
|
||||
SetLuminosity(0)
|
||||
else
|
||||
fon = 1
|
||||
if(src in U.contents)
|
||||
U.AddLuminosity(f_lum)
|
||||
else
|
||||
SetLuminosity(f_lum)
|
||||
if("Medical Scan")
|
||||
if(scanmode == 1)
|
||||
scanmode = 0
|
||||
else if((!isnull(cartridge)) && (cartridge.access_medical))
|
||||
scanmode = 1
|
||||
if("Reagent Scan")
|
||||
if(scanmode == 3)
|
||||
scanmode = 0
|
||||
else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner))
|
||||
scanmode = 3
|
||||
if("Halogen Counter")
|
||||
if(scanmode == 4)
|
||||
scanmode = 0
|
||||
else if((!isnull(cartridge)) && (cartridge.access_engine))
|
||||
scanmode = 4
|
||||
if("Honk")
|
||||
if ( !(last_noise && world.time < last_noise + 20) )
|
||||
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1)
|
||||
last_noise = world.time
|
||||
if("Trombone")
|
||||
if ( !(last_noise && world.time < last_noise + 20) )
|
||||
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, 1)
|
||||
last_noise = world.time
|
||||
if("Gas Scan")
|
||||
if(scanmode == 5)
|
||||
scanmode = 0
|
||||
else if((!isnull(cartridge)) && (cartridge.access_atmos))
|
||||
scanmode = 5
|
||||
|
||||
//NOTEKEEPER FUNCTIONS===================================
|
||||
|
||||
if ("Edit")
|
||||
var/n = stripped_multiline_input(U, "Please enter message", name, note)
|
||||
if (in_range(src, U) && loc == U)
|
||||
if (mode == 1 && n)
|
||||
note = n
|
||||
notehtml = parsepencode(n, U, SIGNFONT)
|
||||
notescanned = 0
|
||||
else
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
//MESSENGER FUNCTIONS===================================
|
||||
|
||||
if("Toggle Messenger")
|
||||
toff = !toff
|
||||
if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status
|
||||
silent = !silent
|
||||
if("Clear")//Clears messages
|
||||
tnote = null
|
||||
if("Ringtone")
|
||||
var/t = input(U, "Please enter new ringtone", name, ttone) as text
|
||||
if(in_range(src, U) && loc == U)
|
||||
if(t)
|
||||
if(hidden_uplink && (trim(lowertext(t)) == trim(lowertext(lock_code))))
|
||||
hidden_uplink.interact(U)
|
||||
U << "The PDA softly beeps."
|
||||
U << browse(null, "window=pda")
|
||||
src.mode = 0
|
||||
else
|
||||
t = copytext(sanitize(t), 1, 20)
|
||||
ttone = t
|
||||
else
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
if("Message")
|
||||
var/obj/item/device/pda/P = locate(href_list["target"])
|
||||
src.create_message(U, P)
|
||||
|
||||
if("MessageAll")
|
||||
src.send_to_all(U)
|
||||
|
||||
if("Send Honk")//Honk virus
|
||||
if(istype(cartridge, /obj/item/weapon/cartridge/clown))//Cartridge checks are kind of unnecessary since everything is done through switch.
|
||||
var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess.
|
||||
if(!isnull(P))
|
||||
if (!P.toff && cartridge:honk_charges > 0)
|
||||
cartridge:honk_charges--
|
||||
U.show_message("<span class='notice'>Virus sent!</span>", 1)
|
||||
P.honkamt = (rand(15,20))
|
||||
else
|
||||
U << "PDA not found."
|
||||
else
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
if("Send Silence")//Silent virus
|
||||
if(istype(cartridge, /obj/item/weapon/cartridge/mime))
|
||||
var/obj/item/device/pda/P = locate(href_list["target"])
|
||||
if(!isnull(P))
|
||||
if (!P.toff && cartridge:mime_charges > 0)
|
||||
cartridge:mime_charges--
|
||||
U.show_message("<span class='notice'>Virus sent!</span>", 1)
|
||||
P.silent = 1
|
||||
P.ttone = "silence"
|
||||
else
|
||||
U << "PDA not found."
|
||||
else
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
//SYNDICATE FUNCTIONS===================================
|
||||
|
||||
if("Toggle Door")
|
||||
if(cartridge && cartridge.access_remote_door)
|
||||
for(var/obj/machinery/door/poddoor/M in machines)
|
||||
if(M.id == cartridge.remote_door_id)
|
||||
if(M.density)
|
||||
M.open()
|
||||
else
|
||||
M.close()
|
||||
|
||||
if("Detonate")//Detonate PDA
|
||||
if(istype(cartridge, /obj/item/weapon/cartridge/syndicate))
|
||||
var/obj/item/device/pda/P = locate(href_list["target"])
|
||||
if(!isnull(P))
|
||||
if (!P.toff && cartridge:shock_charges > 0)
|
||||
cartridge:shock_charges--
|
||||
|
||||
var/difficulty = 0
|
||||
|
||||
if(P.cartridge)
|
||||
difficulty += P.cartridge.access_medical
|
||||
difficulty += P.cartridge.access_security
|
||||
difficulty += P.cartridge.access_engine
|
||||
difficulty += P.cartridge.access_clown
|
||||
difficulty += P.cartridge.access_janitor
|
||||
difficulty += P.cartridge.access_manifest * 2
|
||||
else
|
||||
difficulty += 2
|
||||
|
||||
if(prob(difficulty * 15) || (P.hidden_uplink))
|
||||
U.show_message("<span class='danger'>An error flashes on your [src].</span>", 1)
|
||||
else
|
||||
U.show_message("<span class='notice'>Success!</span>", 1)
|
||||
P.explode()
|
||||
else
|
||||
U << "PDA not found."
|
||||
else
|
||||
U.unset_machine()
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
//pAI FUNCTIONS===================================
|
||||
if("pai")
|
||||
switch(href_list["option"])
|
||||
if("1") // Configure pAI device
|
||||
pai.attack_self(U)
|
||||
if("2") // Eject pAI device
|
||||
var/turf/T = get_turf(src.loc)
|
||||
if(T)
|
||||
pai.loc = T
|
||||
|
||||
//LINK FUNCTIONS===================================
|
||||
|
||||
else//Cartridge menu linking
|
||||
mode = text2num(href_list["choice"])
|
||||
if(cartridge)
|
||||
cartridge.mode = mode
|
||||
cartridge.unlock()
|
||||
else//If not in range, can't interact or not using the pda.
|
||||
U.unset_machine()
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
//EXTRA FUNCTIONS===================================
|
||||
|
||||
if (mode == 2||mode == 21)//To clear message overlays.
|
||||
cut_overlays()
|
||||
|
||||
if ((honkamt > 0) && (prob(60)))//For clown virus.
|
||||
honkamt--
|
||||
playsound(loc, 'sound/items/bikehorn.ogg', 30, 1)
|
||||
|
||||
if(U.machine == src && href_list["skiprefresh"]!="1")//Final safety.
|
||||
attack_self(U)//It auto-closes the menu prior if the user is not in range and so on.
|
||||
else
|
||||
U.unset_machine()
|
||||
U << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
/obj/item/device/pda/proc/remove_id()
|
||||
if (id)
|
||||
if (ismob(loc))
|
||||
var/mob/M = loc
|
||||
M.put_in_hands(id)
|
||||
usr << "<span class='notice'>You remove the ID from the [name].</span>"
|
||||
else
|
||||
id.loc = get_turf(src)
|
||||
id = null
|
||||
|
||||
/obj/item/device/pda/proc/msg_input(mob/living/U = usr)
|
||||
var/t = stripped_input(U, "Please enter message", name, null, MAX_MESSAGE_LEN)
|
||||
if (!t || toff)
|
||||
return
|
||||
if (!in_range(src, U) && loc != U)
|
||||
return
|
||||
if(!U.canUseTopic(src))
|
||||
return
|
||||
if(emped)
|
||||
t = Gibberish(t, 100)
|
||||
return t
|
||||
|
||||
/obj/item/device/pda/proc/send_message(mob/living/user = usr,list/obj/item/device/pda/targets)
|
||||
var/message = msg_input(user)
|
||||
|
||||
if(!message || !targets.len)
|
||||
return
|
||||
|
||||
if(last_text && world.time < last_text + 5)
|
||||
return
|
||||
|
||||
var/multiple = targets.len > 1
|
||||
|
||||
var/datum/data_pda_msg/last_sucessful_msg
|
||||
for(var/obj/item/device/pda/P in targets)
|
||||
if(P == src)
|
||||
continue
|
||||
var/obj/machinery/message_server/MS = null
|
||||
MS = can_send(P)
|
||||
if(MS)
|
||||
var/datum/data_pda_msg/msg = MS.send_pda_message("[P.owner]","[owner]","[message]",photo)
|
||||
if(msg)
|
||||
last_sucessful_msg = msg
|
||||
if(!multiple)
|
||||
show_to_sender(msg)
|
||||
P.show_recieved_message(msg,src)
|
||||
if(!multiple)
|
||||
show_to_ghosts(user,msg)
|
||||
log_pda("[user] (PDA: [src.name]) sent \"[message]\" to [P.name]")
|
||||
else
|
||||
if(!multiple)
|
||||
user << "<span class='notice'>ERROR: Server isn't responding.</span>"
|
||||
return
|
||||
photo = null
|
||||
|
||||
if(multiple)
|
||||
show_to_sender(last_sucessful_msg,1)
|
||||
show_to_ghosts(user,last_sucessful_msg,1)
|
||||
log_pda("[user] (PDA: [src.name]) sent \"[message]\" to Everyone")
|
||||
|
||||
/obj/item/device/pda/proc/show_to_sender(datum/data_pda_msg/msg,multiple = 0)
|
||||
tnote += "<i><b>→ To [multiple ? "Everyone" : msg.recipient]:</b></i><br>[msg.message][msg.get_photo_ref()]<br>"
|
||||
|
||||
/obj/item/device/pda/proc/show_recieved_message(datum/data_pda_msg/msg,obj/item/device/pda/source)
|
||||
tnote += "<i><b>← From <a href='byond://?src=\ref[src];choice=Message;target=\ref[source]'>[source.owner]</a> ([source.ownjob]):</b></i><br>[msg.message][msg.get_photo_ref()]<br>"
|
||||
|
||||
if (!silent)
|
||||
playsound(loc, 'sound/machines/twobeep.ogg', 50, 1)
|
||||
audible_message("\icon[src] *[ttone]*", null, 3)
|
||||
//Search for holder of the PDA.
|
||||
var/mob/living/L = null
|
||||
if(loc && isliving(loc))
|
||||
L = loc
|
||||
//Maybe they are a pAI!
|
||||
else
|
||||
L = get(src, /mob/living/silicon)
|
||||
|
||||
if(L && L.stat != UNCONSCIOUS)
|
||||
L << "\icon[src] <b>Message from [source.owner] ([source.ownjob]), </b>\"[msg.message]\"[msg.get_photo_ref()] (<a href='byond://?src=\ref[src];choice=Message;skiprefresh=1;target=\ref[source]'>Reply</a>)"
|
||||
|
||||
cut_overlays()
|
||||
add_overlay(image(icon, icon_alert))
|
||||
|
||||
/obj/item/device/pda/proc/show_to_ghosts(mob/living/user, datum/data_pda_msg/msg,multiple = 0)
|
||||
for(var/mob/M in player_list)
|
||||
if(isobserver(M) && M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTPDA))
|
||||
var/link = FOLLOW_LINK(M, user)
|
||||
M << "[link] <span class='name'>[msg.sender] </span><span class='game say'>PDA Message</span> --> <span class='name'>[multiple ? "Everyone" : msg.recipient]</span>: <span class='message'>[msg.message][msg.get_photo_ref()]</span></span>"
|
||||
|
||||
/obj/item/device/pda/proc/can_send(obj/item/device/pda/P)
|
||||
if(!P || qdeleted(P) || P.toff)
|
||||
return null
|
||||
|
||||
var/obj/machinery/message_server/useMS = null
|
||||
if(message_servers)
|
||||
for (var/obj/machinery/message_server/MS in message_servers)
|
||||
//PDAs are now dependant on the Message Server.
|
||||
if(MS.active)
|
||||
useMS = MS
|
||||
break
|
||||
|
||||
var/datum/signal/signal = src.telecomms_process()
|
||||
|
||||
if(!P || qdeleted(P) || P.toff) //in case the PDA or mob gets destroyed during telecomms_process()
|
||||
return null
|
||||
|
||||
var/useTC = 0
|
||||
if(signal)
|
||||
if(signal.data["done"])
|
||||
useTC = 1
|
||||
var/turf/pos = get_turf(P)
|
||||
if(pos.z in signal.data["level"])
|
||||
useTC = 2
|
||||
|
||||
if(useTC == 2)
|
||||
return useMS
|
||||
else
|
||||
return null
|
||||
|
||||
|
||||
/obj/item/device/pda/proc/send_to_all(mob/living/U = usr)
|
||||
send_message(U,get_viewable_pdas())
|
||||
|
||||
/obj/item/device/pda/proc/create_message(mob/living/U = usr, obj/item/device/pda/P)
|
||||
send_message(U,list(P))
|
||||
|
||||
/obj/item/device/pda/AltClick()
|
||||
..()
|
||||
|
||||
if(issilicon(usr))
|
||||
return
|
||||
|
||||
if(usr.canUseTopic(src))
|
||||
if(id)
|
||||
remove_id()
|
||||
else
|
||||
usr << "<span class='warning'>This PDA does not have an ID in it!</span>"
|
||||
|
||||
/obj/item/device/pda/verb/verb_remove_id()
|
||||
set category = "Object"
|
||||
set name = "Eject ID"
|
||||
set src in usr
|
||||
|
||||
if(issilicon(usr))
|
||||
return
|
||||
|
||||
if (usr.canUseTopic(src))
|
||||
if(id)
|
||||
remove_id()
|
||||
else
|
||||
usr << "<span class='warning'>This PDA does not have an ID in it!</span>"
|
||||
|
||||
/obj/item/device/pda/verb/verb_remove_pen()
|
||||
set category = "Object"
|
||||
set name = "Remove Pen"
|
||||
set src in usr
|
||||
|
||||
if(issilicon(usr))
|
||||
return
|
||||
|
||||
if (usr.canUseTopic(src))
|
||||
var/obj/item/weapon/pen/O = locate() in src
|
||||
if(O)
|
||||
if (istype(loc, /mob))
|
||||
var/mob/M = loc
|
||||
if(M.get_active_hand() == null)
|
||||
M.put_in_hands(O)
|
||||
usr << "<span class='notice'>You remove \the [O] from \the [src].</span>"
|
||||
return
|
||||
O.loc = get_turf(src)
|
||||
else
|
||||
usr << "<span class='warning'>This PDA does not have a pen in it!</span>"
|
||||
|
||||
/obj/item/device/pda/proc/id_check(mob/user, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use.
|
||||
if(choice == 1)
|
||||
if (id)
|
||||
remove_id()
|
||||
else
|
||||
var/obj/item/I = user.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id))
|
||||
if(!user.unEquip(I))
|
||||
return 0
|
||||
I.loc = src
|
||||
id = I
|
||||
else
|
||||
var/obj/item/weapon/card/I = user.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id) && I:registered_name)
|
||||
if(!user.unEquip(I))
|
||||
return 0
|
||||
var/obj/old_id = id
|
||||
I.loc = src
|
||||
id = I
|
||||
user.put_in_hands(old_id)
|
||||
return 1
|
||||
|
||||
// access to status display signals
|
||||
/obj/item/device/pda/attackby(obj/item/C, mob/user, params)
|
||||
if(istype(C, /obj/item/weapon/cartridge) && !cartridge)
|
||||
cartridge = C
|
||||
if(!user.unEquip(C))
|
||||
return
|
||||
cartridge.loc = src
|
||||
user << "<span class='notice'>You insert [cartridge] into [src].</span>"
|
||||
if(cartridge.radio)
|
||||
cartridge.radio.hostpda = src
|
||||
|
||||
else if(istype(C, /obj/item/weapon/card/id))
|
||||
var/obj/item/weapon/card/id/idcard = C
|
||||
if(!idcard.registered_name)
|
||||
user << "<span class='warning'>\The [src] rejects the ID!</span>"
|
||||
return
|
||||
if(!owner)
|
||||
owner = idcard.registered_name
|
||||
ownjob = idcard.assignment
|
||||
update_label()
|
||||
user << "<span class='notice'>Card scanned.</span>"
|
||||
else
|
||||
//Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand.
|
||||
if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) )
|
||||
if(!id_check(user, 2))
|
||||
return
|
||||
user << "<span class='notice'>You put the ID into \the [src]'s slot.</span>"
|
||||
updateSelfDialog()//Update self dialog on success.
|
||||
return //Return in case of failed check or when successful.
|
||||
updateSelfDialog()//For the non-input related code.
|
||||
else if(istype(C, /obj/item/device/paicard) && !src.pai)
|
||||
if(!user.unEquip(C))
|
||||
return
|
||||
C.loc = src
|
||||
pai = C
|
||||
user << "<span class='notice'>You slot \the [C] into [src].</span>"
|
||||
updateUsrDialog()
|
||||
else if(istype(C, /obj/item/weapon/pen))
|
||||
var/obj/item/weapon/pen/O = locate() in src
|
||||
if(O)
|
||||
user << "<span class='warning'>There is already a pen in \the [src]!</span>"
|
||||
else
|
||||
if(!user.unEquip(C))
|
||||
return
|
||||
C.loc = src
|
||||
user << "<span class='notice'>You slide \the [C] into \the [src].</span>"
|
||||
else if(istype(C, /obj/item/weapon/photo))
|
||||
var/obj/item/weapon/photo/P = C
|
||||
photo = P.img
|
||||
user << "<span class='notice'>You scan \the [C].</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/pda/attack(mob/living/carbon/C, mob/living/user)
|
||||
if(istype(C))
|
||||
switch(scanmode)
|
||||
|
||||
if(1)
|
||||
C.visible_message("<span class='alert'>[user] has analyzed [C]'s vitals!</span>")
|
||||
healthscan(user, C, 1)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(2)
|
||||
// Unused
|
||||
|
||||
if(4)
|
||||
C.visible_message("<span class='warning'>[user] has analyzed [C]'s radiation levels!</span>")
|
||||
|
||||
user.show_message("<span class='notice'>Analyzing Results for [C]:</span>")
|
||||
if(C.radiation)
|
||||
user.show_message("\green Radiation Level: \black [C.radiation]")
|
||||
else
|
||||
user.show_message("<span class='notice'>No radiation detected.</span>")
|
||||
|
||||
/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user, proximity)
|
||||
if(!proximity) return
|
||||
switch(scanmode)
|
||||
|
||||
if(3)
|
||||
if(!isnull(A.reagents))
|
||||
if(A.reagents.reagent_list.len > 0)
|
||||
var/reagents_length = A.reagents.reagent_list.len
|
||||
user << "<span class='notice'>[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.</span>"
|
||||
for (var/re in A.reagents.reagent_list)
|
||||
user << "<span class='notice'>\t [re]</span>"
|
||||
else
|
||||
user << "<span class='notice'>No active chemical agents found in [A].</span>"
|
||||
else
|
||||
user << "<span class='notice'>No significant chemical agents found in [A].</span>"
|
||||
|
||||
if(5)
|
||||
if (istype(A, /obj/item/weapon/tank))
|
||||
var/obj/item/weapon/tank/T = A
|
||||
atmosanalyzer_scan(T.air_contents, user, T)
|
||||
else if (istype(A, /obj/machinery/portable_atmospherics))
|
||||
var/obj/machinery/portable_atmospherics/PA = A
|
||||
atmosanalyzer_scan(PA.air_contents, user, PA)
|
||||
else if (istype(A, /obj/machinery/atmospherics/pipe))
|
||||
var/obj/machinery/atmospherics/pipe/P = A
|
||||
atmosanalyzer_scan(P.parent.air, user, P)
|
||||
else if (istype(A, /obj/machinery/power/rad_collector))
|
||||
var/obj/machinery/power/rad_collector/RC = A
|
||||
if(RC.loaded_tank)
|
||||
atmosanalyzer_scan(RC.loaded_tank.air_contents, user, RC)
|
||||
else if (istype(A, /obj/item/weapon/flamethrower))
|
||||
var/obj/item/weapon/flamethrower/F = A
|
||||
if(F.ptank)
|
||||
atmosanalyzer_scan(F.ptank.air_contents, user, F)
|
||||
|
||||
if (!scanmode && istype(A, /obj/item/weapon/paper) && owner)
|
||||
var/obj/item/weapon/paper/PP = A
|
||||
if (!PP.info)
|
||||
user << "<span class='warning'>Unable to scan! Paper is blank.</span>"
|
||||
return
|
||||
notehtml = PP.info
|
||||
note = replacetext(notehtml, "<BR>", "\[br\]")
|
||||
note = replacetext(note, "<li>", "\[*\]")
|
||||
note = replacetext(note, "<ul>", "\[list\]")
|
||||
note = replacetext(note, "</ul>", "\[/list\]")
|
||||
note = html_encode(note)
|
||||
notescanned = 1
|
||||
user << "<span class='notice'>Paper scanned. Saved to PDA's notekeeper.</span>" //concept of scanning paper copyright brainoblivion 2009
|
||||
|
||||
|
||||
/obj/item/device/pda/proc/explode() //This needs tuning.
|
||||
if(!detonate) return
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
if (ismob(loc))
|
||||
var/mob/M = loc
|
||||
M.show_message("<span class='userdanger'>Your [src] explodes!</span>", 1)
|
||||
else
|
||||
visible_message("<span class='danger'>[src] explodes!</span>", "<span class='warning'>You hear a loud *pop*!</span>")
|
||||
|
||||
if(T)
|
||||
T.hotspot_expose(700,125)
|
||||
if(istype(cartridge, /obj/item/weapon/cartridge/syndicate))
|
||||
explosion(T, -1, 1, 3, 4)
|
||||
else
|
||||
explosion(T, -1, -1, 2, 3)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/device/pda/Destroy()
|
||||
PDAs -= src
|
||||
return ..()
|
||||
|
||||
//AI verb and proc for sending PDA messages.
|
||||
|
||||
/mob/living/silicon/ai/proc/cmd_send_pdamesg(mob/user)
|
||||
var/list/names = list()
|
||||
var/list/plist = list()
|
||||
var/list/namecounts = list()
|
||||
|
||||
if(user.stat == 2)
|
||||
return //won't work if dead
|
||||
|
||||
if(src.aiPDA.toff)
|
||||
user << "Turn on your receiver in order to send messages."
|
||||
return
|
||||
|
||||
for (var/obj/item/device/pda/P in get_viewable_pdas())
|
||||
if (P == src)
|
||||
continue
|
||||
else if (P == src.aiPDA)
|
||||
continue
|
||||
|
||||
var/name = P.owner
|
||||
if (name in names)
|
||||
namecounts[name]++
|
||||
name = text("[name] ([namecounts[name]])")
|
||||
else
|
||||
names.Add(name)
|
||||
namecounts[name] = 1
|
||||
|
||||
plist[text("[name]")] = P
|
||||
|
||||
var/c = input(user, "Please select a PDA") as null|anything in sortList(plist)
|
||||
|
||||
if (!c)
|
||||
return
|
||||
|
||||
var/selected = plist[c]
|
||||
|
||||
if(aicamera.aipictures.len>0)
|
||||
var/add_photo = input(user,"Do you want to attach a photo?","Photo","No") as null|anything in list("Yes","No")
|
||||
if(add_photo=="Yes")
|
||||
var/datum/picture/Pic = aicamera.selectpicture(aicamera)
|
||||
src.aiPDA.photo = Pic.fields["img"]
|
||||
src.aiPDA.create_message(src, selected)
|
||||
|
||||
|
||||
/mob/living/silicon/ai/verb/cmd_toggle_pda_receiver()
|
||||
set category = "AI Commands"
|
||||
set name = "PDA - Toggle Sender/Receiver"
|
||||
if(usr.stat == 2)
|
||||
return //won't work if dead
|
||||
if(!isnull(aiPDA))
|
||||
aiPDA.toff = !aiPDA.toff
|
||||
usr << "<span class='notice'>PDA sender/receiver toggled [(aiPDA.toff ? "Off" : "On")]!</span>"
|
||||
else
|
||||
usr << "You do not have a PDA. You should make an issue report about this."
|
||||
|
||||
/mob/living/silicon/ai/verb/cmd_toggle_pda_silent()
|
||||
set category = "AI Commands"
|
||||
set name = "PDA - Toggle Ringer"
|
||||
if(usr.stat == 2)
|
||||
return //won't work if dead
|
||||
if(!isnull(aiPDA))
|
||||
//0
|
||||
aiPDA.silent = !aiPDA.silent
|
||||
usr << "<span class='notice'>PDA ringer toggled [(aiPDA.silent ? "Off" : "On")]!</span>"
|
||||
else
|
||||
usr << "You do not have a PDA. You should make an issue report about this."
|
||||
|
||||
/mob/living/silicon/ai/proc/cmd_show_message_log(mob/user)
|
||||
if(user.stat == 2)
|
||||
return //won't work if dead
|
||||
if(!isnull(aiPDA))
|
||||
var/HTML = "<html><head><title>AI PDA Message Log</title></head><body>[aiPDA.tnote]</body></html>"
|
||||
user << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0")
|
||||
else
|
||||
user << "You do not have a PDA. You should make an issue report about this."
|
||||
|
||||
//Some spare PDAs in a box
|
||||
/obj/item/weapon/storage/box/PDAs
|
||||
name = "spare PDAs"
|
||||
desc = "A box of spare PDA microcomputers."
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "pda"
|
||||
|
||||
/obj/item/weapon/storage/box/PDAs/New()
|
||||
..()
|
||||
new /obj/item/device/pda(src)
|
||||
new /obj/item/device/pda(src)
|
||||
new /obj/item/device/pda(src)
|
||||
new /obj/item/device/pda(src)
|
||||
new /obj/item/weapon/cartridge/head(src)
|
||||
|
||||
var/newcart = pick( /obj/item/weapon/cartridge/engineering,
|
||||
/obj/item/weapon/cartridge/security,
|
||||
/obj/item/weapon/cartridge/medical,
|
||||
/obj/item/weapon/cartridge/signal/toxins,
|
||||
/obj/item/weapon/cartridge/quartermaster)
|
||||
new newcart(src)
|
||||
|
||||
// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP
|
||||
/obj/item/device/pda/emp_act(severity)
|
||||
for(var/atom/A in src)
|
||||
A.emp_act(severity)
|
||||
emped += 1
|
||||
spawn(200 * severity)
|
||||
emped -= 1
|
||||
|
||||
/proc/get_viewable_pdas()
|
||||
. = list()
|
||||
// Returns a list of PDAs which can be viewed from another PDA/message monitor.
|
||||
for(var/obj/item/device/pda/P in PDAs)
|
||||
if(!P.owner || P.toff || P.hidden) continue
|
||||
. += P
|
||||
return .
|
||||
@@ -0,0 +1,200 @@
|
||||
//Clown PDA is slippery.
|
||||
/obj/item/device/pda/clown
|
||||
name = "clown PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/clown
|
||||
icon_state = "pda-clown"
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings."
|
||||
ttone = "honk"
|
||||
|
||||
/obj/item/device/pda/clown/Crossed(AM as mob|obj)
|
||||
if (istype(AM, /mob/living/carbon))
|
||||
var/mob/living/carbon/M = AM
|
||||
if(M.slip(0, 6, src, NO_SLIP_WHEN_WALKING))
|
||||
if (ishuman(M) && (M.real_name != src.owner))
|
||||
if (istype(src.cartridge, /obj/item/weapon/cartridge/clown))
|
||||
var/obj/item/weapon/cartridge/clown/cart = src.cartridge
|
||||
if(cart.honk_charges < 5)
|
||||
cart.honk_charges++
|
||||
|
||||
|
||||
// Special AI/pAI PDAs that cannot explode.
|
||||
/obj/item/device/pda/ai
|
||||
icon_state = "NONE"
|
||||
ttone = "data"
|
||||
fon = 0
|
||||
detonate = 0
|
||||
|
||||
/obj/item/device/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/device/pda/ai/pai
|
||||
ttone = "assist"
|
||||
|
||||
|
||||
|
||||
/obj/item/device/pda/medical
|
||||
name = "medical PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/medical
|
||||
icon_state = "pda-medical"
|
||||
|
||||
/obj/item/device/pda/viro
|
||||
name = "virology PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/medical
|
||||
icon_state = "pda-virology"
|
||||
|
||||
/obj/item/device/pda/engineering
|
||||
name = "engineering PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/engineering
|
||||
icon_state = "pda-engineer"
|
||||
|
||||
/obj/item/device/pda/security
|
||||
name = "security PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/security
|
||||
icon_state = "pda-security"
|
||||
|
||||
/obj/item/device/pda/detective
|
||||
name = "detective PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/detective
|
||||
icon_state = "pda-detective"
|
||||
|
||||
/obj/item/device/pda/warden
|
||||
name = "warden PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/security
|
||||
icon_state = "pda-warden"
|
||||
|
||||
/obj/item/device/pda/janitor
|
||||
name = "janitor PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/janitor
|
||||
icon_state = "pda-janitor"
|
||||
ttone = "slip"
|
||||
|
||||
/obj/item/device/pda/toxins
|
||||
name = "scientist PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/signal/toxins
|
||||
icon_state = "pda-science"
|
||||
ttone = "boom"
|
||||
|
||||
/obj/item/device/pda/mime
|
||||
name = "mime PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/mime
|
||||
icon_state = "pda-mime"
|
||||
silent = 1
|
||||
ttone = "silence"
|
||||
|
||||
/obj/item/device/pda/heads
|
||||
default_cartridge = /obj/item/weapon/cartridge/head
|
||||
icon_state = "pda-hop"
|
||||
|
||||
/obj/item/device/pda/heads/hop
|
||||
name = "head of personnel PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/hop
|
||||
icon_state = "pda-hop"
|
||||
|
||||
/obj/item/device/pda/heads/hos
|
||||
name = "head of security PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/hos
|
||||
icon_state = "pda-hos"
|
||||
|
||||
/obj/item/device/pda/heads/ce
|
||||
name = "chief engineer PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/ce
|
||||
icon_state = "pda-ce"
|
||||
|
||||
/obj/item/device/pda/heads/cmo
|
||||
name = "chief medical officer PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/cmo
|
||||
icon_state = "pda-cmo"
|
||||
|
||||
/obj/item/device/pda/heads/rd
|
||||
name = "research director PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/rd
|
||||
icon_state = "pda-rd"
|
||||
|
||||
/obj/item/device/pda/captain
|
||||
name = "captain PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/captain
|
||||
icon_state = "pda-captain"
|
||||
detonate = 0
|
||||
|
||||
/obj/item/device/pda/cargo
|
||||
name = "cargo technician PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/quartermaster
|
||||
icon_state = "pda-cargo"
|
||||
|
||||
/obj/item/device/pda/quartermaster
|
||||
name = "quartermaster PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/quartermaster
|
||||
icon_state = "pda-qm"
|
||||
|
||||
/obj/item/device/pda/shaftminer
|
||||
name = "shaft miner PDA"
|
||||
icon_state = "pda-miner"
|
||||
|
||||
/obj/item/device/pda/syndicate
|
||||
default_cartridge = /obj/item/weapon/cartridge/syndicate
|
||||
icon_state = "pda-syndi"
|
||||
name = "military PDA"
|
||||
owner = "John Doe"
|
||||
hidden = 1
|
||||
|
||||
/obj/item/device/pda/chaplain
|
||||
name = "chaplain PDA"
|
||||
icon_state = "pda-chaplain"
|
||||
ttone = "holy"
|
||||
|
||||
/obj/item/device/pda/lawyer
|
||||
name = "lawyer PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/lawyer
|
||||
icon_state = "pda-lawyer"
|
||||
ttone = "objection"
|
||||
|
||||
/obj/item/device/pda/botanist
|
||||
name = "botanist PDA"
|
||||
//default_cartridge = /obj/item/weapon/cartridge/botanist
|
||||
icon_state = "pda-hydro"
|
||||
|
||||
/obj/item/device/pda/roboticist
|
||||
name = "roboticist PDA"
|
||||
icon_state = "pda-roboticist"
|
||||
default_cartridge = /obj/item/weapon/cartridge/roboticist
|
||||
|
||||
/obj/item/device/pda/librarian
|
||||
name = "librarian PDA"
|
||||
icon_state = "pda-library"
|
||||
icon_alert = "pda-r-library"
|
||||
default_cartridge = /obj/item/weapon/cartridge/librarian
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. This is 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!"
|
||||
silent = 1 //Quiet in the library!
|
||||
|
||||
/obj/item/device/pda/clear
|
||||
name = "clear PDA"
|
||||
icon_state = "pda-clear"
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. This is 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!"
|
||||
|
||||
/obj/item/device/pda/cook
|
||||
name = "cook PDA"
|
||||
icon_state = "pda-cook"
|
||||
|
||||
/obj/item/device/pda/bar
|
||||
name = "bartender PDA"
|
||||
icon_state = "pda-bartender"
|
||||
|
||||
/obj/item/device/pda/atmos
|
||||
name = "atmospherics PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/atmos
|
||||
icon_state = "pda-atmos"
|
||||
|
||||
/obj/item/device/pda/chemist
|
||||
name = "chemist PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/chemistry
|
||||
icon_state = "pda-chemistry"
|
||||
|
||||
/obj/item/device/pda/geneticist
|
||||
name = "geneticist PDA"
|
||||
default_cartridge = /obj/item/weapon/cartridge/medical
|
||||
icon_state = "pda-genetics"
|
||||
@@ -0,0 +1,778 @@
|
||||
/obj/item/weapon/cartridge
|
||||
name = "generic cartridge"
|
||||
desc = "A data cartridge for portable microcomputers."
|
||||
icon = 'icons/obj/pda.dmi'
|
||||
icon_state = "cart"
|
||||
item_state = "electronic"
|
||||
w_class = 1
|
||||
|
||||
var/obj/item/radio/integrated/radio = null
|
||||
var/access_security = 0
|
||||
var/access_engine = 0
|
||||
var/access_atmos = 0
|
||||
var/access_medical = 0
|
||||
var/access_manifest = 0
|
||||
var/access_clown = 0
|
||||
var/access_mime = 0
|
||||
var/access_janitor = 0
|
||||
// var/access_flora = 0
|
||||
var/access_reagent_scanner = 0
|
||||
var/access_newscaster = 0
|
||||
var/access_remote_door = 0 //Control some blast doors remotely!!
|
||||
var/remote_door_id = ""
|
||||
var/access_status_display = 0
|
||||
var/access_quartermaster = 0
|
||||
var/access_hydroponics = 0
|
||||
var/bot_access_flags = 0 //Bit flags. Selection: SEC_BOT|MULE_BOT|FLOOR_BOT|CLEAN_BOT|MED_BOT
|
||||
var/spam_enabled = 0 //Enables "Send to All" Option
|
||||
|
||||
var/mode = 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/weapon/cartridge/engineering
|
||||
name = "\improper Power-ON cartridge"
|
||||
icon_state = "cart-e"
|
||||
access_engine = 1
|
||||
bot_access_flags = FLOOR_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/atmos
|
||||
name = "\improper BreatheDeep cartridge"
|
||||
icon_state = "cart-a"
|
||||
access_atmos = 1
|
||||
bot_access_flags = FLOOR_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/medical
|
||||
name = "\improper Med-U cartridge"
|
||||
icon_state = "cart-m"
|
||||
access_medical = 1
|
||||
bot_access_flags = MED_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/chemistry
|
||||
name = "\improper ChemWhiz cartridge"
|
||||
icon_state = "cart-chem"
|
||||
access_reagent_scanner = 1
|
||||
bot_access_flags = MED_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/security
|
||||
name = "\improper R.O.B.U.S.T. cartridge"
|
||||
icon_state = "cart-s"
|
||||
access_security = 1
|
||||
bot_access_flags = SEC_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/detective
|
||||
name = "\improper D.E.T.E.C.T. cartridge"
|
||||
icon_state = "cart-s"
|
||||
access_security = 1
|
||||
access_medical = 1
|
||||
access_manifest = 1
|
||||
bot_access_flags = SEC_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/janitor
|
||||
name = "\improper CustodiPRO cartridge"
|
||||
desc = "The ultimate in clean-room design."
|
||||
icon_state = "cart-j"
|
||||
access_janitor = 1
|
||||
bot_access_flags = CLEAN_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/lawyer
|
||||
name = "\improper P.R.O.V.E. cartridge"
|
||||
icon_state = "cart-s"
|
||||
access_security = 1
|
||||
spam_enabled = 1
|
||||
|
||||
/obj/item/weapon/cartridge/clown
|
||||
name = "\improper Honkworks 5.0 cartridge"
|
||||
icon_state = "cart-clown"
|
||||
access_clown = 1
|
||||
var/honk_charges = 5
|
||||
|
||||
/obj/item/weapon/cartridge/mime
|
||||
name = "\improper Gestur-O 1000 cartridge"
|
||||
icon_state = "cart-mi"
|
||||
access_mime = 1
|
||||
var/mime_charges = 5
|
||||
|
||||
/obj/item/weapon/cartridge/librarian
|
||||
name = "\improper Lib-Tweet cartridge"
|
||||
icon_state = "cart-s"
|
||||
access_newscaster = 1
|
||||
|
||||
/*
|
||||
/obj/item/weapon/cartridge/botanist
|
||||
name = "\improper Green Thumb v4.20 cartridge"
|
||||
icon_state = "cart-b"
|
||||
access_flora = 1
|
||||
*/
|
||||
|
||||
/obj/item/weapon/cartridge/roboticist
|
||||
name = "\improper B.O.O.P. Remote Control cartridge"
|
||||
desc = "Packed with heavy duty triple-bot interlink!"
|
||||
bot_access_flags = FLOOR_BOT|CLEAN_BOT|MED_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/signal
|
||||
name = "generic signaler cartridge"
|
||||
desc = "A data cartridge with an integrated radio signaler module."
|
||||
|
||||
/obj/item/weapon/cartridge/signal/toxins
|
||||
name = "\improper Signal Ace 2 cartridge"
|
||||
desc = "Complete with integrated radio signaler!"
|
||||
icon_state = "cart-tox"
|
||||
access_reagent_scanner = 1
|
||||
access_atmos = 1
|
||||
|
||||
/obj/item/weapon/cartridge/signal/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/signal(src)
|
||||
|
||||
|
||||
|
||||
/obj/item/weapon/cartridge/quartermaster
|
||||
name = "space parts & space vendors cartridge"
|
||||
desc = "Perfect for the Quartermaster on the go!"
|
||||
icon_state = "cart-q"
|
||||
access_quartermaster = 1
|
||||
bot_access_flags = MULE_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/head
|
||||
name = "\improper Easy-Record DELUXE cartridge"
|
||||
icon_state = "cart-h"
|
||||
access_manifest = 1
|
||||
access_status_display = 1
|
||||
|
||||
/obj/item/weapon/cartridge/hop
|
||||
name = "\improper HumanResources9001 cartridge"
|
||||
icon_state = "cart-h"
|
||||
access_manifest = 1
|
||||
access_status_display = 1
|
||||
bot_access_flags = MULE_BOT|CLEAN_BOT
|
||||
access_janitor = 1
|
||||
access_security = 1
|
||||
access_newscaster = 1
|
||||
access_quartermaster = 1
|
||||
|
||||
/obj/item/weapon/cartridge/hos
|
||||
name = "\improper R.O.B.U.S.T. DELUXE cartridge"
|
||||
icon_state = "cart-hos"
|
||||
access_manifest = 1
|
||||
access_status_display = 1
|
||||
access_security = 1
|
||||
bot_access_flags = SEC_BOT
|
||||
|
||||
|
||||
/obj/item/weapon/cartridge/ce
|
||||
name = "\improper Power-On DELUXE cartridge"
|
||||
icon_state = "cart-ce"
|
||||
access_manifest = 1
|
||||
access_status_display = 1
|
||||
access_engine = 1
|
||||
access_atmos = 1
|
||||
bot_access_flags = FLOOR_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/cmo
|
||||
name = "\improper Med-U DELUXE cartridge"
|
||||
icon_state = "cart-cmo"
|
||||
access_manifest = 1
|
||||
access_status_display = 1
|
||||
access_reagent_scanner = 1
|
||||
access_medical = 1
|
||||
bot_access_flags = MED_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/rd
|
||||
name = "\improper Signal Ace DELUXE cartridge"
|
||||
icon_state = "cart-rd"
|
||||
access_manifest = 1
|
||||
access_status_display = 1
|
||||
access_reagent_scanner = 1
|
||||
access_atmos = 1
|
||||
bot_access_flags = FLOOR_BOT|CLEAN_BOT|MED_BOT
|
||||
|
||||
/obj/item/weapon/cartridge/rd/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/signal(src)
|
||||
|
||||
/obj/item/weapon/cartridge/captain
|
||||
name = "\improper Value-PAK cartridge"
|
||||
desc = "Now with 350% more value!" //Give the Captain...EVERYTHING! (Except Mime and Clown)
|
||||
icon_state = "cart-c"
|
||||
access_manifest = 1
|
||||
access_engine = 1
|
||||
access_security = 1
|
||||
access_medical = 1
|
||||
access_reagent_scanner = 1
|
||||
access_status_display = 1
|
||||
access_atmos = 1
|
||||
access_newscaster = 1
|
||||
access_quartermaster = 1
|
||||
access_janitor = 1
|
||||
bot_access_flags = SEC_BOT|MULE_BOT|FLOOR_BOT|CLEAN_BOT|MED_BOT
|
||||
spam_enabled = 1
|
||||
|
||||
/obj/item/weapon/cartridge/captain/New()
|
||||
..()
|
||||
radio = new /obj/item/radio/integrated/signal(src)
|
||||
|
||||
/obj/item/weapon/cartridge/syndicate
|
||||
name = "\improper Detomatix cartridge"
|
||||
icon_state = "cart"
|
||||
access_remote_door = 1
|
||||
remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
|
||||
var/shock_charges = 4
|
||||
|
||||
/obj/item/weapon/cartridge/proc/unlock()
|
||||
if (!istype(loc, /obj/item/device/pda))
|
||||
return
|
||||
|
||||
generate_menu()
|
||||
print_to_host(menu)
|
||||
return
|
||||
|
||||
/obj/item/weapon/cartridge/proc/print_to_host(text)
|
||||
if (!istype(loc, /obj/item/device/pda))
|
||||
return
|
||||
var/obj/item/device/pda/P = loc
|
||||
P.cart = text
|
||||
|
||||
for (var/mob/M in viewers(1, loc.loc))
|
||||
if (M.client && M.machine == loc)
|
||||
P.attack_self(M)
|
||||
|
||||
return
|
||||
|
||||
/obj/item/weapon/cartridge/proc/post_status(command, data1, data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
|
||||
|
||||
if(!frequency) return
|
||||
|
||||
var/datum/signal/status_signal = new
|
||||
status_signal.source = src
|
||||
status_signal.transmission_method = 1
|
||||
status_signal.data["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/weapon/cartridge/proc/generate_menu(mob/user)
|
||||
switch(mode)
|
||||
if(40) //signaller
|
||||
var/obj/item/radio/integrated/signal/S = radio
|
||||
menu = "<h4><img src=pda_signaler.png> 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(S.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>
|
||||
[S.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><img src=pda_notes.png> Crew Manifest</h4>"
|
||||
menu += "Entries cannot be modified from this terminal.<br><br>"
|
||||
if(data_core.general)
|
||||
for (var/datum/data/record/t in sortRecord(data_core.general))
|
||||
menu += "[t.fields["name"]] - [t.fields["rank"]]<br>"
|
||||
menu += "<br>"
|
||||
|
||||
|
||||
if (42) //status displays
|
||||
menu = "<h4><img src=pda_status.png> 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><img src=pda_power.png> Power Monitors - Please select one</h4><BR>"
|
||||
powmonitor = null
|
||||
powermonitors = list()
|
||||
var/powercount = 0
|
||||
|
||||
|
||||
|
||||
for(var/obj/machinery/computer/monitor/pMon in machines)
|
||||
if(!(pMon.stat & (NOPOWER|BROKEN)) )
|
||||
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] </a><BR>"
|
||||
|
||||
menu += "</FONT>"
|
||||
|
||||
if (433)
|
||||
menu = "<h4><img src=pda_power.png> Power Monitor </h4><BR>"
|
||||
if(!powmonitor)
|
||||
menu += "<span class='danger'>No connection<BR></span>"
|
||||
else
|
||||
var/list/L = list()
|
||||
for(var/obj/machinery/power/terminal/term in powmonitor.attached.powernet.nodes)
|
||||
if(istype(term.master, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/A = term.master
|
||||
L += A
|
||||
|
||||
menu += "<PRE>Total power: [powmonitor.attached.powernet.viewavail] W<BR>Total load: [num2text(powmonitor.attached.powernet.viewload,10)] W<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(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><img src=pda_medical.png> Medical Record List</h4>"
|
||||
if(data_core.general)
|
||||
for(var/datum/data/record/R in sortRecord(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><img src=pda_medical.png> Medical Record</h4>"
|
||||
|
||||
if(active1 in 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><img src=pda_medical.png> Medical Data</h4>"
|
||||
if(active2 in 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><img src=pda_cuffs.png> Security Record List</h4>"
|
||||
if(data_core.general)
|
||||
for (var/datum/data/record/R in sortRecord(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><img src=pda_cuffs.png> Security Record</h4>"
|
||||
|
||||
if(active1 in 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><img src=pda_cuffs.png> Security Data</h4>"
|
||||
if(active3 in 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><img src=pda_crate.png> Supply Record Interlink</h4>"
|
||||
|
||||
menu += "<BR><B>Supply shuttle</B><BR>"
|
||||
menu += "Location: "
|
||||
switch(SSshuttle.supply.mode)
|
||||
if(SHUTTLE_CALL)
|
||||
menu += "Moving to "
|
||||
if(SSshuttle.supply.z != ZLEVEL_STATION)
|
||||
menu += "station"
|
||||
else
|
||||
menu += "centcomm"
|
||||
menu += " ([SSshuttle.supply.timeLeft(600)] Mins)"
|
||||
else
|
||||
menu += "At "
|
||||
if(SSshuttle.supply.z != ZLEVEL_STATION)
|
||||
menu += "centcomm"
|
||||
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 (49) //janitorial locator
|
||||
menu = "<h4><img src=pda_bucket.png> 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/weapon/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>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 living_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><img src=pda_notes.png> 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 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><img src=pda_medbot.png> Bots Interlink</h4>"
|
||||
bot_control()
|
||||
|
||||
/obj/item/weapon/cartridge/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
var/obj/item/device/pda/pda = loc
|
||||
|
||||
switch(href_list["choice"])
|
||||
if("Medical Records")
|
||||
active1 = find_record("id", href_list["target"], data_core.general)
|
||||
if(active1)
|
||||
active2 = find_record("id", href_list["target"], data_core.medical)
|
||||
pda.mode = 441
|
||||
mode = 441
|
||||
if(!active2)
|
||||
active1 = null
|
||||
|
||||
if("Security Records")
|
||||
active1 = find_record("id", href_list["target"], data_core.general)
|
||||
if(active1)
|
||||
active3 = find_record("id", href_list["target"], data_core.security)
|
||||
pda.mode = 451
|
||||
mode = 451
|
||||
if(!active3)
|
||||
active1 = null
|
||||
|
||||
if("Send Signal")
|
||||
spawn( 0 )
|
||||
var/obj/item/radio/integrated/signal/S = radio
|
||||
S.send_signal("ACTIVATE")
|
||||
return
|
||||
|
||||
if("Signal Frequency")
|
||||
var/obj/item/radio/integrated/signal/S = radio
|
||||
var/new_frequency = sanitize_frequency(S.frequency + text2num(href_list["sfreq"]))
|
||||
S.set_frequency(new_frequency)
|
||||
|
||||
if("Signal Code")
|
||||
var/obj/item/radio/integrated/signal/S = radio
|
||||
S.code += text2num(href_list["scode"])
|
||||
S.code = round(S.code)
|
||||
S.code = min(100, S.code)
|
||||
S.code = max(1, S.code)
|
||||
|
||||
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"])
|
||||
if("Power Select")
|
||||
var/pnum = text2num(href_list["target"])
|
||||
powmonitor = powermonitors[pnum]
|
||||
pda.mode = 433
|
||||
mode = 433
|
||||
|
||||
if("Supply Orders")
|
||||
pda.mode =47
|
||||
mode = 47
|
||||
|
||||
if("Newscaster Access")
|
||||
mode = 53
|
||||
|
||||
if("Newscaster Message")
|
||||
var/pda_owner_name = pda.id ? "[pda.id.registered_name] ([pda.id.assignment])" : "Unknown"
|
||||
var/message = pda.msg_input()
|
||||
var/datum/newscaster/feed_channel/current
|
||||
for(var/datum/newscaster/feed_channel/chan in news_network.network_channels)
|
||||
if (chan.channel_name == current_channel)
|
||||
current = chan
|
||||
if(current.locked && current.author != pda_owner_name)
|
||||
pda.cart += "<h5> ERROR : NOT AUTHORIZED [pda.id ? "" : "- ID SLOT EMPTY"] </h5>"
|
||||
pda.Topic(null,list("choice"="Refresh"))
|
||||
return
|
||||
news_network.SubmitArticle(message,pda.owner,current_channel)
|
||||
pda.Topic(null,list("choice"=num2text(mode)))
|
||||
return
|
||||
|
||||
if("Newscaster Switch Channel")
|
||||
current_channel = pda.msg_input()
|
||||
pda.Topic(null,list("choice"=num2text(mode)))
|
||||
return
|
||||
|
||||
//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= pda.GetAccess())
|
||||
else //Forward all other bot commands to the bot itself!
|
||||
active_bot.bot_control(command= href_list["op"], user= usr)
|
||||
|
||||
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)
|
||||
|
||||
generate_menu(usr)
|
||||
print_to_host(menu)
|
||||
|
||||
|
||||
|
||||
/obj/item/weapon/cartridge/proc/bot_control()
|
||||
|
||||
|
||||
var/mob/living/simple_animal/bot/Bot
|
||||
|
||||
// if(!SC)
|
||||
// menu = "Interlink Error - Please reinsert cartridge."
|
||||
// return
|
||||
if(active_bot)
|
||||
menu += "<B>[active_bot]</B><BR> Status: (<A href='byond://?src=\ref[src];op=control;bot=\ref[active_bot]'><img src=pda_refresh.png><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'><img src=pda_back.png>Return to bot list</A>"
|
||||
else
|
||||
menu += "<BR><A href='byond://?src=\ref[src];op=botlist'><img src=pda_refresh.png>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 living_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
|
||||
@@ -0,0 +1,70 @@
|
||||
/obj/item/radio/integrated
|
||||
name = "\improper PDA radio module"
|
||||
desc = "An electronic radio system of nanotrasen origin."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "power_mod"
|
||||
var/obj/item/device/pda/hostpda = null
|
||||
|
||||
var/on = 0 //Are we currently active??
|
||||
var/menu_message = ""
|
||||
|
||||
/obj/item/radio/integrated/New()
|
||||
..()
|
||||
if (istype(loc.loc, /obj/item/device/pda))
|
||||
hostpda = loc.loc
|
||||
|
||||
/obj/item/radio/integrated/Destroy()
|
||||
hostpda = null
|
||||
return ..()
|
||||
|
||||
/*
|
||||
* Radio Cartridge, essentially a signaler.
|
||||
*/
|
||||
|
||||
|
||||
/obj/item/radio/integrated/signal
|
||||
var/frequency = 1457
|
||||
var/code = 30
|
||||
var/last_transmission
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
/obj/item/radio/integrated/signal/New()
|
||||
..()
|
||||
if(SSradio)
|
||||
initialize()
|
||||
|
||||
/obj/item/radio/integrated/signal/Destroy()
|
||||
if(SSradio)
|
||||
SSradio.remove_object(src, frequency)
|
||||
radio_connection = null
|
||||
return ..()
|
||||
|
||||
/obj/item/radio/integrated/signal/initialize()
|
||||
if (src.frequency < 1200 || src.frequency > 1600)
|
||||
src.frequency = sanitize_frequency(src.frequency)
|
||||
|
||||
set_frequency(frequency)
|
||||
|
||||
/obj/item/radio/integrated/signal/proc/set_frequency(new_frequency)
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = SSradio.add_object(src, frequency)
|
||||
|
||||
/obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE")
|
||||
|
||||
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)
|
||||
lastsignalers.Add("[time] <B>:</B> [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) <B>:</B> [format_frequency(frequency)]/[code]")
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.source = src
|
||||
signal.encryption = code
|
||||
signal.data["message"] = message
|
||||
|
||||
radio_connection.post_signal(src, signal)
|
||||
|
||||
return
|
||||
@@ -0,0 +1,85 @@
|
||||
/obj/item/device/aicard
|
||||
name = "intelliCard"
|
||||
desc = "A storage device for AIs. Patent pending."
|
||||
icon = 'icons/obj/aicards.dmi'
|
||||
icon_state = "aicard" // aicard-full
|
||||
item_state = "electronic"
|
||||
w_class = 2
|
||||
slot_flags = SLOT_BELT
|
||||
flags = NOBLUDGEON
|
||||
var/flush = FALSE
|
||||
var/mob/living/silicon/ai/AI
|
||||
origin_tech = "programming=3;materials=3"
|
||||
|
||||
/obj/item/device/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)
|
||||
add_logs(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/device/aicard/update_icon()
|
||||
if(AI)
|
||||
name = "[initial(name)]- [AI.name]"
|
||||
if(AI.stat == DEAD)
|
||||
icon_state = "aicard-404"
|
||||
else
|
||||
icon_state = "aicard-full"
|
||||
if(!AI.control_disabled)
|
||||
add_overlay(image('icons/obj/aicards.dmi', "aicard-on"))
|
||||
AI.cancel_camera()
|
||||
else
|
||||
name = initial(name)
|
||||
icon_state = initial(icon_state)
|
||||
cut_overlays()
|
||||
|
||||
/obj/item/device/aicard/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = 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/device/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 ? TRUE : FALSE
|
||||
data["wiping"] = flush
|
||||
return data
|
||||
|
||||
/obj/item/device/aicard/ui_act(action,params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("wipe")
|
||||
var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", name, "Yes", "No")
|
||||
if(confirm == "Yes" && !..())
|
||||
flush = TRUE
|
||||
if(AI && AI.loc == src)
|
||||
AI.suiciding = TRUE
|
||||
AI << "Your core files are being wiped!"
|
||||
while(AI.stat != DEAD)
|
||||
AI.adjustOxyLoss(2)
|
||||
AI.updatehealth()
|
||||
sleep(10)
|
||||
flush = FALSE
|
||||
. = TRUE
|
||||
if("wireless")
|
||||
AI.control_disabled = !AI.control_disabled
|
||||
AI << "[src]'s wireless port has been [AI.control_disabled ? "disabled" : "enabled"]!"
|
||||
. = TRUE
|
||||
if("radio")
|
||||
AI.radio_enabled = !AI.radio_enabled
|
||||
AI << "Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!"
|
||||
. = TRUE
|
||||
update_icon()
|
||||
@@ -0,0 +1,282 @@
|
||||
|
||||
#define BUGMODE_LIST 0
|
||||
#define BUGMODE_MONITOR 1
|
||||
#define BUGMODE_TRACK 2
|
||||
|
||||
|
||||
|
||||
/obj/item/device/camera_bug
|
||||
name = "camera bug"
|
||||
desc = "For illicit snooping through the camera network."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "camera_bug"
|
||||
w_class = 1
|
||||
item_state = "camera_bug"
|
||||
throw_speed = 4
|
||||
throw_range = 20
|
||||
origin_tech = "syndicate=1;engineering=3"
|
||||
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/device/camera_bug/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/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/device/camera_bug/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/device/camera_bug/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/item/device/camera_bug/check_eye(mob/user)
|
||||
if ( loc != user || user.incapacitated() || user.eye_blind || !current )
|
||||
user.unset_machine()
|
||||
return
|
||||
var/turf/T = get_turf(user.loc)
|
||||
if(T.z != current.z || !current.can_use())
|
||||
user << "<span class='danger'>[src] has lost the signal.</span>"
|
||||
current = null
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/device/camera_bug/on_unset_machine(mob/user)
|
||||
user.reset_perspective(null)
|
||||
|
||||
/obj/item/device/camera_bug/proc/get_cameras()
|
||||
if( world.time > (last_net_update + 100))
|
||||
bugged_cameras = list()
|
||||
for(var/obj/machinery/camera/camera in cameranet.cameras)
|
||||
if(camera.stat || !camera.can_use())
|
||||
continue
|
||||
if(length(list("SS13","MINE")&camera.network))
|
||||
bugged_cameras[camera.c_tag] = camera
|
||||
sortList(bugged_cameras)
|
||||
return bugged_cameras
|
||||
|
||||
|
||||
/obj/item/device/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/device/camera_bug/proc/camera_report()
|
||||
// this should only be called if current exists
|
||||
var/dat = ""
|
||||
if(current && current.can_use())
|
||||
var/list/seen = current.can_see()
|
||||
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/device/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)
|
||||
var/obj/machinery/camera/C = locate(href_list["monitor"])
|
||||
if(C)
|
||||
track_mode = BUGMODE_MONITOR
|
||||
current = C
|
||||
usr.reset_perspective(null)
|
||||
interact()
|
||||
if("track" in href_list)
|
||||
var/atom/A = locate(href_list["track"])
|
||||
if(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)
|
||||
var/obj/machinery/camera/C = locate(href_list["emp"])
|
||||
if(istype(C) && C.bug == src)
|
||||
C.emp_act(1)
|
||||
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)
|
||||
var/obj/machinery/camera/C = locate(href_list["view"])
|
||||
if(istype(C))
|
||||
if(!C.can_use())
|
||||
usr << "<span class='warning'>Something's wrong with that camera! You can't get a feed.</span>"
|
||||
return
|
||||
var/turf/T = get_turf(loc)
|
||||
if(!T || C.z != T.z)
|
||||
usr << "<span class='warning'>You can't get a signal!</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/device/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()
|
||||
|
||||
|
||||
#undef BUGMODE_LIST
|
||||
#undef BUGMODE_MONITOR
|
||||
#undef BUGMODE_TRACK
|
||||
@@ -0,0 +1,138 @@
|
||||
/obj/item/device/chameleon
|
||||
name = "chameleon-projector"
|
||||
icon_state = "shield0"
|
||||
flags = CONDUCT | NOBLUDGEON
|
||||
slot_flags = SLOT_BELT
|
||||
item_state = "electronic"
|
||||
throwforce = 5
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = 2
|
||||
origin_tech = "syndicate=4;magnets=4"
|
||||
var/can_use = 1
|
||||
var/obj/effect/dummy/chameleon/active_dummy = null
|
||||
var/saved_appearance = null
|
||||
|
||||
/obj/item/device/chameleon/New()
|
||||
..()
|
||||
var/obj/item/weapon/cigbutt/butt = /obj/item/weapon/cigbutt
|
||||
saved_appearance = initial(butt.appearance)
|
||||
|
||||
/obj/item/device/chameleon/dropped()
|
||||
..()
|
||||
disrupt()
|
||||
|
||||
/obj/item/device/chameleon/equipped()
|
||||
disrupt()
|
||||
|
||||
/obj/item/device/chameleon/attack_self()
|
||||
toggle()
|
||||
|
||||
/obj/item/device/chameleon/afterattack(atom/target, mob/user , proximity)
|
||||
if(!proximity) return
|
||||
if(!active_dummy)
|
||||
if(istype(target,/obj/item) && !istype(target, /obj/item/weapon/disk/nuclear))
|
||||
playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6)
|
||||
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
|
||||
saved_appearance = temp.appearance
|
||||
|
||||
/obj/item/device/chameleon/proc/toggle()
|
||||
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
|
||||
usr << "<span class='notice'>You deactivate \the [src].</span>"
|
||||
PoolOrNew(/obj/effect/overlay/temp/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(usr.loc)
|
||||
C.activate(usr, saved_appearance, src)
|
||||
usr << "<span class='notice'>You activate \the [src].</span>"
|
||||
PoolOrNew(/obj/effect/overlay/temp/emp/pulse, get_turf(src))
|
||||
|
||||
/obj/item/device/chameleon/proc/disrupt(delete_dummy = 1)
|
||||
if(active_dummy)
|
||||
for(var/mob/M in active_dummy)
|
||||
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/device/chameleon/proc/eject_all()
|
||||
for(var/atom/movable/A in active_dummy)
|
||||
A.loc = active_dummy.loc
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
M.reset_perspective(null)
|
||||
|
||||
/obj/effect/dummy/chameleon
|
||||
name = ""
|
||||
desc = ""
|
||||
density = 0
|
||||
var/can_move = 1
|
||||
var/obj/item/device/chameleon/master = null
|
||||
|
||||
/obj/effect/dummy/chameleon/proc/activate(mob/M, saved_appearance, obj/item/device/chameleon/C)
|
||||
appearance = saved_appearance
|
||||
M.loc = src
|
||||
master = C
|
||||
master.active_dummy = src
|
||||
|
||||
/obj/effect/dummy/chameleon/attackby()
|
||||
master.disrupt()
|
||||
|
||||
/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(istype(loc, /turf/open/space) || !direction)
|
||||
return //No magical space movement!
|
||||
|
||||
if(can_move)
|
||||
can_move = 0
|
||||
switch(user.bodytemperature)
|
||||
if(300 to INFINITY)
|
||||
spawn(10) can_move = 1
|
||||
if(295 to 300)
|
||||
spawn(13) can_move = 1
|
||||
if(280 to 295)
|
||||
spawn(16) can_move = 1
|
||||
if(260 to 280)
|
||||
spawn(20) can_move = 1
|
||||
else
|
||||
spawn(25) can_move = 1
|
||||
step(src, direction)
|
||||
return
|
||||
|
||||
/obj/effect/dummy/chameleon/Destroy()
|
||||
master.disrupt(0)
|
||||
return ..()
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/item/device/doorCharge
|
||||
name = "airlock charge"
|
||||
desc = null //Different examine for traitors
|
||||
item_state = "electronic"
|
||||
icon_state = "doorCharge"
|
||||
w_class = 2
|
||||
throw_range = 4
|
||||
throw_speed = 1
|
||||
flags = NOBLUDGEON
|
||||
force = 3
|
||||
attack_verb = list("blown up", "exploded", "detonated")
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=30)
|
||||
origin_tech = "syndicate=1;combat=3;engineering=3"
|
||||
|
||||
/obj/item/device/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(1)
|
||||
if(3)
|
||||
if(prob(25))
|
||||
ex_act(1)
|
||||
|
||||
/obj/item/device/doorCharge/examine(mob/user)
|
||||
..()
|
||||
if(user.mind in ticker.mode.traitors) //No nuke ops because the device is excluded from nuclear
|
||||
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
|
||||
user << "A small, suspicious object that feels lukewarm when held."
|
||||
@@ -0,0 +1,324 @@
|
||||
/obj/item/device/flashlight
|
||||
name = "flashlight"
|
||||
desc = "A hand-held emergency light."
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "flashlight"
|
||||
item_state = "flashlight"
|
||||
w_class = 2
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=20)
|
||||
actions_types = list(/datum/action/item_action/toggle_light)
|
||||
var/on = 0
|
||||
var/brightness_on = 4 //luminosity when on
|
||||
|
||||
/obj/item/device/flashlight/initialize()
|
||||
..()
|
||||
if(on)
|
||||
icon_state = "[initial(icon_state)]-on"
|
||||
SetLuminosity(brightness_on)
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/item/device/flashlight/proc/update_brightness(mob/user = null)
|
||||
if(on)
|
||||
icon_state = "[initial(icon_state)]-on"
|
||||
if(loc == user)
|
||||
user.AddLuminosity(brightness_on)
|
||||
else if(isturf(loc))
|
||||
SetLuminosity(brightness_on)
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
if(loc == user)
|
||||
user.AddLuminosity(-brightness_on)
|
||||
else if(isturf(loc))
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/item/device/flashlight/attack_self(mob/user)
|
||||
if(!isturf(user.loc))
|
||||
user << "<span class='warning'>You cannot turn the light on while in this [user.loc]!</span>" //To prevent some lighting anomalities.
|
||||
return 0
|
||||
on = !on
|
||||
update_brightness(user)
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/item/device/flashlight/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
add_fingerprint(user)
|
||||
if(on && user.zone_selected == "eyes")
|
||||
|
||||
if((user.disabilities & CLUMSY || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly
|
||||
return ..() //just hit them in the head
|
||||
|
||||
if(!user.IsAdvancedToolUser())
|
||||
user << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = M //mob has protective eyewear
|
||||
if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags_cover & GLASSESCOVERSEYES)))
|
||||
user << "<span class='notice'>You're going to need to remove that [(H.head && H.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.</span>"
|
||||
return
|
||||
|
||||
if(M == user) //they're using it on themselves
|
||||
if(M.flash_eyes(visual = 1))
|
||||
M.visible_message("[M] directs [src] to \his eyes.", \
|
||||
"<span class='notice'>You wave the light in front of your eyes! Trippy!</span>")
|
||||
else
|
||||
M.visible_message("[M] directs [src] to \his 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>")
|
||||
var/mob/living/carbon/C = M
|
||||
if(istype(C))
|
||||
if(C.stat == DEAD || (C.disabilities & BLIND)) //mob is dead or fully blind
|
||||
user << "<span class='warning'>[C] pupils don't react to the light!</span>"
|
||||
else if(C.dna.check_mutation(XRAY)) //mob has X-RAY vision
|
||||
user << "<span class='danger'>[C] pupils give an eerie glow!</span>"
|
||||
else //they're okay!
|
||||
if(C.flash_eyes(visual = 1))
|
||||
user << "<span class='notice'>[C]'s pupils narrow.</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/device/flashlight/pickup(mob/user)
|
||||
..()
|
||||
if(on)
|
||||
user.AddLuminosity(brightness_on)
|
||||
SetLuminosity(0)
|
||||
|
||||
|
||||
/obj/item/device/flashlight/dropped(mob/user)
|
||||
..()
|
||||
if(on)
|
||||
user.AddLuminosity(-brightness_on)
|
||||
SetLuminosity(brightness_on)
|
||||
|
||||
|
||||
/obj/item/device/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 = CONDUCT
|
||||
brightness_on = 2
|
||||
var/holo_cooldown = 0
|
||||
|
||||
/obj/item/device/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag)
|
||||
if(!proximity_flag)
|
||||
if(holo_cooldown > world.time)
|
||||
user << "<span class='warning'>[src] is not ready yet!</span>"
|
||||
return
|
||||
var/T = get_turf(target)
|
||||
if(locate(/mob/living) in T)
|
||||
PoolOrNew(/obj/effect/overlay/temp/medical_holosign, list(T,user)) //produce a holographic glow
|
||||
holo_cooldown = world.time + 100
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/effect/overlay/temp/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/overlay/temp/medical_holosign/New(loc, 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/device/flashlight/seclite
|
||||
name = "seclite"
|
||||
desc = "A robust flashlight used by security."
|
||||
icon_state = "seclite"
|
||||
item_state = "seclite"
|
||||
force = 9 // Not as good as a stun baton.
|
||||
brightness_on = 5 // A little better than the standard flashlight.
|
||||
hitsound = 'sound/weapons/genhit1.ogg'
|
||||
|
||||
// the desk lamps are a bit special
|
||||
/obj/item/device/flashlight/lamp
|
||||
name = "desk lamp"
|
||||
desc = "A desk lamp with an adjustable mount."
|
||||
icon_state = "lamp"
|
||||
item_state = "lamp"
|
||||
brightness_on = 5
|
||||
w_class = 4
|
||||
flags = CONDUCT
|
||||
materials = list()
|
||||
on = 1
|
||||
|
||||
|
||||
// green-shaded desk lamp
|
||||
/obj/item/device/flashlight/lamp/green
|
||||
desc = "A classic green-shaded desk lamp."
|
||||
icon_state = "lampgreen"
|
||||
item_state = "lampgreen"
|
||||
|
||||
|
||||
|
||||
/obj/item/device/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/device/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/device/flashlight/flare
|
||||
name = "flare"
|
||||
desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
|
||||
w_class = 2
|
||||
brightness_on = 7 // Pretty bright.
|
||||
icon_state = "flare"
|
||||
item_state = "flare"
|
||||
actions_types = list()
|
||||
var/fuel = 0
|
||||
var/on_damage = 7
|
||||
var/produce_heat = 1500
|
||||
heat = 1000
|
||||
|
||||
/obj/item/device/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/device/flashlight/flare/process()
|
||||
var/turf/pos = get_turf(src)
|
||||
if(pos)
|
||||
pos.hotspot_expose(produce_heat, 5)
|
||||
fuel = max(fuel - 1, 0)
|
||||
if(!fuel || !on)
|
||||
turn_off()
|
||||
if(!fuel)
|
||||
icon_state = "[initial(icon_state)]-empty"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/flashlight/flare/proc/turn_off()
|
||||
on = 0
|
||||
force = initial(src.force)
|
||||
damtype = initial(src.damtype)
|
||||
if(ismob(loc))
|
||||
var/mob/U = loc
|
||||
update_brightness(U)
|
||||
else
|
||||
update_brightness(null)
|
||||
|
||||
/obj/item/device/flashlight/flare/update_brightness(mob/user = null)
|
||||
..()
|
||||
if(on)
|
||||
item_state = "[initial(item_state)]-on"
|
||||
else
|
||||
item_state = "[initial(item_state)]"
|
||||
|
||||
/obj/item/device/flashlight/flare/attack_self(mob/user)
|
||||
|
||||
// Usual checks
|
||||
if(!fuel)
|
||||
user << "<span class='warning'>It's out of fuel!</span>"
|
||||
return
|
||||
if(on)
|
||||
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/device/flashlight/flare/is_hot()
|
||||
return on * heat
|
||||
|
||||
/obj/item/device/flashlight/flare/torch
|
||||
name = "torch"
|
||||
desc = "A torch fashioned from some leaves and a log."
|
||||
w_class = 4
|
||||
brightness_on = 4
|
||||
icon_state = "torch"
|
||||
item_state = "torch"
|
||||
on_damage = 10
|
||||
slot_flags = null
|
||||
|
||||
/obj/item/device/flashlight/lantern
|
||||
name = "lantern"
|
||||
icon_state = "lantern"
|
||||
item_state = "lantern"
|
||||
desc = "A mining lantern."
|
||||
brightness_on = 6 // luminosity when on
|
||||
|
||||
|
||||
/obj/item/device/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 = 2
|
||||
slot_flags = SLOT_BELT
|
||||
materials = list()
|
||||
brightness_on = 6 //luminosity when on
|
||||
|
||||
/obj/item/device/flashlight/emp
|
||||
origin_tech = "magnets=3;syndicate=´1"
|
||||
var/emp_max_charges = 4
|
||||
var/emp_cur_charges = 4
|
||||
var/charge_tick = 0
|
||||
|
||||
|
||||
/obj/item/device/flashlight/emp/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/flashlight/emp/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/flashlight/emp/process()
|
||||
charge_tick++
|
||||
if(charge_tick < 10) return 0
|
||||
charge_tick = 0
|
||||
emp_cur_charges = min(emp_cur_charges+1, emp_max_charges)
|
||||
return 1
|
||||
|
||||
/obj/item/device/flashlight/emp/attack(mob/living/M, mob/living/user)
|
||||
if(on && user.zone_selected == "eyes") // call original attack proc only if aiming at the eyes
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/device/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
|
||||
add_logs(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].")
|
||||
user << "\The [src] now has [emp_cur_charges] charge\s."
|
||||
A.emp_act(1)
|
||||
else
|
||||
user << "<span class='warning'>\The [src] needs time to recharge!</span>"
|
||||
return
|
||||
@@ -0,0 +1,158 @@
|
||||
#define RAD_LEVEL_NORMAL 10
|
||||
#define RAD_LEVEL_MODERATE 30
|
||||
#define RAD_LEVEL_HIGH 75
|
||||
#define RAD_LEVEL_VERY_HIGH 125
|
||||
#define RAD_LEVEL_CRITICAL 200
|
||||
|
||||
/obj/item/device/geiger_counter //DISCLAIMER: I know nothing about how real-life Geiger counters work. This will not be realistic. ~Xhuis
|
||||
name = "geiger counter"
|
||||
desc = "A handheld device used for detecting and measuring radiation pulses."
|
||||
icon_state = "geiger_off"
|
||||
item_state = "multitool"
|
||||
w_class = 2
|
||||
slot_flags = SLOT_BELT
|
||||
materials = list(MAT_METAL = 150, MAT_GLASS = 150)
|
||||
var/scanning = 0
|
||||
var/radiation_count = 0
|
||||
var/emagged = 0
|
||||
|
||||
/obj/item/device/geiger_counter/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/geiger_counter/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
..()
|
||||
|
||||
/obj/item/device/geiger_counter/process()
|
||||
if(emagged)
|
||||
if(radiation_count < 20)
|
||||
radiation_count++
|
||||
return 0
|
||||
if(radiation_count > 0)
|
||||
radiation_count--
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/geiger_counter/examine(mob/user)
|
||||
..()
|
||||
if(!scanning)
|
||||
return 1
|
||||
user << "<span class='info'>Alt-click it to clear stored radiation levels.</span>"
|
||||
if(emagged)
|
||||
user << "<span class='warning'>The display seems to be incomprehensible.</span>"
|
||||
return 1
|
||||
switch(radiation_count)
|
||||
if(-INFINITY to RAD_LEVEL_NORMAL)
|
||||
user << "<span class='notice'>Ambient radiation level count reports that all is well.</span>"
|
||||
if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
|
||||
user << "<span class='disarm'>Ambient radiation levels slightly above average.</span>"
|
||||
if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
|
||||
user << "<span class='warning'>Ambient radiation levels above average.</span>"
|
||||
if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
|
||||
user << "<span class='danger'>Ambient radiation levels highly above average.</span>"
|
||||
if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
|
||||
user << "<span class='suicide'>Ambient radiation levels nearing critical level.</span>"
|
||||
if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
|
||||
user << "<span class='boldannounce'>Ambient radiation levels above critical level!</span>"
|
||||
|
||||
/obj/item/device/geiger_counter/update_icon()
|
||||
if(!scanning)
|
||||
icon_state = "geiger_off"
|
||||
return 1
|
||||
if(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/device/geiger_counter/rad_act(amount)
|
||||
if(!amount && scanning)
|
||||
return 0
|
||||
if(emagged)
|
||||
amount = Clamp(amount, 0, 25) //Emagged geiger counters can only accept 25 radiation at a time
|
||||
radiation_count += amount
|
||||
if(isliving(loc))
|
||||
var/mob/living/M = loc
|
||||
if(!emagged)
|
||||
M << "<span class='boldannounce'>\icon[src] RADIATION PULSE DETECTED.</span>"
|
||||
M << "<span class='boldannounce'>\icon[src] Severity: [amount]</span>"
|
||||
else
|
||||
M << "<span class='boldannounce'>\icon[src] !@%$AT!(N P!LS! D/TEC?ED.</span>"
|
||||
M << "<span class='boldannounce'>\icon[src] &!F2rity: <=[amount]#1</span>"
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/geiger_counter/attack_self(mob/user)
|
||||
scanning = !scanning
|
||||
update_icon()
|
||||
user << "<span class='notice'>\icon[src] You switch [scanning ? "on" : "off"] [src].</span>"
|
||||
|
||||
/obj/item/device/geiger_counter/attack(mob/living/M, mob/user)
|
||||
if(user.a_intent == "help")
|
||||
if(!emagged)
|
||||
user.visible_message("<span class='notice'>[user] scans [M] with [src].</span>", "<span class='notice'>You scan [M]'s radiation levels with [src]...</span>")
|
||||
if(!M.radiation)
|
||||
user << "<span class='notice'>\icon[src] Radiation levels within normal boundaries.</span>"
|
||||
return 1
|
||||
else
|
||||
user << "<span class='boldannounce'>\icon[src] Subject is irradiated. Radiation levels: [M.radiation].</span>"
|
||||
return 1
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] scans [M] with [src].</span>", "<span class='danger'>You project [src]'s stored radiation into [M]'s body!</span>")
|
||||
M.rad_act(radiation_count)
|
||||
radiation_count = 0
|
||||
return 1
|
||||
..()
|
||||
|
||||
/obj/item/device/geiger_counter/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/screwdriver) && emagged)
|
||||
if(scanning)
|
||||
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>")
|
||||
playsound(user, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
if(!do_after(user, 40/I.toolspeed, target = user))
|
||||
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>")
|
||||
playsound(user, 'sound/items/Screwdriver2.ogg', 50, 1)
|
||||
emagged = 0
|
||||
radiation_count = 0
|
||||
update_icon()
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/geiger_counter/AltClick(mob/living/user)
|
||||
if(!istype(user) || user.incapacitated())
|
||||
return ..()
|
||||
if(!scanning)
|
||||
usr << "<span class='warning'>[src] must be on to reset its radiation level!</span>"
|
||||
return 0
|
||||
radiation_count = 0
|
||||
usr << "<span class='notice'>You flush [src]'s radiation counts, resetting it to normal.</span>"
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/geiger_counter/emag_act(mob/user)
|
||||
if(!emagged)
|
||||
if(scanning)
|
||||
user << "<span class='warning'>Turn off [src] before you perform this action!</span>"
|
||||
return 0
|
||||
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>"
|
||||
emagged = 1
|
||||
|
||||
#undef RAD_LEVEL_NORMAL
|
||||
#undef RAD_LEVEL_MODERATE
|
||||
#undef RAD_LEVEL_HIGH
|
||||
#undef RAD_LEVEL_VERY_HIGH
|
||||
#undef RAD_LEVEL_CRITICAL
|
||||
@@ -0,0 +1,73 @@
|
||||
//copy pasta of the space piano, don't hurt me -Pete
|
||||
/obj/item/device/instrument
|
||||
name = "generic instrument"
|
||||
burn_state = FLAMMABLE
|
||||
burntime = 20
|
||||
var/datum/song/handheld/song
|
||||
var/instrumentId = "generic"
|
||||
var/instrumentExt = "ogg"
|
||||
|
||||
/obj/item/device/instrument/New()
|
||||
song = new(instrumentId, src)
|
||||
song.instrumentExt = instrumentExt
|
||||
|
||||
/obj/item/device/instrument/Destroy()
|
||||
qdel(song)
|
||||
song = null
|
||||
return ..()
|
||||
|
||||
/obj/item/device/instrument/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins to play 'Gloomy Sunday'! It looks like \he's trying to commit suicide..</span>")
|
||||
return (BRUTELOSS)
|
||||
|
||||
/obj/item/device/instrument/initialize()
|
||||
song.tempo = song.sanitize_tempo(song.tempo) // tick_lag isn't set when the map is loaded
|
||||
..()
|
||||
|
||||
/obj/item/device/instrument/attack_self(mob/user)
|
||||
if(!user.IsAdvancedToolUser())
|
||||
user << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
||||
return 1
|
||||
interact(user)
|
||||
|
||||
/obj/item/device/instrument/interact(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
if(!isliving(user) || user.stat || user.restrained() || user.lying)
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
song.interact(user)
|
||||
|
||||
/obj/item/device/instrument/violin
|
||||
name = "space violin"
|
||||
desc = "A wooden musical instrument with four strings and a bow. \"The devil went down to space, he was looking for an assistant to grief.\""
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "violin"
|
||||
item_state = "violin"
|
||||
force = 10
|
||||
hitsound = "swing_hit"
|
||||
instrumentId = "violin"
|
||||
|
||||
/obj/item/device/instrument/guitar
|
||||
name = "guitar"
|
||||
desc = "It's made of wood and has bronze strings."
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "guitar"
|
||||
item_state = "guitar"
|
||||
force = 10
|
||||
attack_verb = list("played metal on", "serenaded", "crashed", "smashed")
|
||||
hitsound = 'sound/weapons/stringsmash.ogg'
|
||||
instrumentId = "guitar"
|
||||
|
||||
/obj/item/device/instrument/eguitar
|
||||
name = "eletric guitar"
|
||||
desc = "Makes all your shredding needs possible."
|
||||
icon = 'icons/obj/musician.dmi'
|
||||
icon_state = "eguitar"
|
||||
item_state = "eguitar"
|
||||
force = 12
|
||||
attack_verb = list("played metal on", "shredded", "crashed", "smashed")
|
||||
hitsound = 'sound/weapons/stringsmash.ogg'
|
||||
instrumentId = "eguitar"
|
||||
@@ -0,0 +1,172 @@
|
||||
/obj/item/device/laser_pointer
|
||||
name = "laser pointer"
|
||||
desc = "Don't shine it in your eyes!"
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "pointer"
|
||||
item_state = "pen"
|
||||
var/pointer_icon_state
|
||||
flags = CONDUCT | NOBLUDGEON
|
||||
slot_flags = SLOT_BELT
|
||||
materials = list(MAT_METAL=500, MAT_GLASS=500)
|
||||
w_class = 2 //Increased to 2, because diodes are w_class 2. Conservation of matter.
|
||||
origin_tech = "combat=1;magnets=2"
|
||||
var/turf/pointer_loc
|
||||
var/energy = 5
|
||||
var/max_energy = 5
|
||||
var/effectchance = 33
|
||||
var/recharging = 0
|
||||
var/recharge_locked = 0
|
||||
var/obj/item/weapon/stock_parts/micro_laser/diode //used for upgrading!
|
||||
|
||||
|
||||
/obj/item/device/laser_pointer/red
|
||||
pointer_icon_state = "red_laser"
|
||||
/obj/item/device/laser_pointer/green
|
||||
pointer_icon_state = "green_laser"
|
||||
/obj/item/device/laser_pointer/blue
|
||||
pointer_icon_state = "blue_laser"
|
||||
/obj/item/device/laser_pointer/purple
|
||||
pointer_icon_state = "purple_laser"
|
||||
|
||||
/obj/item/device/laser_pointer/New()
|
||||
..()
|
||||
diode = new(src)
|
||||
if(!pointer_icon_state)
|
||||
pointer_icon_state = pick("red_laser","green_laser","blue_laser","purple_laser")
|
||||
|
||||
/obj/item/device/laser_pointer/upgraded/New()
|
||||
..()
|
||||
diode = new /obj/item/weapon/stock_parts/micro_laser/ultra
|
||||
|
||||
/obj/item/device/laser_pointer/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/stock_parts/micro_laser))
|
||||
if(!diode)
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
diode = W
|
||||
user << "<span class='notice'>You install a [diode.name] in [src].</span>"
|
||||
else
|
||||
user << "<span class='notice'>[src] already has a diode installed.</span>"
|
||||
|
||||
else if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(diode)
|
||||
user << "<span class='notice'>You remove the [diode.name] from \the [src].</span>"
|
||||
diode.loc = get_turf(src.loc)
|
||||
diode = null
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/laser_pointer/afterattack(atom/target, mob/living/user, flag, params)
|
||||
laser_act(target, user, params)
|
||||
|
||||
/obj/item/device/laser_pointer/proc/laser_act(atom/target, mob/living/user, params)
|
||||
if( !(user in (viewers(7,target))) )
|
||||
return
|
||||
if (!diode)
|
||||
user << "<span class='notice'>You point [src] at [target], but nothing happens!</span>"
|
||||
return
|
||||
if (!user.IsAdvancedToolUser())
|
||||
user << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
||||
return
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.dna.check_mutation(HULK) || (NOGUNS in H.dna.species.specflags))
|
||||
user << "<span class='warning'>Your fingers can't press the button!</span>"
|
||||
return
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
//nothing happens if the battery is drained
|
||||
if(recharge_locked)
|
||||
user << "<span class='notice'>You point [src] at [target], but it's still charging.</span>"
|
||||
return
|
||||
|
||||
var/outmsg
|
||||
var/turf/targloc = get_turf(target)
|
||||
|
||||
//human/alien mobs
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(user.zone_selected == "eyes")
|
||||
add_logs(user, C, "shone in the eyes", src)
|
||||
|
||||
var/severity = 1
|
||||
if(prob(33))
|
||||
severity = 2
|
||||
else if(prob(50))
|
||||
severity = 0
|
||||
|
||||
//20% chance to actually hit the eyes
|
||||
if(prob(effectchance * diode.rating) && C.flash_eyes(severity))
|
||||
outmsg = "<span class='notice'>You blind [C] by shining [src] in their eyes.</span>"
|
||||
if(C.weakeyes)
|
||||
C.Stun(1)
|
||||
else
|
||||
outmsg = "<span class='warning'>You fail to blind [C] by shining [src] at their eyes!</span>"
|
||||
|
||||
//robots
|
||||
else if(isrobot(target))
|
||||
var/mob/living/silicon/S = target
|
||||
//20% chance to actually hit the sensors
|
||||
if(prob(effectchance * diode.rating))
|
||||
S.flash_eyes(affect_silicon = 1)
|
||||
S.Weaken(rand(5,10))
|
||||
S << "<span class='danger'>Your sensors were overloaded by a laser!</span>"
|
||||
outmsg = "<span class='notice'>You overload [S] by shining [src] at their sensors.</span>"
|
||||
add_logs(user, S, "shone in the sensors", src)
|
||||
else
|
||||
outmsg = "<span class='warning'>You fail to overload [S] by shining [src] at their sensors!</span>"
|
||||
|
||||
//cameras
|
||||
else if(istype(target, /obj/machinery/camera))
|
||||
var/obj/machinery/camera/C = target
|
||||
if(prob(effectchance * diode.rating))
|
||||
C.emp_act(1)
|
||||
outmsg = "<span class='notice'>You hit the lens of [C] with [src], temporarily disabling the camera!</span>"
|
||||
add_logs(user, C, "EMPed", src)
|
||||
else
|
||||
outmsg = "<span class='warning'>You miss the lens of [C] with [src]!</span>"
|
||||
|
||||
//laser pointer image
|
||||
icon_state = "pointer_[pointer_icon_state]"
|
||||
var/list/showto = list()
|
||||
for(var/mob/M in viewers(7,targloc))
|
||||
if(M.client)
|
||||
showto.Add(M.client)
|
||||
var/image/I = image('icons/obj/projectiles.dmi',targloc,pointer_icon_state,10)
|
||||
var/list/click_params = params2list(params)
|
||||
if(click_params)
|
||||
if(click_params["icon-x"])
|
||||
I.pixel_x = (text2num(click_params["icon-x"]) - 16)
|
||||
if(click_params["icon-y"])
|
||||
I.pixel_y = (text2num(click_params["icon-y"]) - 16)
|
||||
else
|
||||
I.pixel_x = target.pixel_x + rand(-5,5)
|
||||
I.pixel_y = target.pixel_y + rand(-5,5)
|
||||
|
||||
if(outmsg)
|
||||
user << outmsg
|
||||
else
|
||||
user << "<span class='info'>You point [src] at [target].</span>"
|
||||
|
||||
energy -= 1
|
||||
if(energy <= max_energy)
|
||||
if(!recharging)
|
||||
recharging = 1
|
||||
START_PROCESSING(SSobj, src)
|
||||
if(energy <= 0)
|
||||
user << "<span class='warning'>[src]'s battery is overused, it needs time to recharge!</span>"
|
||||
recharge_locked = 1
|
||||
|
||||
flick_overlay(I, showto, 10)
|
||||
icon_state = "pointer"
|
||||
|
||||
/obj/item/device/laser_pointer/process()
|
||||
if(prob(20 - recharge_locked*5))
|
||||
energy += 1
|
||||
if(energy >= max_energy)
|
||||
energy = max_energy
|
||||
recharging = 0
|
||||
recharge_locked = 0
|
||||
..()
|
||||
@@ -0,0 +1,264 @@
|
||||
|
||||
// Light Replacer (LR)
|
||||
//
|
||||
// ABOUT THE DEVICE
|
||||
//
|
||||
// This is a device supposedly to be used by Janitors and Janitor Cyborgs which will
|
||||
// allow them to easily replace lights. This was mostly designed for Janitor Cyborgs since
|
||||
// they don't have hands or a way to replace lightbulbs.
|
||||
//
|
||||
// HOW IT WORKS
|
||||
//
|
||||
// You attack a light fixture with it, if the light fixture is broken it will replace the
|
||||
// light fixture with a working light; the broken light is then placed on the floor for the
|
||||
// user to then pickup with a trash bag. If it's empty then it will just place a light in the fixture.
|
||||
//
|
||||
// HOW TO REFILL THE DEVICE
|
||||
//
|
||||
// It will need to be manually refilled with lights.
|
||||
// If it's part of a robot module, it will charge when the Robot is inside a Recharge Station.
|
||||
//
|
||||
// EMAGGED FEATURES
|
||||
//
|
||||
// NOTICE: The Cyborg cannot use the emagged Light Replacer and the light's explosion was nerfed. It cannot create holes in the station anymore.
|
||||
//
|
||||
// I'm not sure everyone will react the emag's features so please say what your opinions are of it.
|
||||
//
|
||||
// When emagged it will rig every light it replaces, which will explode when the light is on.
|
||||
// This is VERY noticable, even the device's name changes when you emag it so if anyone
|
||||
// examines you when you're holding it in your hand, you will be discovered.
|
||||
// It will also be very obvious who is setting all these lights off, since only Janitor Borgs and Janitors have easy
|
||||
// access to them, and only one of them can emag their device.
|
||||
//
|
||||
// The explosion cannot insta-kill anyone with 30% or more health.
|
||||
|
||||
#define LIGHT_OK 0
|
||||
#define LIGHT_EMPTY 1
|
||||
#define LIGHT_BROKEN 2
|
||||
#define LIGHT_BURNED 3
|
||||
|
||||
|
||||
/obj/item/device/lightreplacer
|
||||
|
||||
name = "light replacer"
|
||||
desc = "A device to automatically replace lights. Refill with broken or working lightbulbs, or sheets of glass."
|
||||
|
||||
icon = 'icons/obj/janitor.dmi'
|
||||
icon_state = "lightreplacer0"
|
||||
item_state = "electronic"
|
||||
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
origin_tech = "magnets=3;engineering=4"
|
||||
|
||||
var/max_uses = 20
|
||||
var/uses = 0
|
||||
var/emagged = 0
|
||||
var/failmsg = ""
|
||||
// How much to increase per each glass?
|
||||
var/increment = 5
|
||||
// How much to take from the glass?
|
||||
var/decrement = 1
|
||||
var/charge = 1
|
||||
|
||||
// Eating used bulbs gives us bulb shards
|
||||
var/bulb_shards = 0
|
||||
// when we get this many shards, we get a free bulb.
|
||||
var/shards_required = 4
|
||||
|
||||
/obj/item/device/lightreplacer/New()
|
||||
uses = max_uses / 2
|
||||
failmsg = "The [name]'s refill light blinks red."
|
||||
..()
|
||||
|
||||
/obj/item/device/lightreplacer/examine(mob/user)
|
||||
..()
|
||||
user << status_string()
|
||||
|
||||
/obj/item/device/lightreplacer/attackby(obj/item/W, mob/user, params)
|
||||
|
||||
if(istype(W, /obj/item/stack/sheet/glass))
|
||||
var/obj/item/stack/sheet/glass/G = W
|
||||
if(uses >= max_uses)
|
||||
user << "<span class='warning'>[src.name] is full.</span>"
|
||||
return
|
||||
else if(G.use(decrement))
|
||||
AddUses(increment)
|
||||
user << "<span class='notice'>You insert a piece of glass into the [src.name]. You have [uses] light\s remaining.</span>"
|
||||
return
|
||||
else
|
||||
user << "<span class='warning'>You need one sheet of glass to replace lights!</span>"
|
||||
|
||||
if(istype(W, /obj/item/weapon/light))
|
||||
var/new_bulbs = 0
|
||||
var/obj/item/weapon/light/L = W
|
||||
if(L.status == 0) // LIGHT OKAY
|
||||
if(uses < max_uses)
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
AddUses(1)
|
||||
qdel(L)
|
||||
else
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
new_bulbs += AddShards(1)
|
||||
qdel(L)
|
||||
if(new_bulbs != 0)
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
user << "<span class='notice'>You insert the [L.name] into the [src.name]. " + status_string() + "</span>"
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/storage))
|
||||
var/obj/item/weapon/storage/S = W
|
||||
var/found_lightbulbs = FALSE
|
||||
var/replaced_something = TRUE
|
||||
|
||||
for(var/obj/item/I in S.contents)
|
||||
if(istype(I,/obj/item/weapon/light))
|
||||
var/obj/item/weapon/light/L = I
|
||||
found_lightbulbs = TRUE
|
||||
if(src.uses >= max_uses)
|
||||
break
|
||||
if(L.status == LIGHT_OK)
|
||||
replaced_something = TRUE
|
||||
AddUses(1)
|
||||
qdel(L)
|
||||
|
||||
else if(L.status == LIGHT_BROKEN || L.status == LIGHT_BURNED)
|
||||
replaced_something = TRUE
|
||||
AddShards(1)
|
||||
qdel(L)
|
||||
|
||||
if(!found_lightbulbs)
|
||||
user << "<span class='warning'>\The [S] contains no bulbs.</span>"
|
||||
return
|
||||
|
||||
if(!replaced_something && src.uses == max_uses)
|
||||
user << "<span class='warning'>\The [src] is full!</span>"
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You fill \the [src] with lights from \the [S]. " + status_string() + "</span>"
|
||||
|
||||
/obj/item/device/lightreplacer/emag_act()
|
||||
if(!emagged)
|
||||
Emag()
|
||||
|
||||
/obj/item/device/lightreplacer/attack_self(mob/user)
|
||||
user << status_string()
|
||||
|
||||
|
||||
/obj/item/device/lightreplacer/update_icon()
|
||||
icon_state = "lightreplacer[emagged]"
|
||||
|
||||
/obj/item/device/lightreplacer/proc/status_string()
|
||||
return "It has [uses] light\s remaining (plus [bulb_shards] fragment\s)."
|
||||
|
||||
/obj/item/device/lightreplacer/proc/Use(mob/user)
|
||||
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
AddUses(-1)
|
||||
return 1
|
||||
|
||||
// Negative numbers will subtract
|
||||
/obj/item/device/lightreplacer/proc/AddUses(amount = 1)
|
||||
uses = Clamp(uses + amount, 0, max_uses)
|
||||
|
||||
/obj/item/device/lightreplacer/proc/AddShards(amount = 1)
|
||||
bulb_shards += amount
|
||||
var/new_bulbs = round(bulb_shards / shards_required)
|
||||
if(new_bulbs > 0)
|
||||
AddUses(new_bulbs)
|
||||
bulb_shards = bulb_shards % shards_required
|
||||
return new_bulbs
|
||||
|
||||
/obj/item/device/lightreplacer/proc/Charge(var/mob/user)
|
||||
charge += 1
|
||||
if(charge > 3)
|
||||
AddUses(1)
|
||||
charge = 1
|
||||
|
||||
/obj/item/device/lightreplacer/proc/ReplaceLight(obj/machinery/light/target, mob/living/U)
|
||||
|
||||
if(target.status != LIGHT_OK)
|
||||
if(CanUse(U))
|
||||
if(!Use(U)) return
|
||||
U << "<span class='notice'>You replace the [target.fitting] with \the [src].</span>"
|
||||
|
||||
if(target.status != LIGHT_EMPTY)
|
||||
var/new_bulbs = AddShards(1)
|
||||
if(new_bulbs != 0)
|
||||
U << "<span class='notice'>\The [src] has fabricated a new bulb from the broken bulbs it has stored. It now has [uses] uses.</span>"
|
||||
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
|
||||
target.status = LIGHT_EMPTY
|
||||
target.update()
|
||||
|
||||
var/obj/item/weapon/light/L2 = new target.light_type()
|
||||
|
||||
target.status = L2.status
|
||||
target.switchcount = L2.switchcount
|
||||
target.rigged = emagged
|
||||
target.brightness = L2.brightness
|
||||
target.on = target.has_power()
|
||||
target.update()
|
||||
qdel(L2)
|
||||
|
||||
if(target.on && target.rigged)
|
||||
target.explode()
|
||||
return
|
||||
|
||||
else
|
||||
U << failmsg
|
||||
return
|
||||
else
|
||||
U << "<span class='warning'>There is a working [target.fitting] already inserted!</span>"
|
||||
return
|
||||
|
||||
/obj/item/device/lightreplacer/proc/Emag()
|
||||
emagged = !emagged
|
||||
playsound(src.loc, "sparks", 100, 1)
|
||||
if(emagged)
|
||||
name = "shortcircuited [initial(name)]"
|
||||
else
|
||||
name = initial(name)
|
||||
update_icon()
|
||||
|
||||
//Can you use it?
|
||||
|
||||
/obj/item/device/lightreplacer/proc/CanUse(mob/living/user)
|
||||
src.add_fingerprint(user)
|
||||
//Not sure what else to check for. Maybe if clumsy?
|
||||
if(uses > 0)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/item/device/lightreplacer/afterattack(atom/T, mob/U, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(!isturf(T))
|
||||
return
|
||||
|
||||
var/used = FALSE
|
||||
for(var/atom/A in T)
|
||||
if(!CanUse(U))
|
||||
break
|
||||
used = TRUE
|
||||
if(istype(A, /obj/machinery/light))
|
||||
ReplaceLight(A, U)
|
||||
|
||||
if(!used)
|
||||
U << failmsg
|
||||
|
||||
/obj/item/device/lightreplacer/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
|
||||
J.put_in_cart(src, user)
|
||||
J.myreplacer = src
|
||||
J.update_icon()
|
||||
|
||||
/obj/item/device/lightreplacer/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
|
||||
return
|
||||
|
||||
#undef LIGHT_OK
|
||||
#undef LIGHT_EMPTY
|
||||
#undef LIGHT_BROKEN
|
||||
#undef LIGHT_BURNED
|
||||
@@ -0,0 +1,7 @@
|
||||
/obj/item/device/machineprototype
|
||||
name = "machine prototype"
|
||||
desc = "A complicated machine prototype. You have no idea how it works."
|
||||
icon = 'icons/obj/machineprototype.dmi'
|
||||
icon_state = "machineprototype"
|
||||
materials = list(MAT_METAL=1000, MAT_GLASS=500)
|
||||
origin_tech = "engineering=6"
|
||||
@@ -0,0 +1,74 @@
|
||||
/obj/item/device/megaphone
|
||||
name = "megaphone"
|
||||
desc = "A device used to project your voice. Loudly."
|
||||
icon_state = "megaphone"
|
||||
item_state = "radio"
|
||||
w_class = 2
|
||||
flags = FPRINT
|
||||
siemens_coefficient = 1
|
||||
|
||||
var/spamcheck = 0
|
||||
var/emagged = 0
|
||||
var/insults = 0
|
||||
var/voicespan = "command_headset" // sic
|
||||
var/list/insultmsg = list("FUCK EVERYONE!", "DEATH TO LIZARDS!", "ALL SECURITY TO SHOOT ME ON SIGHT!", "I HAVE A BOMB!", "CAPTAIN IS A COMDOM!", "FOR THE SYNDICATE!", "VIVA!", "HONK!")
|
||||
|
||||
/obj/item/device/megaphone/attack_self(mob/living/carbon/human/user)
|
||||
if(user.client)
|
||||
if(user.client.prefs.muted & MUTE_IC)
|
||||
src << "<span class='warning'>You cannot speak in IC (muted).</span>"
|
||||
return
|
||||
|
||||
if(!ishuman(user))
|
||||
user << "<span class='warning'>You don't know how to use this!</span>"
|
||||
return
|
||||
|
||||
if(spamcheck > world.time)
|
||||
user << "<span class='warning'>\The [src] needs to recharge!</span>"
|
||||
return
|
||||
|
||||
var/message = copytext(sanitize(input(user, "Shout a message?", "Megaphone", null) as text),1,MAX_MESSAGE_LEN)
|
||||
if(!message)
|
||||
return
|
||||
|
||||
message = capitalize(message)
|
||||
if(!user.can_speak(message))
|
||||
user << "<span class='warning'>You find yourself unable to speak at all!</span>"
|
||||
return
|
||||
|
||||
if ((src.loc == user && user.stat == 0))
|
||||
if(emagged)
|
||||
if(insults)
|
||||
user.say(pick(insultmsg),"machine", list(voicespan))
|
||||
insults--
|
||||
else
|
||||
user << "<span class='warning'>*BZZZZzzzzzt*</span>"
|
||||
else
|
||||
user.say(message,"machine", list(voicespan))
|
||||
|
||||
playsound(loc, 'sound/items/megaphone.ogg', 100, 0, 1)
|
||||
spamcheck = world.time + 50
|
||||
return
|
||||
|
||||
/obj/item/device/megaphone/emag_act(mob/user)
|
||||
user << "<span class='warning'>You overload \the [src]'s voice synthesizer.</span>"
|
||||
emagged = 1
|
||||
insults = rand(1, 3) //to prevent dickflooding
|
||||
|
||||
/obj/item/device/megaphone/sec
|
||||
name = "security megaphone"
|
||||
icon_state = "megaphone-sec"
|
||||
|
||||
/obj/item/device/megaphone/command
|
||||
name = "command megaphone"
|
||||
icon_state = "megaphone-command"
|
||||
|
||||
/obj/item/device/megaphone/cargo
|
||||
name = "supply megaphone"
|
||||
icon_state = "megaphone-cargo"
|
||||
|
||||
/obj/item/device/megaphone/clown
|
||||
name = "clown's megaphone"
|
||||
desc = "Something that should not exist."
|
||||
icon_state = "megaphone-clown"
|
||||
voicespan = "clown"
|
||||
@@ -0,0 +1,35 @@
|
||||
/obj/item/modkit
|
||||
name = "modification kit"
|
||||
desc = "A one-use kit, which enables kinetic accelerators to retain their \
|
||||
charge when away from a bioelectric source, renders them immune to \
|
||||
interference with other accelerators, as well as allowing less \
|
||||
dextrous races to use the tool."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "modkit"
|
||||
origin_tech = "programming=2;materials=2;magnets=4"
|
||||
var/uses = 1
|
||||
|
||||
/obj/item/modkit/afterattack(obj/item/weapon/gun/energy/kinetic_accelerator/C, mob/user)
|
||||
..()
|
||||
if(!uses)
|
||||
qdel(src)
|
||||
return
|
||||
if(!istype(C))
|
||||
user << "<span class='warning'>This kit can only modify kinetic \
|
||||
accelerators!</span>"
|
||||
return ..()
|
||||
// RIP the 'improved improved improved improved kinetic accelerator
|
||||
if(C.holds_charge && C.unique_frequency)
|
||||
user << "<span class='warning'>This kinetic accelerator already has \
|
||||
these upgrades.</span>"
|
||||
return ..()
|
||||
|
||||
user <<"<span class='notice'>You modify the [C], adjusting the trigger \
|
||||
guard and internal capacitor.</span>"
|
||||
C.name = "improved [C.name]"
|
||||
C.holds_charge = TRUE
|
||||
C.unique_frequency = TRUE
|
||||
C.trigger_guard = TRIGGER_GUARD_ALLOW_ALL
|
||||
uses--
|
||||
if(!uses)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,92 @@
|
||||
#define PROXIMITY_NONE ""
|
||||
#define PROXIMITY_ON_SCREEN "_red"
|
||||
#define PROXIMITY_NEAR "_yellow"
|
||||
|
||||
/**
|
||||
* Multitool -- A multitool is used for hacking electronic devices.
|
||||
* TO-DO -- Using it as a power measurement tool for cables etc. Nannek.
|
||||
*
|
||||
*/
|
||||
|
||||
/obj/item/device/multitool
|
||||
name = "multitool"
|
||||
desc = "Used for pulsing wires to test which to cut. Not recommended by doctors."
|
||||
icon_state = "multitool"
|
||||
force = 5
|
||||
w_class = 2
|
||||
throwforce = 0
|
||||
throw_range = 7
|
||||
throw_speed = 3
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=20)
|
||||
origin_tech = "magnets=1;engineering=2"
|
||||
var/obj/machinery/buffer // simple machine buffer for device linkage
|
||||
hitsound = 'sound/weapons/tap.ogg'
|
||||
toolspeed = 1
|
||||
|
||||
|
||||
// Syndicate device disguised as a multitool; it will turn red when an AI camera is nearby.
|
||||
|
||||
|
||||
/obj/item/device/multitool/ai_detect
|
||||
var/track_cooldown = 0
|
||||
var/track_delay = 10 //How often it checks for proximity
|
||||
var/detect_state = PROXIMITY_NONE
|
||||
var/rangealert = 8 //Glows red when inside
|
||||
var/rangewarning = 20 //Glows yellow when inside
|
||||
origin_tech = "magnets=1;engineering=2;syndicate=1"
|
||||
|
||||
/obj/item/device/multitool/ai_detect/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/multitool/ai_detect/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/multitool/ai_detect/process()
|
||||
if(track_cooldown > world.time)
|
||||
return
|
||||
detect_state = PROXIMITY_NONE
|
||||
multitool_detect()
|
||||
icon_state = "[initial(icon_state)][detect_state]"
|
||||
track_cooldown = world.time + track_delay
|
||||
|
||||
/obj/item/device/multitool/ai_detect/proc/multitool_detect()
|
||||
var/turf/our_turf = get_turf(src)
|
||||
for(var/mob/living/silicon/ai/AI in ai_list)
|
||||
if(AI.cameraFollow == src)
|
||||
detect_state = PROXIMITY_ON_SCREEN
|
||||
break
|
||||
|
||||
if(!detect_state && cameranet.chunkGenerated(our_turf.x, our_turf.y, our_turf.z))
|
||||
var/datum/camerachunk/chunk = cameranet.getCameraChunk(our_turf.x, our_turf.y, our_turf.z)
|
||||
if(chunk)
|
||||
if(chunk.seenby.len)
|
||||
for(var/mob/camera/aiEye/A in chunk.seenby)
|
||||
var/turf/detect_turf = get_turf(A)
|
||||
if(get_dist(our_turf, detect_turf) < rangealert)
|
||||
detect_state = PROXIMITY_ON_SCREEN
|
||||
break
|
||||
if(get_dist(our_turf, detect_turf) < rangewarning)
|
||||
detect_state = PROXIMITY_NEAR
|
||||
break
|
||||
|
||||
/obj/item/device/multitool/ai_detect/admin
|
||||
desc = "Used for pulsing wires to test which to cut. Not recommended by doctors. Has a strange tag that says 'Grief in Safety'" //What else should I say for a meme item?
|
||||
track_delay = 5
|
||||
|
||||
/obj/item/device/multitool/ai_detect/admin/multitool_detect()
|
||||
var/turf/our_turf = get_turf(src)
|
||||
for(var/mob/J in urange(rangewarning,our_turf))
|
||||
if(admin_datums[J.ckey])
|
||||
detect_state = PROXIMITY_NEAR
|
||||
var/turf/detect_turf = get_turf(J)
|
||||
if(get_dist(our_turf, detect_turf) < rangealert)
|
||||
detect_state = PROXIMITY_ON_SCREEN
|
||||
break
|
||||
|
||||
/obj/item/device/multitool/cyborg
|
||||
name = "multitool"
|
||||
desc = "Optimised and stripped-down version of a regular multitool."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
toolspeed = 2
|
||||
@@ -0,0 +1,140 @@
|
||||
/obj/item/device/paicard
|
||||
name = "personal AI device"
|
||||
icon = 'icons/obj/aicards.dmi'
|
||||
icon_state = "pai"
|
||||
item_state = "electronic"
|
||||
w_class = 2
|
||||
slot_flags = SLOT_BELT
|
||||
origin_tech = "programming=2"
|
||||
var/obj/item/device/radio/radio
|
||||
var/looking_for_personality = 0
|
||||
var/mob/living/silicon/pai/pai
|
||||
|
||||
/obj/item/device/paicard/New()
|
||||
..()
|
||||
add_overlay("pai-off")
|
||||
|
||||
/obj/item/device/paicard/Destroy()
|
||||
//Will stop people throwing friend pAIs into the singularity so they can respawn
|
||||
if(!isnull(pai))
|
||||
pai.death(0)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/paicard/attack_self(mob/user)
|
||||
if (!in_range(src, user))
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = "<TT><B>Personal AI Device</B><BR>"
|
||||
if(pai && (!pai.master_dna || !pai.master))
|
||||
dat += "<a href='byond://?src=\ref[src];setdna=1'>Imprint Master DNA</a><br>"
|
||||
if(pai)
|
||||
dat += "Installed Personality: [pai.name]<br>"
|
||||
dat += "Prime directive: <br>[pai.laws.zeroth]<br>"
|
||||
for(var/slaws in pai.laws.supplied)
|
||||
dat += "Additional directives: <br>[slaws]<br>"
|
||||
dat += "<a href='byond://?src=\ref[src];setlaws=1'>Configure Directives</a><br>"
|
||||
dat += "<br>"
|
||||
dat += "<h3>Device Settings</h3><br>"
|
||||
if(radio)
|
||||
dat += "<b>Radio Uplink</b><br>"
|
||||
dat += "Transmit: <A href='byond://?src=\ref[src];wires=[WIRE_TX]'>[(radio.wires.is_cut(WIRE_TX)) ? "Disabled" : "Enabled"]</A><br>"
|
||||
dat += "Receive: <A href='byond://?src=\ref[src];wires=[WIRE_RX]'>[(radio.wires.is_cut(WIRE_RX)) ? "Disabled" : "Enabled"]</A><br>"
|
||||
else
|
||||
dat += "<b>Radio Uplink</b><br>"
|
||||
dat += "<font color=red><i>Radio firmware not loaded. Please install a pAI personality to load firmware.</i></font><br>"
|
||||
dat += "<A href='byond://?src=\ref[src];wipe=1'>\[Wipe current pAI personality\]</a><br>"
|
||||
else
|
||||
if(looking_for_personality)
|
||||
dat += "Searching for a personality..."
|
||||
dat += "<A href='byond://?src=\ref[src];request=1'>\[View available personalities\]</a><br>"
|
||||
else
|
||||
dat += "No personality is installed.<br>"
|
||||
dat += "<A href='byond://?src=\ref[src];request=1'>\[Request personal AI personality\]</a><br>"
|
||||
dat += "Each time this button is pressed, a request will be sent out to any available personalities. Check back often and give a lot of time for personalities to respond. This process could take anywhere from 15 seconds to several minutes, depending on the available personalities' timeliness."
|
||||
user << browse(dat, "window=paicard")
|
||||
onclose(user, "paicard")
|
||||
return
|
||||
|
||||
/obj/item/device/paicard/Topic(href, href_list)
|
||||
|
||||
if(!usr || usr.stat)
|
||||
return
|
||||
|
||||
if(href_list["request"])
|
||||
src.looking_for_personality = 1
|
||||
SSpai.findPAI(src, usr)
|
||||
|
||||
if(pai)
|
||||
if(href_list["setdna"])
|
||||
if(pai.master_dna)
|
||||
return
|
||||
if(!istype(usr, /mob/living/carbon))
|
||||
usr << "<span class='warning'>You don't have any DNA, or your DNA is incompatible with this device!</span>"
|
||||
else
|
||||
var/mob/living/carbon/M = usr
|
||||
pai.master = M.real_name
|
||||
pai.master_dna = M.dna.unique_enzymes
|
||||
pai << "<span class='notice'>You have been bound to a new master.</span>"
|
||||
if(href_list["wipe"])
|
||||
var/confirm = input("Are you CERTAIN you wish to delete the current personality? This action cannot be undone.", "Personality Wipe") in list("Yes", "No")
|
||||
if(confirm == "Yes")
|
||||
if(pai)
|
||||
pai << "<span class='warning'>You feel yourself slipping away from reality.</span>"
|
||||
pai << "<span class='danger'>Byte by byte you lose your sense of self.</span>"
|
||||
pai << "<span class='userdanger'>Your mental faculties leave you.</span>"
|
||||
pai << "<span class='rose'>oblivion... </span>"
|
||||
pai.death(0)
|
||||
removePersonality()
|
||||
if(href_list["wires"])
|
||||
var/wire = text2num(href_list["wires"])
|
||||
if(radio)
|
||||
radio.wires.cut(wire)
|
||||
if(href_list["setlaws"])
|
||||
var/newlaws = copytext(sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1]) as message),1,MAX_MESSAGE_LEN)
|
||||
if(newlaws && pai)
|
||||
pai.add_supplied_law(0,newlaws)
|
||||
pai << "Your supplemental directives have been updated. Your new directives are:"
|
||||
pai << "Prime Directive : <br>[pai.laws.zeroth]"
|
||||
for(var/slaws in pai.laws.supplied)
|
||||
pai << "Supplemental Directives: <br>[slaws]"
|
||||
attack_self(usr)
|
||||
|
||||
// WIRE_SIGNAL = 1
|
||||
// WIRE_RECEIVE = 2
|
||||
// WIRE_TRANSMIT = 4
|
||||
|
||||
/obj/item/device/paicard/proc/setPersonality(mob/living/silicon/pai/personality)
|
||||
src.pai = personality
|
||||
src.add_overlay("pai-null")
|
||||
|
||||
playsound(loc, 'sound/effects/pai_boot.ogg', 50, 1, -1)
|
||||
audible_message("\The [src] plays a cheerful startup noise!")
|
||||
|
||||
/obj/item/device/paicard/proc/removePersonality()
|
||||
src.pai = null
|
||||
src.cut_overlays()
|
||||
src.add_overlay("pai-off")
|
||||
|
||||
/obj/item/device/paicard/proc/setEmotion(emotion)
|
||||
if(pai)
|
||||
src.cut_overlays()
|
||||
switch(emotion)
|
||||
if(1) src.add_overlay("pai-happy")
|
||||
if(2) src.add_overlay("pai-cat")
|
||||
if(3) src.add_overlay("pai-extremely-happy")
|
||||
if(4) src.add_overlay("pai-face")
|
||||
if(5) src.add_overlay("pai-laugh")
|
||||
if(6) src.add_overlay("pai-off")
|
||||
if(7) src.add_overlay("pai-sad")
|
||||
if(8) src.add_overlay("pai-angry")
|
||||
if(9) src.add_overlay("pai-what")
|
||||
if(10) src.add_overlay("pai-null")
|
||||
|
||||
/obj/item/device/paicard/proc/alertUpdate()
|
||||
visible_message("<span class ='info'>[src] flashes a message across its screen, \"Additional personalities available for download.\"", "<span class='notice'>[src] bleeps electronically.</span>")
|
||||
|
||||
/obj/item/device/paicard/emp_act(severity)
|
||||
if(pai)
|
||||
pai.emp_act(severity)
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
/obj/item/device/pipe_painter
|
||||
name = "pipe painter"
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "labeler1"
|
||||
item_state = "flight"
|
||||
flags = NOBLUDGEON
|
||||
var/list/modes = list(
|
||||
"grey" = rgb(255,255,255),
|
||||
"red" = rgb(255,0,0),
|
||||
"blue" = rgb(0,0,255),
|
||||
"cyan" = rgb(0,256,249),
|
||||
"green" = rgb(30,255,0),
|
||||
"yellow" = rgb(255,198,0),
|
||||
"purple" = rgb(130,43,255)
|
||||
)
|
||||
var/mode = "grey"
|
||||
|
||||
materials = list(MAT_METAL=5000, MAT_GLASS=2000)
|
||||
|
||||
/obj/item/device/pipe_painter/afterattack(atom/A, mob/user, proximity_flag)
|
||||
//Make sure we only paint adjacent items
|
||||
if(!proximity_flag)
|
||||
return
|
||||
|
||||
if(!istype(A,/obj/machinery/atmospherics/pipe))
|
||||
return
|
||||
|
||||
var/obj/machinery/atmospherics/pipe/P = A
|
||||
P.color = modes[mode]
|
||||
P.pipe_color = modes[mode]
|
||||
P.stored.color = modes[mode]
|
||||
user.visible_message("<span class='notice'>[user] paints \the [P] [mode].</span>","<span class='notice'>You paint \the [P] [mode].</span>")
|
||||
P.update_node_icon() //updates the neighbors
|
||||
|
||||
/obj/item/device/pipe_painter/attack_self(mob/user)
|
||||
mode = input("Which colour do you want to use?","Pipe painter") in modes
|
||||
|
||||
/obj/item/device/pipe_painter/examine()
|
||||
..()
|
||||
usr << "It is set to [mode]."
|
||||
@@ -0,0 +1,145 @@
|
||||
// Powersink - used to drain station power
|
||||
|
||||
/obj/item/device/powersink
|
||||
desc = "A nulling power sink which drains energy from electrical systems."
|
||||
name = "power sink"
|
||||
icon_state = "powersink0"
|
||||
item_state = "electronic"
|
||||
w_class = 4
|
||||
flags = CONDUCT
|
||||
throwforce = 5
|
||||
throw_speed = 1
|
||||
throw_range = 2
|
||||
materials = list(MAT_METAL=750)
|
||||
origin_tech = "powerstorage=5;syndicate=5"
|
||||
var/drain_rate = 1600000 // amount of power to drain per tick
|
||||
var/power_drained = 0 // has drained this much power
|
||||
var/max_power = 1e10 // maximum power that can be drained before exploding
|
||||
var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
|
||||
var/admins_warned = 0 // stop spam, only warn the admins once that we are about to boom
|
||||
|
||||
var/const/DISCONNECTED = 0
|
||||
var/const/CLAMPED_OFF = 1
|
||||
var/const/OPERATING = 2
|
||||
|
||||
var/obj/structure/cable/attached // the attached cable
|
||||
|
||||
/obj/item/device/powersink/update_icon()
|
||||
icon_state = "powersink[mode == OPERATING]"
|
||||
|
||||
/obj/item/device/powersink/proc/set_mode(value)
|
||||
if(value == mode)
|
||||
return
|
||||
switch(value)
|
||||
if(DISCONNECTED)
|
||||
attached = null
|
||||
if(mode == OPERATING)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
anchored = 0
|
||||
|
||||
if(CLAMPED_OFF)
|
||||
if(!attached)
|
||||
return
|
||||
if(mode == OPERATING)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
anchored = 1
|
||||
|
||||
if(OPERATING)
|
||||
if(!attached)
|
||||
return
|
||||
START_PROCESSING(SSobj, src)
|
||||
anchored = 1
|
||||
|
||||
mode = value
|
||||
update_icon()
|
||||
SetLuminosity(0)
|
||||
|
||||
/obj/item/device/powersink/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/screwdriver))
|
||||
if(mode == DISCONNECTED)
|
||||
var/turf/T = loc
|
||||
if(isturf(T) && !T.intact)
|
||||
attached = locate() in T
|
||||
if(!attached)
|
||||
user << "<span class='warning'>This device must be placed over an exposed, powered cable node!</span>"
|
||||
else
|
||||
set_mode(CLAMPED_OFF)
|
||||
user.visible_message( \
|
||||
"[user] attaches \the [src] to the cable.", \
|
||||
"<span class='notice'>You attach \the [src] to the cable.</span>",
|
||||
"<span class='italics'>You hear some wires being connected to something.</span>")
|
||||
else
|
||||
user << "<span class='warning'>This device must be placed over an exposed, powered cable node!</span>"
|
||||
else
|
||||
set_mode(DISCONNECTED)
|
||||
user.visible_message( \
|
||||
"[user] detaches \the [src] from the cable.", \
|
||||
"<span class='notice'>You detach \the [src] from the cable.</span>",
|
||||
"<span class='italics'>You hear some wires being disconnected from something.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/powersink/attack_paw()
|
||||
return
|
||||
|
||||
/obj/item/device/powersink/attack_ai()
|
||||
return
|
||||
|
||||
/obj/item/device/powersink/attack_hand(mob/user)
|
||||
switch(mode)
|
||||
if(DISCONNECTED)
|
||||
..()
|
||||
|
||||
if(CLAMPED_OFF)
|
||||
user.visible_message( \
|
||||
"[user] activates \the [src]!", \
|
||||
"<span class='notice'>You activate \the [src].</span>",
|
||||
"<span class='italics'>You hear a click.</span>")
|
||||
message_admins("Power sink activated by [key_name_admin(user)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) at ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
|
||||
log_game("Power sink activated by [key_name(user)] at ([x],[y],[z])")
|
||||
set_mode(OPERATING)
|
||||
|
||||
if(OPERATING)
|
||||
user.visible_message( \
|
||||
"[user] deactivates \the [src]!", \
|
||||
"<span class='notice'>You deactivate \the [src].</span>",
|
||||
"<span class='italics'>You hear a click.</span>")
|
||||
set_mode(CLAMPED_OFF)
|
||||
|
||||
/obj/item/device/powersink/process()
|
||||
if(!attached)
|
||||
set_mode(DISCONNECTED)
|
||||
return
|
||||
|
||||
var/datum/powernet/PN = attached.powernet
|
||||
if(PN)
|
||||
SetLuminosity(5)
|
||||
|
||||
// found a powernet, so drain up to max power from it
|
||||
|
||||
var/drained = min ( drain_rate, PN.avail )
|
||||
PN.load += drained
|
||||
power_drained += drained
|
||||
|
||||
// if tried to drain more than available on powernet
|
||||
// now look for APCs and drain their cells
|
||||
if(drained < drain_rate)
|
||||
for(var/obj/machinery/power/terminal/T in PN.nodes)
|
||||
if(istype(T.master, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/A = T.master
|
||||
if(A.operating && A.cell)
|
||||
A.cell.charge = max(0, A.cell.charge - 50)
|
||||
power_drained += 50
|
||||
if(A.charging == 2) // If the cell was full
|
||||
A.charging = 1 // It's no longer full
|
||||
|
||||
if(power_drained > max_power * 0.98)
|
||||
if (!admins_warned)
|
||||
admins_warned = 1
|
||||
message_admins("Power sink at ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) is 95% full. Explosion imminent.")
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1, 1)
|
||||
|
||||
if(power_drained >= max_power)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
explosion(src.loc, 4,8,16,32)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/item/device/radio/beacon
|
||||
name = "tracking beacon"
|
||||
desc = "A beacon used by a teleporter."
|
||||
icon_state = "beacon"
|
||||
item_state = "beacon"
|
||||
var/code = "electronic"
|
||||
origin_tech = "bluespace=1"
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/device/radio/beacon/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
|
||||
return
|
||||
|
||||
/obj/item/device/radio/beacon/send_hear()
|
||||
return null
|
||||
|
||||
|
||||
/obj/item/device/radio/beacon/verb/alter_signal(t as text)
|
||||
set name = "Alter Beacon's Signal"
|
||||
set category = "Object"
|
||||
set src in usr
|
||||
|
||||
if ((usr.canmove && !( usr.restrained() )))
|
||||
src.code = t
|
||||
if (!( src.code ))
|
||||
src.code = "beacon"
|
||||
src.add_fingerprint(usr)
|
||||
return
|
||||
|
||||
/*
|
||||
//Probably a better way of doing this, I'm lazy.
|
||||
/obj/item/device/radio/beacon/bacon/proc/digest_delay()
|
||||
spawn(600)
|
||||
qdel(src)*/ //Bacon beacons are no more rip in peace
|
||||
@@ -0,0 +1,147 @@
|
||||
/obj/item/device/electropack
|
||||
name = "electropack"
|
||||
desc = "Dance my monkeys! DANCE!!!"
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
icon_state = "electropack0"
|
||||
item_state = "electropack"
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BACK
|
||||
w_class = 5
|
||||
materials = list(MAT_METAL=10000, MAT_GLASS=2500)
|
||||
var/on = 1
|
||||
var/code = 2
|
||||
var/frequency = 1449
|
||||
var/shock_cooldown = 0
|
||||
|
||||
/obj/item/device/electropack/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] hooks \himself to the electropack and spams the trigger! It looks like \he's trying to commit suicide..</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
/obj/item/device/electropack/initialize()
|
||||
if(SSradio)
|
||||
SSradio.add_object(src, frequency, RADIO_CHAT)
|
||||
|
||||
/obj/item/device/electropack/Destroy()
|
||||
if(SSradio)
|
||||
SSradio.remove_object(src, frequency)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/electropack/attack_hand(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(src == C.back)
|
||||
user << "<span class='warning'>You need help taking this off!</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/device/electropack/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/clothing/head/helmet))
|
||||
var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit( user )
|
||||
A.icon = 'icons/obj/assemblies.dmi'
|
||||
|
||||
if(!user.unEquip(W))
|
||||
user << "<span class='warning'>\the [W] is stuck to your hand, you cannot attach it to \the [src]!</span>"
|
||||
return
|
||||
W.loc = A
|
||||
W.master = A
|
||||
A.part1 = W
|
||||
|
||||
user.unEquip(src)
|
||||
loc = A
|
||||
master = A
|
||||
A.part2 = src
|
||||
|
||||
user.put_in_hands(A)
|
||||
A.add_fingerprint(user)
|
||||
if(src.flags & NODROP)
|
||||
A.flags |= NODROP
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/electropack/Topic(href, href_list)
|
||||
//..()
|
||||
var/mob/living/carbon/C = usr
|
||||
if(usr.stat || usr.restrained() || C.back == src)
|
||||
return
|
||||
if(((istype(usr, /mob/living/carbon/human) && ((!( ticker ) || (ticker && ticker.mode != "monkey")) && usr.contents.Find(src))) || (usr.contents.Find(master) || (in_range(src, usr) && istype(loc, /turf)))))
|
||||
usr.set_machine(src)
|
||||
if(href_list["freq"])
|
||||
SSradio.remove_object(src, frequency)
|
||||
frequency = sanitize_frequency(frequency + text2num(href_list["freq"]))
|
||||
SSradio.add_object(src, frequency, RADIO_CHAT)
|
||||
else
|
||||
if(href_list["code"])
|
||||
code += text2num(href_list["code"])
|
||||
code = round(code)
|
||||
code = min(100, code)
|
||||
code = max(1, code)
|
||||
else
|
||||
if(href_list["power"])
|
||||
on = !( on )
|
||||
icon_state = "electropack[on]"
|
||||
if(!( master ))
|
||||
if(istype(loc, /mob))
|
||||
attack_self(loc)
|
||||
else
|
||||
for(var/mob/M in viewers(1, src))
|
||||
if(M.client)
|
||||
attack_self(M)
|
||||
else
|
||||
if(istype(master.loc, /mob))
|
||||
attack_self(master.loc)
|
||||
else
|
||||
for(var/mob/M in viewers(1, master))
|
||||
if(M.client)
|
||||
attack_self(M)
|
||||
else
|
||||
usr << browse(null, "window=radio")
|
||||
return
|
||||
return
|
||||
|
||||
/obj/item/device/electropack/receive_signal(datum/signal/signal)
|
||||
if(!signal || signal.encryption != code)
|
||||
return
|
||||
|
||||
if(ismob(loc) && on)
|
||||
if(shock_cooldown != 0)
|
||||
return
|
||||
shock_cooldown = 1
|
||||
spawn(100)
|
||||
shock_cooldown = 0
|
||||
var/mob/M = loc
|
||||
step(M, pick(cardinal))
|
||||
|
||||
M << "<span class='danger'>You feel a sharp shock!</span>"
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, M)
|
||||
s.start()
|
||||
|
||||
M.Weaken(5)
|
||||
|
||||
if(master)
|
||||
master.receive_signal()
|
||||
return
|
||||
|
||||
/obj/item/device/electropack/attack_self(mob/user)
|
||||
|
||||
if(!istype(user, /mob/living/carbon/human))
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = {"<TT>Turned [on ? "On" : "Off"] -
|
||||
<A href='?src=\ref[src];power=1'>Toggle</A><BR>
|
||||
<B>Frequency/Code</B> for electropack:<BR>
|
||||
Frequency:
|
||||
<A href='byond://?src=\ref[src];freq=-10'>-</A>
|
||||
<A href='byond://?src=\ref[src];freq=-2'>-</A> [format_frequency(frequency)]
|
||||
<A href='byond://?src=\ref[src];freq=2'>+</A>
|
||||
<A href='byond://?src=\ref[src];freq=10'>+</A><BR>
|
||||
|
||||
Code:
|
||||
<A href='byond://?src=\ref[src];code=-5'>-</A>
|
||||
<A href='byond://?src=\ref[src];code=-1'>-</A> [code]
|
||||
<A href='byond://?src=\ref[src];code=1'>+</A>
|
||||
<A href='byond://?src=\ref[src];code=5'>+</A><BR>
|
||||
</TT>"}
|
||||
user << browse(dat, "window=radio")
|
||||
onclose(user, "radio")
|
||||
return
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
/obj/item/device/encryptionkey/
|
||||
name = "standard encryption key"
|
||||
desc = "An encryption key for a radio headset. Has no special codes in it. WHY DOES IT EXIST? ASK NANOTRASEN."
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
icon_state = "cypherkey"
|
||||
w_class = 1
|
||||
origin_tech = "engineering=2;bluespace=1"
|
||||
var/translate_binary = 0
|
||||
var/translate_hive = 0
|
||||
var/syndie = 0
|
||||
var/centcom = 0
|
||||
var/list/channels = list()
|
||||
|
||||
/obj/item/device/encryptionkey/syndicate
|
||||
icon_state = "cypherkey"
|
||||
channels = list("Syndicate" = 1)
|
||||
origin_tech = "syndicate=1;engineering=3;bluespace=2"
|
||||
syndie = 1//Signifies that it de-crypts Syndicate transmissions
|
||||
|
||||
/obj/item/device/encryptionkey/binary
|
||||
name = "binary translator key"
|
||||
desc = "An encryption key for a radio headset. To access the binary channel, use :b."
|
||||
icon_state = "cypherkey"
|
||||
translate_binary = 1
|
||||
origin_tech = "syndicate=3;engineering=4;bluespace=3"
|
||||
|
||||
/obj/item/device/encryptionkey/headset_sec
|
||||
name = "security radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the security channel, use :s."
|
||||
icon_state = "sec_cypherkey"
|
||||
channels = list("Security" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_eng
|
||||
name = "engineering radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the engineering channel, use :e."
|
||||
icon_state = "eng_cypherkey"
|
||||
channels = list("Engineering" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_rob
|
||||
name = "robotics radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the engineering channel, use :e. For research, use :n."
|
||||
icon_state = "rob_cypherkey"
|
||||
channels = list("Science" = 1, "Engineering" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_med
|
||||
name = "medical radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the medical channel, use :m."
|
||||
icon_state = "med_cypherkey"
|
||||
channels = list("Medical" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_sci
|
||||
name = "science radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the science channel, use :n."
|
||||
icon_state = "sci_cypherkey"
|
||||
channels = list("Science" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_medsci
|
||||
name = "medical research radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the medical channel, use :m. For science, use :n."
|
||||
icon_state = "medsci_cypherkey"
|
||||
channels = list("Science" = 1, "Medical" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_com
|
||||
name = "command radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the command channel, use :c."
|
||||
icon_state = "com_cypherkey"
|
||||
channels = list("Command" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/captain
|
||||
name = "\proper the captain's encryption key"
|
||||
desc = "An encryption key for a radio headset. Channels are as follows: :c - command, :s - security, :e - engineering, :u - supply, :v - service, :m - medical, :n - science."
|
||||
icon_state = "cap_cypherkey"
|
||||
channels = list("Command" = 1, "Security" = 1, "Engineering" = 0, "Science" = 0, "Medical" = 0, "Supply" = 0, "Service" = 0)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/rd
|
||||
name = "\proper the research director's encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the science channel, use :n. For command, use :c."
|
||||
icon_state = "rd_cypherkey"
|
||||
channels = list("Science" = 1, "Command" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/hos
|
||||
name = "\proper the head of security's encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the security channel, use :s. For command, use :c."
|
||||
icon_state = "hos_cypherkey"
|
||||
channels = list("Security" = 1, "Command" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/ce
|
||||
name = "\proper the chief engineer's encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the engineering channel, use :e. For command, use :c."
|
||||
icon_state = "ce_cypherkey"
|
||||
channels = list("Engineering" = 1, "Command" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/cmo
|
||||
name = "\proper the chief medical officer's encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the medical channel, use :m. For command, use :c."
|
||||
icon_state = "cmo_cypherkey"
|
||||
channels = list("Medical" = 1, "Command" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/heads/hop
|
||||
name = "\proper the head of personnel's encryption key"
|
||||
desc = "An encryption key for a radio headset. Channels are as follows: :u - supply, :v - service, :c - command."
|
||||
icon_state = "hop_cypherkey"
|
||||
channels = list("Supply" = 1, "Service" = 1, "Command" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_cargo
|
||||
name = "supply radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the supply channel, use :u."
|
||||
icon_state = "cargo_cypherkey"
|
||||
channels = list("Supply" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_service
|
||||
name = "service radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the service channel, use :v."
|
||||
icon_state = "srv_cypherkey"
|
||||
channels = list("Service" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/headset_cent
|
||||
name = "centcom radio encryption key"
|
||||
desc = "An encryption key for a radio headset. To access the centcom channel, use :y."
|
||||
icon_state = "cent_cypherkey"
|
||||
centcom = 1
|
||||
channels = list("Centcom" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/ai //ported from NT, this goes 'inside' the AI.
|
||||
channels = list("Command" = 1, "Security" = 1, "Engineering" = 1, "Science" = 1, "Medical" = 1, "Supply" = 1, "Service" = 1, "AI Private" = 1)
|
||||
|
||||
/obj/item/device/encryptionkey/secbot
|
||||
channels = list("AI Private"=1,"Security"=1)
|
||||
@@ -0,0 +1,290 @@
|
||||
/obj/item/device/radio/headset
|
||||
name = "radio headset"
|
||||
desc = "An updated, modular intercom that fits over the head. Takes encryption keys. \nTo speak on the general radio frequency, use ; before speaking."
|
||||
icon_state = "headset"
|
||||
item_state = "headset"
|
||||
materials = list(MAT_METAL=75)
|
||||
subspace_transmission = 1
|
||||
canhear_range = 0 // can't hear headsets from very far away
|
||||
|
||||
slot_flags = SLOT_EARS
|
||||
var/obj/item/device/encryptionkey/keyslot2 = null
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/device/radio/headset/New()
|
||||
..()
|
||||
recalculateChannels()
|
||||
|
||||
/obj/item/device/radio/headset/Destroy()
|
||||
qdel(keyslot)
|
||||
qdel(keyslot2)
|
||||
keyslot = null
|
||||
keyslot2 = null
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/headset/talk_into(mob/living/M, message, channel, list/spans)
|
||||
if (!listening)
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/device/radio/headset/receive_range(freq, level, AIuser)
|
||||
if(ishuman(src.loc))
|
||||
var/mob/living/carbon/human/H = src.loc
|
||||
if(H.ears == src)
|
||||
return ..(freq, level)
|
||||
else if(AIuser)
|
||||
return ..(freq, level)
|
||||
return -1
|
||||
|
||||
/obj/item/device/radio/headset/syndicate //disguised to look like a normal headset for stealth ops
|
||||
origin_tech = "syndicate=3"
|
||||
|
||||
/obj/item/device/radio/headset/syndicate/alt //undisguised bowman with flash protection
|
||||
name = "syndicate headset"
|
||||
desc = "A syndicate headset that can be used to hear all radio frequencies. Protects ears from flashbangs. \nTo access the syndicate channel, use ; before speaking."
|
||||
flags = EARBANGPROTECT
|
||||
origin_tech = "syndicate=3"
|
||||
icon_state = "syndie_headset"
|
||||
item_state = "syndie_headset"
|
||||
|
||||
/obj/item/device/radio/headset/syndicate/alt/leader
|
||||
name = "team leader headset"
|
||||
command = TRUE
|
||||
|
||||
/obj/item/device/radio/headset/syndicate/New()
|
||||
..()
|
||||
make_syndie()
|
||||
|
||||
/obj/item/device/radio/headset/binary
|
||||
origin_tech = "syndicate=3"
|
||||
/obj/item/device/radio/headset/binary/New()
|
||||
..()
|
||||
qdel(keyslot)
|
||||
keyslot = new /obj/item/device/encryptionkey/binary
|
||||
recalculateChannels()
|
||||
|
||||
/obj/item/device/radio/headset/headset_sec
|
||||
name = "security radio headset"
|
||||
desc = "This is used by your elite security force. \nTo access the security channel, use :s."
|
||||
icon_state = "sec_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_sec
|
||||
|
||||
/obj/item/device/radio/headset/headset_sec/alt
|
||||
name = "security bowman headset"
|
||||
desc = "This is used by your elite security force. Protects ears from flashbangs. \nTo access the security channel, use :s."
|
||||
flags = EARBANGPROTECT
|
||||
icon_state = "sec_headset_alt"
|
||||
item_state = "sec_headset_alt"
|
||||
|
||||
/obj/item/device/radio/headset/headset_eng
|
||||
name = "engineering radio headset"
|
||||
desc = "When the engineers wish to chat like girls. \nTo access the engineering channel, use :e. "
|
||||
icon_state = "eng_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_eng
|
||||
|
||||
/obj/item/device/radio/headset/headset_rob
|
||||
name = "robotics radio headset"
|
||||
desc = "Made specifically for the roboticists, who cannot decide between departments. \nTo access the engineering channel, use :e. For research, use :n."
|
||||
icon_state = "rob_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_rob
|
||||
|
||||
/obj/item/device/radio/headset/headset_med
|
||||
name = "medical radio headset"
|
||||
desc = "A headset for the trained staff of the medbay. \nTo access the medical channel, use :m."
|
||||
icon_state = "med_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_med
|
||||
|
||||
/obj/item/device/radio/headset/headset_sci
|
||||
name = "science radio headset"
|
||||
desc = "A sciency headset. Like usual. \nTo access the science channel, use :n."
|
||||
icon_state = "sci_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_sci
|
||||
|
||||
/obj/item/device/radio/headset/headset_medsci
|
||||
name = "medical research radio headset"
|
||||
desc = "A headset that is a result of the mating between medical and science. \nTo access the medical channel, use :m. For science, use :n."
|
||||
icon_state = "medsci_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_medsci
|
||||
|
||||
/obj/item/device/radio/headset/headset_com
|
||||
name = "command radio headset"
|
||||
desc = "A headset with a commanding channel. \nTo access the command channel, use :c."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_com
|
||||
|
||||
/obj/item/device/radio/headset/heads
|
||||
command = TRUE
|
||||
|
||||
/obj/item/device/radio/headset/heads/captain
|
||||
name = "\proper the captain's headset"
|
||||
desc = "The headset of the king. \nChannels are as follows: :c - command, :s - security, :e - engineering, :u - supply, :v - service, :m - medical, :n - science."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/captain
|
||||
|
||||
/obj/item/device/radio/headset/heads/captain/alt
|
||||
name = "\proper the captain's bowman headset"
|
||||
desc = "The headset of the boss. Protects ears from flashbangs. \nChannels are as follows: :c - command, :s - security, :e - engineering, :u - supply, :v - service, :m - medical, :n - science."
|
||||
flags = EARBANGPROTECT
|
||||
icon_state = "com_headset_alt"
|
||||
item_state = "com_headset_alt"
|
||||
|
||||
/obj/item/device/radio/headset/heads/rd
|
||||
name = "\proper the research director's headset"
|
||||
desc = "Headset of the fellow who keeps society marching towards technological singularity. \nTo access the science channel, use :n. For command, use :c."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/rd
|
||||
|
||||
/obj/item/device/radio/headset/heads/hos
|
||||
name = "\proper the head of security's headset"
|
||||
desc = "The headset of the man in charge of keeping order and protecting the station. \nTo access the security channel, use :s. For command, use :c."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/hos
|
||||
|
||||
/obj/item/device/radio/headset/heads/hos/alt
|
||||
name = "\proper the head of security's bowman headset"
|
||||
desc = "The headset of the man in charge of keeping order and protecting the station. Protects ears from flashbangs. \nTo access the security channel, use :s. For command, use :c."
|
||||
flags = EARBANGPROTECT
|
||||
icon_state = "com_headset_alt"
|
||||
item_state = "com_headset_alt"
|
||||
|
||||
/obj/item/device/radio/headset/heads/ce
|
||||
name = "\proper the chief engineer's headset"
|
||||
desc = "The headset of the guy in charge of keeping the station powered and undamaged. \nTo access the engineering channel, use :e. For command, use :c."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/ce
|
||||
|
||||
/obj/item/device/radio/headset/heads/cmo
|
||||
name = "\proper the chief medical officer's headset"
|
||||
desc = "The headset of the highly trained medical chief. \nTo access the medical channel, use :m. For command, use :c."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/cmo
|
||||
|
||||
/obj/item/device/radio/headset/heads/hop
|
||||
name = "\proper the head of personnel's headset"
|
||||
desc = "The headset of the guy who will one day be captain. \nChannels are as follows: :u - supply, :v - service, :c - command."
|
||||
icon_state = "com_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/hop
|
||||
|
||||
/obj/item/device/radio/headset/headset_cargo
|
||||
name = "supply radio headset"
|
||||
desc = "A headset used by the QM and his slaves. \nTo access the supply channel, use :u."
|
||||
icon_state = "cargo_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_cargo
|
||||
|
||||
/obj/item/device/radio/headset/headset_cargo/mining
|
||||
name = "mining radio headset"
|
||||
desc = "Headset used by shaft miners. \nTo access the supply channel, use :u."
|
||||
icon_state = "mine_headset"
|
||||
|
||||
/obj/item/device/radio/headset/headset_srv
|
||||
name = "service radio headset"
|
||||
desc = "Headset used by the service staff, tasked with keeping the station full, happy and clean. \nTo access the service channel, use :v."
|
||||
icon_state = "srv_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_service
|
||||
|
||||
/obj/item/device/radio/headset/headset_cent
|
||||
name = "\improper Centcom headset"
|
||||
desc = "A headset used by the upper echelons of Nanotrasen. \nTo access the centcom channel, use :y."
|
||||
icon_state = "cent_headset"
|
||||
keyslot = new /obj/item/device/encryptionkey/headset_com
|
||||
keyslot2 = new /obj/item/device/encryptionkey/headset_cent
|
||||
|
||||
/obj/item/device/radio/headset/headset_cent/commander
|
||||
keyslot = new /obj/item/device/encryptionkey/heads/captain
|
||||
|
||||
/obj/item/device/radio/headset/headset_cent/alt
|
||||
name = "\improper Centcom bowman headset"
|
||||
desc = "A headset especially for emergency response personnel. Protects ears from flashbangs. \nTo access the centcom channel, use :y."
|
||||
flags = EARBANGPROTECT
|
||||
icon_state = "cent_headset_alt"
|
||||
item_state = "cent_headset_alt"
|
||||
keyslot = null
|
||||
|
||||
/obj/item/device/radio/headset/ai
|
||||
name = "\proper Integrated Subspace Transceiver "
|
||||
keyslot2 = new /obj/item/device/encryptionkey/ai
|
||||
|
||||
/obj/item/device/radio/headset/ai/receive_range(freq, level)
|
||||
return ..(freq, level, 1)
|
||||
|
||||
/obj/item/device/radio/headset/attackby(obj/item/weapon/W, mob/user, params)
|
||||
user.set_machine(src)
|
||||
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(keyslot || keyslot2)
|
||||
|
||||
|
||||
for(var/ch_name in channels)
|
||||
SSradio.remove_object(src, radiochannels[ch_name])
|
||||
secure_radio_connections[ch_name] = null
|
||||
|
||||
|
||||
if(keyslot)
|
||||
var/turf/T = get_turf(user)
|
||||
if(T)
|
||||
keyslot.loc = T
|
||||
keyslot = null
|
||||
|
||||
|
||||
|
||||
if(keyslot2)
|
||||
var/turf/T = get_turf(user)
|
||||
if(T)
|
||||
keyslot2.loc = T
|
||||
keyslot2 = null
|
||||
|
||||
recalculateChannels()
|
||||
user << "<span class='notice'>You pop out the encryption keys in the headset.</span>"
|
||||
|
||||
else
|
||||
user << "<span class='warning'>This headset doesn't have any unique encryption keys! How useless...</span>"
|
||||
|
||||
else if(istype(W, /obj/item/device/encryptionkey/))
|
||||
if(keyslot && keyslot2)
|
||||
user << "<span class='warning'>The headset can't hold another key!</span>"
|
||||
return
|
||||
|
||||
if(!keyslot)
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
keyslot = W
|
||||
|
||||
else
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
keyslot2 = W
|
||||
|
||||
|
||||
recalculateChannels()
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/device/radio/headset/recalculateChannels()
|
||||
..()
|
||||
if(keyslot2)
|
||||
for(var/ch_name in keyslot2.channels)
|
||||
if(ch_name in src.channels)
|
||||
continue
|
||||
src.channels += ch_name
|
||||
src.channels[ch_name] = keyslot2.channels[ch_name]
|
||||
|
||||
if(keyslot2.translate_binary)
|
||||
src.translate_binary = 1
|
||||
|
||||
if(keyslot2.translate_hive)
|
||||
src.translate_hive = 1
|
||||
|
||||
if(keyslot2.syndie)
|
||||
src.syndie = 1
|
||||
|
||||
if (keyslot2.centcom)
|
||||
centcom = 1
|
||||
|
||||
|
||||
for(var/ch_name in channels)
|
||||
secure_radio_connections[ch_name] = add_radio(src, radiochannels[ch_name])
|
||||
|
||||
return
|
||||
@@ -0,0 +1,71 @@
|
||||
/obj/item/device/radio/intercom
|
||||
name = "station intercom"
|
||||
desc = "Talk through this."
|
||||
icon_state = "intercom"
|
||||
anchored = 1
|
||||
w_class = 4
|
||||
canhear_range = 2
|
||||
var/number = 0
|
||||
var/anyai = 1
|
||||
var/mob/living/silicon/ai/ai = list()
|
||||
var/last_tick //used to delay the powercheck
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/device/radio/intercom/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/radio/intercom/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/intercom/attack_ai(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/item/device/radio/intercom/attack_hand(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/item/device/radio/intercom/interact(mob/user)
|
||||
..()
|
||||
ui_interact(user, state = default_state)
|
||||
|
||||
/obj/item/device/radio/intercom/receive_range(freq, level)
|
||||
if(!on)
|
||||
return -1
|
||||
if(wires.is_cut(WIRE_RX))
|
||||
return -1
|
||||
if(!(0 in level))
|
||||
var/turf/position = get_turf(src)
|
||||
if(isnull(position) || !(position.z in level))
|
||||
return -1
|
||||
if(!src.listening)
|
||||
return -1
|
||||
if(freq == SYND_FREQ)
|
||||
if(!(src.syndie))
|
||||
return -1//Prevents broadcast of messages over devices lacking the encryption
|
||||
|
||||
return canhear_range
|
||||
|
||||
|
||||
/obj/item/device/radio/intercom/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
|
||||
if(!anyai && !(speaker in ai))
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/device/radio/intercom/process()
|
||||
if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0))
|
||||
last_tick = world.timeofday
|
||||
|
||||
var/area/A = get_area_master(src)
|
||||
if(!A || emped)
|
||||
on = 0
|
||||
else
|
||||
on = A.powered(EQUIP) // set "on" to the power status
|
||||
|
||||
if(!on)
|
||||
icon_state = "intercom-p"
|
||||
else
|
||||
icon_state = "intercom"
|
||||
|
||||
/obj/item/device/radio/intercom/add_blood(list/blood_dna)
|
||||
return 0
|
||||
@@ -0,0 +1,591 @@
|
||||
/obj/item/device/radio
|
||||
icon = 'icons/obj/radio.dmi'
|
||||
name = "station bounced radio"
|
||||
suffix = "\[3\]"
|
||||
icon_state = "walkietalkie"
|
||||
item_state = "walkietalkie"
|
||||
dog_fashion = /datum/dog_fashion/back
|
||||
var/on = 1 // 0 for off
|
||||
var/last_transmission
|
||||
var/frequency = 1459 //common chat
|
||||
var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies
|
||||
var/canhear_range = 3 // the range which mobs can hear this radio from
|
||||
var/obj/item/device/radio/patch_link = null
|
||||
var/list/secure_radio_connections
|
||||
var/prison_radio = 0
|
||||
var/b_stat = 0
|
||||
var/broadcasting = 0
|
||||
var/listening = 1
|
||||
var/translate_binary = 0
|
||||
var/translate_hive = 0
|
||||
var/freerange = 0 // 0 - Sanitize frequencies, 1 - Full range
|
||||
var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h
|
||||
var/obj/item/device/encryptionkey/keyslot //To allow the radio to accept encryption keys.
|
||||
var/subspace_switchable = 0
|
||||
var/subspace_transmission = 0
|
||||
var/syndie = 0//Holder to see if it's a syndicate encrpyed radio
|
||||
var/centcom = 0//Bleh, more dirty booleans
|
||||
var/freqlock = 0 //Frequency lock to stop the user from untuning specialist radios.
|
||||
var/emped = 0 //Highjacked to track the number of consecutive EMPs on the radio, allowing consecutive EMP's to stack properly.
|
||||
// "Example" = FREQ_LISTENING|FREQ_BROADCASTING
|
||||
flags = CONDUCT | HEAR
|
||||
slot_flags = SLOT_BELT
|
||||
languages_spoken = HUMAN | ROBOT
|
||||
languages_understood = HUMAN | ROBOT
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
w_class = 2
|
||||
materials = list(MAT_METAL=75, MAT_GLASS=25)
|
||||
|
||||
var/const/TRANSMISSION_DELAY = 5 // only 2/second/radio
|
||||
var/const/FREQ_LISTENING = 1
|
||||
//FREQ_BROADCASTING = 2
|
||||
|
||||
var/command = FALSE //If we are speaking into a command headset, our text can be BOLD
|
||||
var/use_command = FALSE
|
||||
|
||||
/obj/item/device/radio/proc/set_frequency(new_frequency)
|
||||
remove_radio(src, frequency)
|
||||
frequency = add_radio(src, new_frequency)
|
||||
|
||||
/obj/item/device/radio/New()
|
||||
wires = new /datum/wires/radio(src)
|
||||
if(prison_radio)
|
||||
wires.cut(WIRE_TX) // OH GOD WHY
|
||||
secure_radio_connections = new
|
||||
..()
|
||||
if(SSradio)
|
||||
initialize()
|
||||
|
||||
/obj/item/device/radio/proc/recalculateChannels()
|
||||
channels = list()
|
||||
translate_binary = 0
|
||||
translate_hive = 0
|
||||
syndie = 0
|
||||
centcom = 0
|
||||
|
||||
if(keyslot)
|
||||
for(var/ch_name in keyslot.channels)
|
||||
if(ch_name in src.channels)
|
||||
continue
|
||||
channels += ch_name
|
||||
channels[ch_name] = keyslot.channels[ch_name]
|
||||
|
||||
if(keyslot.translate_binary)
|
||||
translate_binary = 1
|
||||
|
||||
if(keyslot.translate_hive)
|
||||
translate_hive = 1
|
||||
|
||||
if(keyslot.syndie)
|
||||
syndie = 1
|
||||
|
||||
if(keyslot.centcom)
|
||||
centcom = 1
|
||||
|
||||
for(var/ch_name in channels)
|
||||
secure_radio_connections[ch_name] = add_radio(src, radiochannels[ch_name])
|
||||
|
||||
/obj/item/device/radio/proc/make_syndie() // Turns normal radios into Syndicate radios!
|
||||
qdel(keyslot)
|
||||
keyslot = new /obj/item/device/encryptionkey/syndicate
|
||||
syndie = 1
|
||||
recalculateChannels()
|
||||
|
||||
/obj/item/device/radio/Destroy()
|
||||
qdel(wires)
|
||||
wires = null
|
||||
remove_radio_all(src) //Just to be sure
|
||||
patch_link = null
|
||||
keyslot = null
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/initialize()
|
||||
frequency = sanitize_frequency(frequency, freerange)
|
||||
set_frequency(frequency)
|
||||
|
||||
for(var/ch_name in channels)
|
||||
secure_radio_connections[ch_name] = add_radio(src, radiochannels[ch_name])
|
||||
|
||||
/obj/item/device/radio/interact(mob/user)
|
||||
if (..())
|
||||
return
|
||||
if(b_stat && !istype(user, /mob/living/silicon/ai))
|
||||
wires.interact(user)
|
||||
else
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/device/radio/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = inventory_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "radio", name, 370, 220 + channels.len * 22, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/device/radio/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
data["broadcasting"] = broadcasting
|
||||
data["listening"] = listening
|
||||
data["frequency"] = frequency
|
||||
data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ
|
||||
data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ
|
||||
data["freqlock"] = freqlock
|
||||
data["channels"] = list()
|
||||
for(var/channel in channels)
|
||||
data["channels"][channel] = channels[channel] & FREQ_LISTENING
|
||||
data["command"] = command
|
||||
data["useCommand"] = use_command
|
||||
data["subspace"] = subspace_transmission
|
||||
data["subspaceSwitchable"] = subspace_switchable
|
||||
data["headset"] = istype(src, /obj/item/device/radio/headset)
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/device/radio/ui_act(action, params, datum/tgui/ui)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("frequency")
|
||||
if(freqlock)
|
||||
return
|
||||
var/tune = params["tune"]
|
||||
var/adjust = text2num(params["adjust"])
|
||||
if(tune == "input")
|
||||
var/min = format_frequency(freerange ? MIN_FREE_FREQ : MIN_FREQ)
|
||||
var/max = format_frequency(freerange ? MAX_FREE_FREQ : MAX_FREQ)
|
||||
tune = input("Tune frequency ([min]-[max]):", name, format_frequency(frequency)) as null|num
|
||||
if(!isnull(tune) && !..())
|
||||
. = TRUE
|
||||
else if(adjust)
|
||||
tune = frequency + adjust * 10
|
||||
. = TRUE
|
||||
else if(text2num(tune) != null)
|
||||
tune = tune * 10
|
||||
. = TRUE
|
||||
if(.)
|
||||
frequency = sanitize_frequency(tune, freerange)
|
||||
set_frequency(frequency)
|
||||
if(frequency == traitor_frequency && hidden_uplink)
|
||||
hidden_uplink.interact(usr)
|
||||
ui.close()
|
||||
if("listen")
|
||||
listening = !listening
|
||||
. = TRUE
|
||||
if("broadcast")
|
||||
broadcasting = !broadcasting
|
||||
. = TRUE
|
||||
if("channel")
|
||||
var/channel = params["channel"]
|
||||
if(!(channel in channels))
|
||||
return
|
||||
if(channels[channel] & FREQ_LISTENING)
|
||||
channels[channel] &= ~FREQ_LISTENING
|
||||
else
|
||||
channels[channel] |= FREQ_LISTENING
|
||||
. = TRUE
|
||||
if("command")
|
||||
use_command = !use_command
|
||||
. = TRUE
|
||||
if("subspace")
|
||||
if(subspace_switchable)
|
||||
subspace_transmission = !subspace_transmission
|
||||
if(!subspace_transmission)
|
||||
channels = list()
|
||||
else
|
||||
recalculateChannels()
|
||||
. = TRUE
|
||||
|
||||
/obj/item/device/radio/talk_into(atom/movable/M, message, channel, list/spans)
|
||||
if(!on) return // the device has to be on
|
||||
// Fix for permacell radios, but kinda eh about actually fixing them.
|
||||
if(!M || !message) return
|
||||
|
||||
if(wires.is_cut(WIRE_TX))
|
||||
return
|
||||
|
||||
if(!M.IsVocal())
|
||||
return
|
||||
|
||||
if(use_command)
|
||||
spans |= SPAN_COMMAND
|
||||
|
||||
/* Quick introduction:
|
||||
This new radio system uses a very robust FTL signaling technology unoriginally
|
||||
dubbed "subspace" which is somewhat similar to 'blue-space' but can't
|
||||
actually transmit large mass. Headsets are the only radio devices capable
|
||||
of sending subspace transmissions to the Communications Satellite.
|
||||
|
||||
A headset sends a signal to a subspace listener/reciever elsewhere in space,
|
||||
the signal gets processed and logged, and an audible transmission gets sent
|
||||
to each individual headset.
|
||||
*/
|
||||
|
||||
/*
|
||||
be prepared to disregard any comments in all of tcomms code. i tried my best to keep them somewhat up-to-date, but eh
|
||||
*/
|
||||
|
||||
//get the frequency you buttface. radios no longer use the SSradio. confusing for future generations, convenient for me.
|
||||
var/freq
|
||||
if(channel && channels && channels.len > 0)
|
||||
if(channel == "department")
|
||||
channel = channels[1]
|
||||
freq = secure_radio_connections[channel]
|
||||
if (!channels[channel]) // if the channel is turned off, don't broadcast
|
||||
return
|
||||
else
|
||||
freq = frequency
|
||||
channel = null
|
||||
|
||||
var/freqnum = text2num(freq) //Why should we call text2num three times when we can just do it here?
|
||||
var/turf/position = get_turf(src)
|
||||
|
||||
//#### Tagging the signal with all appropriate identity values ####//
|
||||
|
||||
// ||-- The mob's name identity --||
|
||||
var/real_name = M.name // mob's real name
|
||||
var/mobkey = "none" // player key associated with mob
|
||||
var/voicemask = 0 // the speaker is wearing a voice mask
|
||||
var/voice = M.GetVoice() // Why reinvent the wheel when there is a proc that does nice things already
|
||||
if(ismob(M))
|
||||
var/mob/speaker = M
|
||||
real_name = speaker.real_name
|
||||
if(speaker.client)
|
||||
mobkey = speaker.key // assign the mob's key
|
||||
|
||||
|
||||
var/jobname // the mob's "job"
|
||||
|
||||
|
||||
// --- Human: use their job as seen on the crew manifest - makes it unneeded to carry an ID for an AI to see their job
|
||||
if(ishuman(M))
|
||||
var/datum/data/record/findjob = find_record("name", voice, data_core.general)
|
||||
|
||||
if(voice != real_name)
|
||||
voicemask = 1
|
||||
if(findjob)
|
||||
jobname = findjob.fields["rank"]
|
||||
else
|
||||
jobname = "Unknown"
|
||||
|
||||
// --- Carbon Nonhuman ---
|
||||
else if(iscarbon(M)) // Nonhuman carbon mob
|
||||
jobname = "No id"
|
||||
|
||||
// --- AI ---
|
||||
else if(isAI(M))
|
||||
jobname = "AI"
|
||||
|
||||
// --- Cyborg ---
|
||||
else if(isrobot(M))
|
||||
var/mob/living/silicon/robot/B = M
|
||||
jobname = "[B.designation] Cyborg"
|
||||
|
||||
// --- Personal AI (pAI) ---
|
||||
else if(istype(M, /mob/living/silicon/pai))
|
||||
jobname = "Personal AI"
|
||||
|
||||
// --- Cold, emotionless machines. ---
|
||||
else if(isobj(M))
|
||||
jobname = "Machine"
|
||||
|
||||
// --- Unidentifiable mob ---
|
||||
else
|
||||
jobname = "Unknown"
|
||||
|
||||
/* ###### Centcom channel bypasses all comms relays. ###### */
|
||||
|
||||
if (freqnum == CENTCOM_FREQ && centcom)
|
||||
var/datum/signal/signal = new
|
||||
signal.transmission_method = 2
|
||||
signal.data = list(
|
||||
"mob" = M, // store a reference to the mob
|
||||
"mobtype" = M.type, // the mob's type
|
||||
"realname" = real_name, // the mob's real name
|
||||
"name" = voice, // the mob's voice name
|
||||
"job" = jobname, // the mob's job
|
||||
"key" = mobkey, // the mob's key
|
||||
"vmask" = voicemask, // 1 if the mob is using a voice gas mas
|
||||
|
||||
"compression" = 0, // uncompressed radio signal
|
||||
"message" = message, // the actual sent message
|
||||
"radio" = src, // stores the radio used for transmission
|
||||
"slow" = 0,
|
||||
"traffic" = 0,
|
||||
"type" = 0,
|
||||
"server" = null,
|
||||
"reject" = 0,
|
||||
"level" = 0,
|
||||
"languages" = languages_spoken,
|
||||
"spans" = spans,
|
||||
"verb_say" = M.verb_say,
|
||||
"verb_ask" = M.verb_ask,
|
||||
"verb_exclaim" = M.verb_exclaim,
|
||||
"verb_yell" = M.verb_yell
|
||||
)
|
||||
signal.frequency = freqnum // Quick frequency set
|
||||
Broadcast_Message(M, voicemask,
|
||||
src, message, voice, jobname, real_name,
|
||||
5, signal.data["compression"], list(position.z, 0), freq, spans,
|
||||
verb_say, verb_ask, verb_exclaim, verb_yell)
|
||||
return
|
||||
|
||||
/* ###### Radio headsets can only broadcast through subspace ###### */
|
||||
|
||||
if(subspace_transmission)
|
||||
// First, we want to generate a new radio signal
|
||||
var/datum/signal/signal = new
|
||||
signal.transmission_method = 2 // 2 would be a subspace transmission.
|
||||
// transmission_method could probably be enumerated through #define. Would be neater.
|
||||
// --- Finally, tag the actual signal with the appropriate values ---
|
||||
signal.data = list(
|
||||
// Identity-associated tags:
|
||||
"mob" = M, // store a reference to the mob
|
||||
"mobtype" = M.type, // the mob's type
|
||||
"realname" = real_name, // the mob's real name
|
||||
"name" = voice, // the mob's voice name
|
||||
"job" = jobname, // the mob's job
|
||||
"key" = mobkey, // the mob's key
|
||||
"vmask" = voicemask, // 1 if the mob is using a voice gas mask
|
||||
|
||||
// We store things that would otherwise be kept in the actual mob
|
||||
// so that they can be logged even AFTER the mob is deleted or something
|
||||
|
||||
// Other tags:
|
||||
"compression" = rand(35,65), // compressed radio signal
|
||||
"message" = message, // the actual sent message
|
||||
"radio" = src, // stores the radio used for transmission
|
||||
"slow" = 0, // how much to sleep() before broadcasting - simulates net lag
|
||||
"traffic" = 0, // dictates the total traffic sum that the signal went through
|
||||
"type" = 0, // determines what type of radio input it is: normal broadcast
|
||||
"server" = null, // the last server to log this signal
|
||||
"reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery
|
||||
"level" = position.z, // The source's z level
|
||||
"languages" = M.languages_spoken, //The languages M is talking in.
|
||||
"spans" = spans, //the span classes of this message.
|
||||
"verb_say" = M.verb_say, //the verb used when talking normally
|
||||
"verb_ask" = M.verb_ask, //the verb used when asking
|
||||
"verb_exclaim" = M.verb_exclaim, //the verb used when exclaiming
|
||||
"verb_yell" = M.verb_yell //the verb used when yelling
|
||||
)
|
||||
signal.frequency = freq
|
||||
|
||||
//#### Sending the signal to all subspace receivers ####//
|
||||
|
||||
for(var/obj/machinery/telecomms/receiver/R in telecomms_list)
|
||||
R.receive_signal(signal)
|
||||
|
||||
// Allinone can act as receivers.
|
||||
for(var/obj/machinery/telecomms/allinone/R in telecomms_list)
|
||||
R.receive_signal(signal)
|
||||
|
||||
// Receiving code can be located in Telecommunications.dm
|
||||
return
|
||||
|
||||
|
||||
/* ###### Intercoms and station-bounced radios ###### */
|
||||
|
||||
var/filter_type = 2
|
||||
|
||||
var/datum/signal/signal = new
|
||||
signal.transmission_method = 2
|
||||
|
||||
|
||||
/* --- Try to send a normal subspace broadcast first */
|
||||
|
||||
signal.data = list(
|
||||
"mob" = M, // store a reference to the mob
|
||||
"mobtype" = M.type, // the mob's type
|
||||
"realname" = real_name, // the mob's real name
|
||||
"name" = voice, // the mob's voice name
|
||||
"job" = jobname, // the mob's job
|
||||
"key" = mobkey, // the mob's key
|
||||
"vmask" = voicemask, // 1 if the mob is using a voice gas mas
|
||||
|
||||
"compression" = 0, // uncompressed radio signal
|
||||
"message" = message, // the actual sent message
|
||||
"radio" = src, // stores the radio used for transmission
|
||||
"slow" = 0,
|
||||
"traffic" = 0,
|
||||
"type" = 0,
|
||||
"server" = null,
|
||||
"reject" = 0,
|
||||
"level" = position.z,
|
||||
"languages" = languages_spoken,
|
||||
"spans" = spans,
|
||||
"verb_say" = M.verb_say,
|
||||
"verb_ask" = M.verb_ask,
|
||||
"verb_exclaim" = M.verb_exclaim,
|
||||
"verb_yell" = M.verb_yell
|
||||
)
|
||||
signal.frequency = freqnum // Quick frequency set
|
||||
for(var/obj/machinery/telecomms/receiver/R in telecomms_list)
|
||||
R.receive_signal(signal)
|
||||
|
||||
|
||||
spawn(20) // wait a little...
|
||||
|
||||
if(signal.data["done"] && position.z in signal.data["level"])
|
||||
// we're done here.
|
||||
return
|
||||
|
||||
// Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level.
|
||||
// Send a mundane broadcast with limited targets:
|
||||
Broadcast_Message(M, voicemask,
|
||||
src, message, voice, jobname, real_name,
|
||||
filter_type, signal.data["compression"], list(position.z), freq, spans,
|
||||
verb_say, verb_ask, verb_exclaim, verb_yell)
|
||||
|
||||
/obj/item/device/radio/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
|
||||
if(radio_freq)
|
||||
return
|
||||
if(broadcasting)
|
||||
if(get_dist(src, speaker) <= canhear_range)
|
||||
talk_into(speaker, raw_message, , spans)
|
||||
/*
|
||||
/obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message)
|
||||
|
||||
if ((R.frequency == frequency && message))
|
||||
return 1
|
||||
else if
|
||||
|
||||
else
|
||||
return null
|
||||
return
|
||||
*/
|
||||
|
||||
|
||||
/obj/item/device/radio/proc/receive_range(freq, level)
|
||||
// check if this radio can receive on the given frequency, and if so,
|
||||
// what the range is in which mobs will hear the radio
|
||||
// returns: -1 if can't receive, range otherwise
|
||||
|
||||
if (wires.is_cut(WIRE_RX))
|
||||
return -1
|
||||
if(!listening)
|
||||
return -1
|
||||
if(!(0 in level))
|
||||
var/turf/position = get_turf(src)
|
||||
if(!position || !(position.z in level))
|
||||
return -1
|
||||
if(freq == SYND_FREQ)
|
||||
if(!(src.syndie)) //Checks to see if it's allowed on that frequency, based on the encryption keys
|
||||
return -1
|
||||
if(freq == CENTCOM_FREQ)
|
||||
if (!(src.centcom))
|
||||
return -1
|
||||
if (!on)
|
||||
return -1
|
||||
if (!freq) //received on main frequency
|
||||
if (!listening)
|
||||
return -1
|
||||
else
|
||||
var/accept = (freq==frequency && listening)
|
||||
if (!accept)
|
||||
for(var/ch_name in channels)
|
||||
if(channels[ch_name] & FREQ_LISTENING)
|
||||
if(radiochannels[ch_name] == text2num(freq) || syndie) //the radiochannels list is located in communications.dm
|
||||
accept = 1
|
||||
break
|
||||
if (!accept)
|
||||
return -1
|
||||
return canhear_range
|
||||
|
||||
/obj/item/device/radio/proc/send_hear(freq, level)
|
||||
|
||||
var/range = receive_range(freq, level)
|
||||
if(range > -1)
|
||||
return get_hearers_in_view(canhear_range, src)
|
||||
|
||||
|
||||
/obj/item/device/radio/examine(mob/user)
|
||||
..()
|
||||
if (b_stat)
|
||||
user << "<span class='notice'>[name] can be attached and modified.</span>"
|
||||
else
|
||||
user << "<span class='notice'>[name] can not be modified or attached.</span>"
|
||||
|
||||
/obj/item/device/radio/attackby(obj/item/weapon/W, mob/user, params)
|
||||
add_fingerprint(user)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
b_stat = !b_stat
|
||||
if(b_stat)
|
||||
user << "<span class='notice'>The radio can now be attached and modified!</span>"
|
||||
else
|
||||
user << "<span class='notice'>The radio can no longer be modified or attached!</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/device/radio/emp_act(severity)
|
||||
emped++ //There's been an EMP; better count it
|
||||
var/curremp = emped //Remember which EMP this was
|
||||
if (listening && ismob(loc)) // if the radio is turned on and on someone's person they notice
|
||||
loc << "<span class='warning'>\The [src] overloads.</span>"
|
||||
broadcasting = 0
|
||||
listening = 0
|
||||
for (var/ch_name in channels)
|
||||
channels[ch_name] = 0
|
||||
on = 0
|
||||
spawn(200)
|
||||
if(emped == curremp) //Don't fix it if it's been EMP'd again
|
||||
emped = 0
|
||||
if (!istype(src, /obj/item/device/radio/intercom)) // intercoms will turn back on on their own
|
||||
on = 1
|
||||
..()
|
||||
|
||||
///////////////////////////////
|
||||
//////////Borg Radios//////////
|
||||
///////////////////////////////
|
||||
//Giving borgs their own radio to have some more room to work with -Sieve
|
||||
|
||||
/obj/item/device/radio/borg
|
||||
name = "cyborg radio"
|
||||
subspace_switchable = 1
|
||||
dog_fashion = null
|
||||
|
||||
/obj/item/device/radio/borg/syndicate
|
||||
syndie = 1
|
||||
keyslot = new /obj/item/device/encryptionkey/syndicate
|
||||
|
||||
/obj/item/device/radio/borg/syndicate/New()
|
||||
..()
|
||||
set_frequency(SYND_FREQ)
|
||||
|
||||
/obj/item/device/radio/borg/attackby(obj/item/weapon/W, mob/user, params)
|
||||
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
if(keyslot)
|
||||
for(var/ch_name in channels)
|
||||
SSradio.remove_object(src, radiochannels[ch_name])
|
||||
secure_radio_connections[ch_name] = null
|
||||
|
||||
|
||||
if(keyslot)
|
||||
var/turf/T = get_turf(user)
|
||||
if(T)
|
||||
keyslot.loc = T
|
||||
keyslot = null
|
||||
|
||||
recalculateChannels()
|
||||
user << "<span class='notice'>You pop out the encryption key in the radio.</span>"
|
||||
|
||||
else
|
||||
user << "<span class='warning'>This radio doesn't have any encryption keys!</span>"
|
||||
|
||||
else if(istype(W, /obj/item/device/encryptionkey/))
|
||||
if(keyslot)
|
||||
user << "<span class='warning'>The radio can't hold another key!</span>"
|
||||
return
|
||||
|
||||
if(!keyslot)
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
keyslot = W
|
||||
|
||||
recalculateChannels()
|
||||
|
||||
|
||||
/obj/item/device/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag.
|
||||
listening = 0 // And it's nice to have a subtype too for future features.
|
||||
dog_fashion = /datum/dog_fashion/back
|
||||
@@ -0,0 +1,423 @@
|
||||
|
||||
/*
|
||||
CONTAINS:
|
||||
T-RAY
|
||||
DETECTIVE SCANNER
|
||||
HEALTH ANALYZER
|
||||
GAS ANALYZER
|
||||
MASS SPECTROMETER
|
||||
|
||||
*/
|
||||
/obj/item/device/t_scanner
|
||||
name = "\improper T-ray scanner"
|
||||
desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
|
||||
icon_state = "t-ray0"
|
||||
var/on = 0
|
||||
slot_flags = SLOT_BELT
|
||||
w_class = 2
|
||||
item_state = "electronic"
|
||||
materials = list(MAT_METAL=150)
|
||||
origin_tech = "magnets=1;engineering=1"
|
||||
|
||||
/obj/item/device/t_scanner/attack_self(mob/user)
|
||||
|
||||
on = !on
|
||||
icon_state = copytext(icon_state, 1, length(icon_state))+"[on]"
|
||||
|
||||
if(on)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/device/t_scanner/proc/flick_sonar(obj/pipe)
|
||||
var/image/I = image('icons/effects/effects.dmi', pipe, "blip", pipe.layer+1)
|
||||
I.alpha = 128
|
||||
var/list/nearby = list()
|
||||
for(var/mob/M in viewers(pipe))
|
||||
if(M.client)
|
||||
nearby |= M.client
|
||||
flick_overlay(I,nearby,8)
|
||||
|
||||
/obj/item/device/t_scanner/process()
|
||||
if(!on)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return null
|
||||
scan()
|
||||
|
||||
/obj/item/device/t_scanner/proc/scan()
|
||||
|
||||
for(var/turf/T in range(2, src.loc) )
|
||||
for(var/obj/O in T.contents)
|
||||
|
||||
if(O.level != 1)
|
||||
continue
|
||||
|
||||
var/mob/living/L = locate() in O
|
||||
|
||||
if(O.invisibility == INVISIBILITY_MAXIMUM)
|
||||
O.invisibility = 0
|
||||
if(L)
|
||||
flick_sonar(O)
|
||||
spawn(10)
|
||||
if(O && O.loc)
|
||||
var/turf/U = O.loc
|
||||
if(U.intact)
|
||||
O.invisibility = INVISIBILITY_MAXIMUM
|
||||
else
|
||||
if(L)
|
||||
flick_sonar(O)
|
||||
|
||||
|
||||
/obj/item/device/healthanalyzer
|
||||
name = "health analyzer"
|
||||
icon_state = "health"
|
||||
item_state = "analyzer"
|
||||
desc = "A hand-held body scanner able to distinguish vital signs of the subject."
|
||||
flags = CONDUCT | NOBLUDGEON
|
||||
slot_flags = SLOT_BELT
|
||||
throwforce = 3
|
||||
w_class = 1
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
materials = list(MAT_METAL=200)
|
||||
origin_tech = "magnets=1;biotech=1"
|
||||
var/mode = 1
|
||||
var/scanmode = 0
|
||||
|
||||
/obj/item/device/healthanalyzer/attack_self(mob/user)
|
||||
if(!scanmode)
|
||||
user << "<span class='notice'>You switch the health analyzer to scan chemical contents.</span>"
|
||||
scanmode = 1
|
||||
else
|
||||
user << "<span class='notice'>You switch the health analyzer to check physical health.</span>"
|
||||
scanmode = 0
|
||||
|
||||
/obj/item/device/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
|
||||
|
||||
// Clumsiness/brain damage check
|
||||
if ((user.disabilities & CLUMSY || user.getBrainLoss() >= 60) && prob(50))
|
||||
user << "<span class='notice'>You stupidly try to analyze the floor's vitals!</span>"
|
||||
user.visible_message("<span class='warning'>[user] has analyzed the floor's vitals!</span>")
|
||||
user << "<span class='info'>Analyzing results for The floor:\n\tOverall status: <b>Healthy</b>"
|
||||
user << "<span class='info'>Key: <font color='blue'>Suffocation</font>/<font color='green'>Toxin</font>/<font color='#FF8000'>Burn</font>/<font color='red'>Brute</font></span>"
|
||||
user << "<span class='info'>\tDamage specifics: <font color='blue'>0</font>-<font color='green'>0</font>-<font color='#FF8000'>0</font>-<font color='red'>0</font></span>"
|
||||
user << "<span class='info'>Body temperature: ???</span>"
|
||||
return
|
||||
|
||||
user.visible_message("<span class='notice'>[user] has analyzed [M]'s vitals.</span>")
|
||||
|
||||
if(scanmode == 0)
|
||||
healthscan(user, M, mode)
|
||||
else if(scanmode == 1)
|
||||
chemscan(user, M)
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
// Used by the PDA medical scanner too
|
||||
/proc/healthscan(mob/living/user, mob/living/M, mode = 1)
|
||||
if(user.stat || user.eye_blind)
|
||||
return
|
||||
//Damage specifics
|
||||
var/oxy_loss = M.getOxyLoss()
|
||||
var/tox_loss = M.getToxLoss()
|
||||
var/fire_loss = M.getFireLoss()
|
||||
var/brute_loss = M.getBruteLoss()
|
||||
var/mob_status = (M.stat > 1 ? "<span class='alert'><b>Deceased</b></span>" : "<b>[round(M.health/M.maxHealth,0.01)*100] % healthy</b>")
|
||||
|
||||
if(M.status_flags & FAKEDEATH)
|
||||
mob_status = "<span class='alert'>Deceased</span>"
|
||||
oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss
|
||||
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.heart_attack && H.stat != DEAD)
|
||||
user << "<span class='danger'>Subject suffering from heart attack: Apply defibrillator immediately!</span>"
|
||||
user << "<span class='info'>Analyzing results for [M]:\n\tOverall status: [mob_status]</span>"
|
||||
|
||||
// Damage descriptions
|
||||
if(brute_loss > 10)
|
||||
user << "\t<span class='alert'>[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.</span>"
|
||||
if(fire_loss > 10)
|
||||
user << "\t<span class='alert'>[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.</span>"
|
||||
if(oxy_loss > 10)
|
||||
user << "\t<span class='info'><span class='alert'>[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.</span>"
|
||||
if(tox_loss > 10)
|
||||
user << "\t<span class='alert'>[tox_loss > 50 ? "Critical" : "Dangerous"] amount of toxins detected.</span>"
|
||||
if(M.getStaminaLoss())
|
||||
user << "\t<span class='alert'>Subject appears to be suffering from fatigue.</span>"
|
||||
if (M.getCloneLoss())
|
||||
user << "\t<span class='alert'>Subject appears to have [M.getCloneLoss() > 30 ? "severe" : "minor"] cellular damage.</span>"
|
||||
if (M.reagents && M.reagents.get_reagent_amount("epinephrine"))
|
||||
user << "\t<span class='info'>Bloodstream analysis located [M.reagents:get_reagent_amount("epinephrine")] units of rejuvenation chemicals.</span>"
|
||||
if (M.getBrainLoss() >= 100 || !M.getorgan(/obj/item/organ/brain))
|
||||
user << "\t<span class='alert'>Subject brain function is non-existent.</span>"
|
||||
else if (M.getBrainLoss() >= 60)
|
||||
user << "\t<span class='alert'>Severe brain damage detected. Subject likely to have mental retardation.</span>"
|
||||
else if (M.getBrainLoss() >= 10)
|
||||
user << "\t<span class='alert'>Brain damage detected. Subject may have had a concussion.</span>"
|
||||
|
||||
// Organ damage report
|
||||
if(istype(M, /mob/living/carbon/human) && mode == 1)
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/list/damaged = H.get_damaged_bodyparts(1,1)
|
||||
if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0)
|
||||
user << "<span class='info'>\tDamage: <span class='info'><font color='red'>Brute</font></span>-<font color='#FF8000'>Burn</font>-<font color='green'>Toxin</font>-<font color='blue'>Suffocation</font>\n\t\tSpecifics: <font color='red'>[brute_loss]</font>-<font color='#FF8000'>[fire_loss]</font>-<font color='green'>[tox_loss]</font>-<font color='blue'>[oxy_loss]</font></span>"
|
||||
for(var/obj/item/bodypart/org in damaged)
|
||||
user << "\t\t<span class='info'>[capitalize(org.name)]: [(org.brute_dam > 0) ? "<font color='red'>[org.brute_dam]</font></span>" : "<font color='red'>0</font>"]-[(org.burn_dam > 0) ? "<font color='#FF8000'>[org.burn_dam]</font>" : "<font color='#FF8000'>0</font>"]"
|
||||
|
||||
// Species and body temperature
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
user << "<span class='info'>Species: [H.dna.species.name]</span>"
|
||||
user << "<span class='info'>Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)</span>"
|
||||
|
||||
// Time of death
|
||||
if(M.tod && (M.stat == DEAD || (M.status_flags & FAKEDEATH)))
|
||||
user << "<span class='info'>Time of Death:</span> [M.tod]"
|
||||
var/tdelta = round(world.time - M.timeofdeath)
|
||||
if(tdelta < (DEFIB_TIME_LIMIT * 10))
|
||||
user << "<span class='danger'>Subject died [tdelta / 10] seconds \
|
||||
ago, defibrillation may be possible!</span>"
|
||||
|
||||
for(var/datum/disease/D in M.viruses)
|
||||
if(!(D.visibility_flags & HIDDEN_SCANNER))
|
||||
user << "<span class='alert'><b>Warning: [D.form] detected</b>\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]</span>"
|
||||
|
||||
// Blood Level
|
||||
if(M.has_dna())
|
||||
var/mob/living/carbon/C = M
|
||||
var/blood_id = C.get_blood_id()
|
||||
if(blood_id)
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.bleed_rate)
|
||||
user << "<span class='danger'>Subject is bleeding!</span>"
|
||||
var/blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
|
||||
var/blood_type = C.dna.blood_type
|
||||
if(blood_id != "blood")//special blood substance
|
||||
blood_type = blood_id
|
||||
if(C.blood_volume <= BLOOD_VOLUME_SAFE && C.blood_volume > BLOOD_VOLUME_OKAY)
|
||||
user << "<span class='danger'>LOW blood level [blood_percent] %, [C.blood_volume] cl,</span> <span class='info'>type: [blood_type]</span>"
|
||||
else if(C.blood_volume <= BLOOD_VOLUME_OKAY)
|
||||
user << "<span class='danger'>CRITICAL blood level [blood_percent] %, [C.blood_volume] cl,</span> <span class='info'>type: [blood_type]</span>"
|
||||
else
|
||||
user << "<span class='info'>Blood level [blood_percent] %, [C.blood_volume] cl, type: [blood_type]</span>"
|
||||
|
||||
var/implant_detect
|
||||
for(var/obj/item/organ/cyberimp/CI in C.internal_organs)
|
||||
if(CI.status == ORGAN_ROBOTIC)
|
||||
implant_detect += "[C.name] is modified with a [CI.name].<br>"
|
||||
if(implant_detect)
|
||||
user << "<span class='notice'>Detected cybernetic modifications:</span>"
|
||||
user << "<span class='notice'>[implant_detect]</span>"
|
||||
|
||||
/proc/chemscan(mob/living/user, mob/living/M)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.reagents)
|
||||
if(H.reagents.reagent_list.len)
|
||||
user << "<span class='notice'>Subject contains the following reagents:</span>"
|
||||
for(var/datum/reagent/R in H.reagents.reagent_list)
|
||||
user << "<span class='notice'>[R.volume] units of [R.name][R.overdosed == 1 ? "</span> - <span class='boldannounce'>OVERDOSING</span>" : ".</span>"]"
|
||||
else
|
||||
user << "<span class='notice'>Subject contains no reagents.</span>"
|
||||
if(H.reagents.addiction_list.len)
|
||||
user << "<span class='boldannounce'>Subject is addicted to the following reagents:</span>"
|
||||
for(var/datum/reagent/R in H.reagents.addiction_list)
|
||||
user << "<span class='danger'>[R.name]</span>"
|
||||
else
|
||||
user << "<span class='notice'>Subject is not addicted to any reagents.</span>"
|
||||
|
||||
/obj/item/device/healthanalyzer/verb/toggle_mode()
|
||||
set name = "Switch Verbosity"
|
||||
set category = "Object"
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
|
||||
mode = !mode
|
||||
switch (mode)
|
||||
if(1)
|
||||
usr << "The scanner now shows specific limb damage."
|
||||
if(0)
|
||||
usr << "The scanner no longer shows limb damage."
|
||||
|
||||
|
||||
/obj/item/device/analyzer
|
||||
desc = "A hand-held environmental scanner which reports current gas levels."
|
||||
name = "analyzer"
|
||||
icon_state = "atmos"
|
||||
item_state = "analyzer"
|
||||
w_class = 2
|
||||
flags = CONDUCT | NOBLUDGEON
|
||||
slot_flags = SLOT_BELT
|
||||
throwforce = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
materials = list(MAT_METAL=30, MAT_GLASS=20)
|
||||
origin_tech = "magnets=1;engineering=1"
|
||||
|
||||
/obj/item/device/analyzer/attack_self(mob/user)
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
if (user.stat || user.eye_blind)
|
||||
return
|
||||
|
||||
var/turf/location = user.loc
|
||||
if(!istype(location))
|
||||
return
|
||||
|
||||
var/datum/gas_mixture/environment = location.return_air()
|
||||
|
||||
var/pressure = environment.return_pressure()
|
||||
var/total_moles = environment.total_moles()
|
||||
|
||||
user << "<span class='info'><B>Results:</B></span>"
|
||||
if(abs(pressure - ONE_ATMOSPHERE) < 10)
|
||||
user << "<span class='info'>Pressure: [round(pressure,0.1)] kPa</span>"
|
||||
else
|
||||
user << "<span class='alert'>Pressure: [round(pressure,0.1)] kPa</span>"
|
||||
if(total_moles)
|
||||
var/list/env_gases = environment.gases
|
||||
|
||||
environment.assert_gases(arglist(hardcoded_gases))
|
||||
var/o2_concentration = env_gases["o2"][MOLES]/total_moles
|
||||
var/n2_concentration = env_gases["n2"][MOLES]/total_moles
|
||||
var/co2_concentration = env_gases["co2"][MOLES]/total_moles
|
||||
var/plasma_concentration = env_gases["plasma"][MOLES]/total_moles
|
||||
environment.garbage_collect()
|
||||
|
||||
if(abs(n2_concentration - N2STANDARD) < 20)
|
||||
user << "<span class='info'>Nitrogen: [round(n2_concentration*100, 0.01)] %</span>"
|
||||
else
|
||||
user << "<span class='alert'>Nitrogen: [round(n2_concentration*100, 0.01)] %</span>"
|
||||
|
||||
if(abs(o2_concentration - O2STANDARD) < 2)
|
||||
user << "<span class='info'>Oxygen: [round(o2_concentration*100, 0.01)] %</span>"
|
||||
else
|
||||
user << "<span class='alert'>Oxygen: [round(o2_concentration*100, 0.01)] %</span>"
|
||||
|
||||
if(co2_concentration > 0.01)
|
||||
user << "<span class='alert'>CO2: [round(co2_concentration*100, 0.01)] %</span>"
|
||||
else
|
||||
user << "<span class='info'>CO2: [round(co2_concentration*100, 0.01)] %</span>"
|
||||
|
||||
if(plasma_concentration > 0.005)
|
||||
user << "<span class='alert'>Plasma: [round(plasma_concentration*100, 0.01)] %</span>"
|
||||
else
|
||||
user << "<span class='info'>Plasma: [round(plasma_concentration*100, 0.01)] %</span>"
|
||||
|
||||
|
||||
for(var/id in env_gases)
|
||||
if(id in hardcoded_gases)
|
||||
continue
|
||||
var/gas_concentration = env_gases[id][MOLES]/total_moles
|
||||
user << "<span class='alert'>[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] %</span>"
|
||||
user << "<span class='info'>Temperature: [round(environment.temperature-T0C)] °C</span>"
|
||||
|
||||
|
||||
/obj/item/device/mass_spectrometer
|
||||
desc = "A hand-held mass spectrometer which identifies trace chemicals in a blood sample."
|
||||
name = "mass-spectrometer"
|
||||
icon_state = "spectrometer"
|
||||
item_state = "analyzer"
|
||||
w_class = 2
|
||||
flags = CONDUCT | OPENCONTAINER
|
||||
slot_flags = SLOT_BELT
|
||||
throwforce = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
materials = list(MAT_METAL=150, MAT_GLASS=100)
|
||||
origin_tech = "magnets=2;biotech=1;plasmatech=2"
|
||||
var/details = 0
|
||||
|
||||
/obj/item/device/mass_spectrometer/New()
|
||||
..()
|
||||
create_reagents(5)
|
||||
|
||||
/obj/item/device/mass_spectrometer/on_reagent_change()
|
||||
if(reagents.total_volume)
|
||||
icon_state = initial(icon_state) + "_s"
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/item/device/mass_spectrometer/attack_self(mob/user)
|
||||
if (user.stat || user.eye_blind)
|
||||
return
|
||||
if (!user.IsAdvancedToolUser())
|
||||
user << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
||||
return
|
||||
if(reagents.total_volume)
|
||||
var/list/blood_traces = list()
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if(R.id != "blood")
|
||||
reagents.clear_reagents()
|
||||
user << "<span class='warning'>The sample was contaminated! Please insert another sample.</span>"
|
||||
return
|
||||
else
|
||||
blood_traces = params2list(R.data["trace_chem"])
|
||||
break
|
||||
var/dat = "<i><b>Trace Chemicals Found:</b>"
|
||||
if(!blood_traces.len)
|
||||
dat += "<br>None"
|
||||
else
|
||||
for(var/R in blood_traces)
|
||||
dat += "<br>[chemical_reagents_list[R]]"
|
||||
if(details)
|
||||
dat += " ([blood_traces[R]] units)"
|
||||
dat += "</i>"
|
||||
user << dat
|
||||
reagents.clear_reagents()
|
||||
|
||||
|
||||
/obj/item/device/mass_spectrometer/adv
|
||||
name = "advanced mass-spectrometer"
|
||||
icon_state = "adv_spectrometer"
|
||||
details = 1
|
||||
origin_tech = "magnets=4;biotech=3;plasmatech=3"
|
||||
|
||||
/obj/item/device/slime_scanner
|
||||
name = "slime scanner"
|
||||
desc = "A device that analyzes a slime's internal composition and measures its stats."
|
||||
icon_state = "adv_spectrometer"
|
||||
item_state = "analyzer"
|
||||
origin_tech = "biotech=2"
|
||||
w_class = 2
|
||||
flags = CONDUCT
|
||||
throwforce = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
materials = list(MAT_METAL=30, MAT_GLASS=20)
|
||||
|
||||
/obj/item/device/slime_scanner/attack(mob/living/M, mob/living/user)
|
||||
if(user.stat || user.eye_blind)
|
||||
return
|
||||
if (!isslime(M))
|
||||
user << "<span class='warning'>This device can only scan slimes!</span>"
|
||||
return
|
||||
var/mob/living/simple_animal/slime/T = M
|
||||
user << "Slime scan results:"
|
||||
user << "[T.colour] [T.is_adult ? "adult" : "baby"] slime"
|
||||
user << "Nutrition: [T.nutrition]/[T.get_max_nutrition()]"
|
||||
if (T.nutrition < T.get_starve_nutrition())
|
||||
user << "<span class='warning'>Warning: slime is starving!</span>"
|
||||
else if (T.nutrition < T.get_hunger_nutrition())
|
||||
user << "<span class='warning'>Warning: slime is hungry</span>"
|
||||
user << "Electric change strength: [T.powerlevel]"
|
||||
user << "Health: [round(T.health/T.maxHealth,0.01)*100]"
|
||||
if (T.slime_mutation[4] == T.colour)
|
||||
user << "This slime does not evolve any further."
|
||||
else
|
||||
if (T.slime_mutation[3] == T.slime_mutation[4])
|
||||
if (T.slime_mutation[2] == T.slime_mutation[1])
|
||||
user << "Possible mutation: [T.slime_mutation[3]]"
|
||||
user << "Genetic destability: [T.mutation_chance/2] % chance of mutation on splitting"
|
||||
else
|
||||
user << "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)"
|
||||
user << "Genetic destability: [T.mutation_chance] % chance of mutation on splitting"
|
||||
else
|
||||
user << "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]"
|
||||
user << "Genetic destability: [T.mutation_chance] % chance of mutation on splitting"
|
||||
if (T.cores > 1)
|
||||
user << "Anomalious slime core amount detected"
|
||||
user << "Growth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]"
|
||||
@@ -0,0 +1,11 @@
|
||||
/obj/item/device/sensor_device
|
||||
name = "handheld crew monitor" //Thanks to Gun Hog for the name!
|
||||
desc = "A miniature machine that tracks suit sensors across the station."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "scanner"
|
||||
w_class = 2
|
||||
slot_flags = SLOT_BELT
|
||||
origin_tech = "programming=3;materials=3;magnets=3"
|
||||
|
||||
/obj/item/device/sensor_device/attack_self(mob/user)
|
||||
crewmonitor.show(user) //Proc already exists, just had to call it
|
||||
@@ -0,0 +1,280 @@
|
||||
/obj/item/device/taperecorder
|
||||
name = "universal recorder"
|
||||
desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback."
|
||||
icon_state = "taperecorder_empty"
|
||||
item_state = "analyzer"
|
||||
w_class = 2
|
||||
flags = HEAR
|
||||
slot_flags = SLOT_BELT
|
||||
languages_spoken = ALL //this is a translator, after all.
|
||||
languages_understood = ALL //this is a translator, after all.
|
||||
materials = list(MAT_METAL=60, MAT_GLASS=30)
|
||||
force = 2
|
||||
throwforce = 0
|
||||
var/recording = 0
|
||||
var/playing = 0
|
||||
var/playsleepseconds = 0
|
||||
var/obj/item/device/tape/mytape
|
||||
var/open_panel = 0
|
||||
var/canprint = 1
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/New()
|
||||
mytape = new /obj/item/device/tape/random(src)
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/examine(mob/user)
|
||||
..()
|
||||
user << "The wire panel is [open_panel ? "opened" : "closed"]."
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/attackby(obj/item/I, mob/user, params)
|
||||
if(!mytape && istype(I, /obj/item/device/tape))
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
I.loc = src
|
||||
mytape = I
|
||||
user << "<span class='notice'>You insert [I] into [src].</span>"
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/proc/eject(mob/user)
|
||||
if(mytape)
|
||||
user << "<span class='notice'>You remove [mytape] from [src].</span>"
|
||||
stop()
|
||||
user.put_in_hands(mytape)
|
||||
mytape = null
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/taperecorder/fire_act()
|
||||
mytape.ruin() //Fires destroy the tape
|
||||
return()
|
||||
|
||||
/obj/item/device/taperecorder/attack_hand(mob/user)
|
||||
if(loc == user)
|
||||
if(mytape)
|
||||
if(user.l_hand != src && user.r_hand != src)
|
||||
..()
|
||||
return
|
||||
eject(user)
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/proc/can_use(mob/user)
|
||||
if(user && ismob(user))
|
||||
if(!user.incapacitated())
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/verb/ejectverb()
|
||||
set name = "Eject Tape"
|
||||
set category = "Object"
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape)
|
||||
return
|
||||
|
||||
eject(usr)
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/update_icon()
|
||||
if(!mytape)
|
||||
icon_state = "taperecorder_empty"
|
||||
else if(recording)
|
||||
icon_state = "taperecorder_recording"
|
||||
else if(playing)
|
||||
icon_state = "taperecorder_playing"
|
||||
else
|
||||
icon_state = "taperecorder_idle"
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans)
|
||||
if(mytape && recording)
|
||||
mytape.timestamp += mytape.used_capacity
|
||||
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [message]"
|
||||
|
||||
/obj/item/device/taperecorder/verb/record()
|
||||
set name = "Start Recording"
|
||||
set category = "Object"
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape || mytape.ruined)
|
||||
return
|
||||
if(recording)
|
||||
return
|
||||
if(playing)
|
||||
return
|
||||
|
||||
if(mytape.used_capacity < mytape.max_capacity)
|
||||
usr << "<span class='notice'>Recording started.</span>"
|
||||
recording = 1
|
||||
update_icon()
|
||||
mytape.timestamp += mytape.used_capacity
|
||||
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording started."
|
||||
var/used = mytape.used_capacity //to stop runtimes when you eject the tape
|
||||
var/max = mytape.max_capacity
|
||||
for(used, used < max)
|
||||
if(recording == 0)
|
||||
break
|
||||
mytape.used_capacity++
|
||||
used++
|
||||
sleep(10)
|
||||
recording = 0
|
||||
update_icon()
|
||||
else
|
||||
usr << "<span class='notice'>The tape is full.</span>"
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/verb/stop()
|
||||
set name = "Stop"
|
||||
set category = "Object"
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
|
||||
if(recording)
|
||||
recording = 0
|
||||
mytape.timestamp += mytape.used_capacity
|
||||
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording stopped."
|
||||
usr << "<span class='notice'>Recording stopped.</span>"
|
||||
return
|
||||
else if(playing)
|
||||
playing = 0
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<font color=Maroon><B>Tape Recorder</B>: Playback stopped.</font>")
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/verb/play()
|
||||
set name = "Play Tape"
|
||||
set category = "Object"
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape || mytape.ruined)
|
||||
return
|
||||
if(recording)
|
||||
return
|
||||
if(playing)
|
||||
return
|
||||
|
||||
playing = 1
|
||||
update_icon()
|
||||
usr << "<span class='notice'>Playing started.</span>"
|
||||
var/used = mytape.used_capacity //to stop runtimes when you eject the tape
|
||||
var/max = mytape.max_capacity
|
||||
for(var/i = 1, used < max, sleep(10 * playsleepseconds))
|
||||
if(!mytape)
|
||||
break
|
||||
if(playing == 0)
|
||||
break
|
||||
if(mytape.storedinfo.len < i)
|
||||
break
|
||||
say(mytape.storedinfo[i])
|
||||
if(mytape.storedinfo.len < i + 1)
|
||||
playsleepseconds = 1
|
||||
sleep(10)
|
||||
say("End of recording.")
|
||||
else
|
||||
playsleepseconds = mytape.timestamp[i + 1] - mytape.timestamp[i]
|
||||
if(playsleepseconds > 14)
|
||||
sleep(10)
|
||||
say("Skipping [playsleepseconds] seconds of silence")
|
||||
playsleepseconds = 1
|
||||
i++
|
||||
|
||||
playing = 0
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/attack_self(mob/user)
|
||||
if(!mytape || mytape.ruined)
|
||||
return
|
||||
if(recording)
|
||||
stop()
|
||||
else
|
||||
record()
|
||||
|
||||
|
||||
/obj/item/device/taperecorder/verb/print_transcript()
|
||||
set name = "Print Transcript"
|
||||
set category = "Object"
|
||||
|
||||
if(!can_use(usr))
|
||||
return
|
||||
if(!mytape)
|
||||
return
|
||||
if(!canprint)
|
||||
usr << "<span class='notice'>The recorder can't print that fast!</span>"
|
||||
return
|
||||
if(recording || playing)
|
||||
return
|
||||
|
||||
usr << "<span class='notice'>Transcript printed.</span>"
|
||||
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(get_turf(src))
|
||||
var/t1 = "<B>Transcript:</B><BR><BR>"
|
||||
for(var/i = 1, mytape.storedinfo.len >= i, i++)
|
||||
t1 += "[mytape.storedinfo[i]]<BR>"
|
||||
P.info = t1
|
||||
P.name = "paper- 'Transcript'"
|
||||
usr.put_in_hands(P)
|
||||
canprint = 0
|
||||
sleep(300)
|
||||
canprint = 1
|
||||
|
||||
|
||||
//empty tape recorders
|
||||
/obj/item/device/taperecorder/empty/New()
|
||||
return
|
||||
|
||||
|
||||
/obj/item/device/tape
|
||||
name = "tape"
|
||||
desc = "A magnetic tape that can hold up to ten minutes of content."
|
||||
icon_state = "tape_white"
|
||||
item_state = "analyzer"
|
||||
w_class = 1
|
||||
materials = list(MAT_METAL=20, MAT_GLASS=5)
|
||||
force = 1
|
||||
throwforce = 0
|
||||
var/max_capacity = 600
|
||||
var/used_capacity = 0
|
||||
var/list/storedinfo = list()
|
||||
var/list/timestamp = list()
|
||||
var/ruined = 0
|
||||
|
||||
/obj/item/device/tape/fire_act()
|
||||
ruin()
|
||||
|
||||
/obj/item/device/tape/attack_self(mob/user)
|
||||
if(!ruined)
|
||||
user << "<span class='notice'>You pull out all the tape!</span>"
|
||||
ruin()
|
||||
|
||||
|
||||
/obj/item/device/tape/proc/ruin()
|
||||
add_overlay("ribbonoverlay")
|
||||
ruined = 1
|
||||
|
||||
|
||||
/obj/item/device/tape/proc/fix()
|
||||
overlays -= "ribbonoverlay"
|
||||
ruined = 0
|
||||
|
||||
|
||||
/obj/item/device/tape/attackby(obj/item/I, mob/user, params)
|
||||
if(ruined && istype(I, /obj/item/weapon/screwdriver))
|
||||
user << "<span class='notice'>You start winding the tape back in...</span>"
|
||||
if(do_after(user, 120/I.toolspeed, target = src))
|
||||
user << "<span class='notice'>You wound the tape back in.</span>"
|
||||
fix()
|
||||
|
||||
|
||||
//Random colour tapes
|
||||
/obj/item/device/tape/random/New()
|
||||
icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
|
||||
Miscellaneous traitor devices
|
||||
|
||||
BATTERER
|
||||
|
||||
RADIOACTIVE MICROLASER
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
The Batterer, like a flashbang but 50% chance to knock people over. Can be either very
|
||||
effective or pretty fucking useless.
|
||||
|
||||
*/
|
||||
|
||||
/obj/item/device/batterer
|
||||
name = "mind batterer"
|
||||
desc = "A strange device with twin antennas."
|
||||
icon_state = "batterer"
|
||||
throwforce = 5
|
||||
w_class = 1
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
flags = CONDUCT
|
||||
item_state = "electronic"
|
||||
origin_tech = "magnets=3;combat=3;syndicate=3"
|
||||
|
||||
var/times_used = 0 //Number of times it's been used.
|
||||
var/max_uses = 2
|
||||
|
||||
|
||||
/obj/item/device/batterer/attack_self(mob/living/carbon/user, flag = 0, emp = 0)
|
||||
if(!user) return
|
||||
if(times_used >= max_uses)
|
||||
user << "<span class='danger'>The mind batterer has been burnt out!</span>"
|
||||
return
|
||||
|
||||
add_logs(user, null, "knocked down people in the area", src)
|
||||
|
||||
for(var/mob/living/carbon/human/M in urange(10, user, 1))
|
||||
if(prob(50))
|
||||
|
||||
M.Weaken(rand(10,20))
|
||||
if(prob(25))
|
||||
M.Stun(rand(5,10))
|
||||
M << "<span class='userdanger'>You feel a tremendous, paralyzing wave flood your mind.</span>"
|
||||
|
||||
else
|
||||
M << "<span class='userdanger'>You feel a sudden, electric jolt travel through your head.</span>"
|
||||
|
||||
playsound(src.loc, 'sound/misc/interference.ogg', 50, 1)
|
||||
user << "<span class='notice'>You trigger [src].</span>"
|
||||
times_used += 1
|
||||
if(times_used >= max_uses)
|
||||
icon_state = "battererburnt"
|
||||
|
||||
/*
|
||||
The radioactive microlaser, a device disguised as a health analyzer used to irradiate people.
|
||||
|
||||
The strength of the radiation is determined by the 'intensity' setting, while the delay between
|
||||
the scan and the irradiation kicking in is determined by the wavelength.
|
||||
|
||||
Each scan will cause the microlaser to have a brief cooldown period. Higher intensity will increase
|
||||
the cooldown, while higher wavelength will decrease it.
|
||||
|
||||
Wavelength is also slightly increased by the intensity as well.
|
||||
*/
|
||||
|
||||
/obj/item/device/healthanalyzer/rad_laser
|
||||
materials = list(MAT_METAL=400)
|
||||
origin_tech = "magnets=3;biotech=5;syndicate=3"
|
||||
var/irradiate = 1
|
||||
var/intensity = 10 // how much damage the radiation does
|
||||
var/wavelength = 10 // time it takes for the radiation to kick in, in seconds
|
||||
var/used = 0 // is it cooling down?
|
||||
|
||||
/obj/item/device/healthanalyzer/rad_laser/attack(mob/living/M, mob/living/user)
|
||||
..()
|
||||
if(!irradiate)
|
||||
return
|
||||
if(!used)
|
||||
add_logs(user, M, "irradiated", src)
|
||||
var/cooldown = round(max(10, (intensity*5 - wavelength/4))) * 10
|
||||
used = 1
|
||||
icon_state = "health1"
|
||||
handle_cooldown(cooldown) // splits off to handle the cooldown while handling wavelength
|
||||
user << "<span class='warning'>Successfully irradiated [M].</span>"
|
||||
spawn((wavelength+(intensity*4))*5)
|
||||
if(M)
|
||||
if(intensity >= 5)
|
||||
M.apply_effect(round(intensity/1.5), PARALYZE)
|
||||
M.rad_act(intensity*10)
|
||||
else
|
||||
user << "<span class='warning'>The radioactive microlaser is still recharging.</span>"
|
||||
|
||||
/obj/item/device/healthanalyzer/rad_laser/proc/handle_cooldown(cooldown)
|
||||
spawn(cooldown)
|
||||
used = 0
|
||||
icon_state = "health"
|
||||
|
||||
/obj/item/device/healthanalyzer/rad_laser/attack_self(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/item/device/healthanalyzer/rad_laser/interact(mob/user)
|
||||
user.set_machine(src)
|
||||
|
||||
var/cooldown = round(max(10, (intensity*5 - wavelength/4)))
|
||||
var/dat = "Irradiation: <A href='?src=\ref[src];rad=1'>[irradiate ? "On" : "Off"]</A><br>"
|
||||
dat += "Scan Mode: <a href='?src=\ref[src];mode=1'>"
|
||||
if(!scanmode)
|
||||
dat += "Scan Health"
|
||||
else if(scanmode == 1)
|
||||
dat += "Scan Reagents"
|
||||
else
|
||||
dat += "Disabled"
|
||||
dat += "</a><br><br>"
|
||||
|
||||
dat += {"
|
||||
Radiation Intensity:
|
||||
<A href='?src=\ref[src];radint=-5'>-</A><A href='?src=\ref[src];radint=-1'>-</A>
|
||||
[intensity]
|
||||
<A href='?src=\ref[src];radint=1'>+</A><A href='?src=\ref[src];radint=5'>+</A><BR>
|
||||
|
||||
Radiation Wavelength:
|
||||
<A href='?src=\ref[src];radwav=-5'>-</A><A href='?src=\ref[src];radwav=-1'>-</A>
|
||||
[(wavelength+(intensity*4))]
|
||||
<A href='?src=\ref[src];radwav=1'>+</A><A href='?src=\ref[src];radwav=5'>+</A><BR>
|
||||
Laser Cooldown: [cooldown] Seconds<BR>
|
||||
"}
|
||||
|
||||
var/datum/browser/popup = new(user, "radlaser", "Radioactive Microlaser Interface", 400, 240)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
/obj/item/device/healthanalyzer/rad_laser/Topic(href, href_list)
|
||||
if(!usr.canUseTopic(src))
|
||||
return 1
|
||||
|
||||
usr.set_machine(src)
|
||||
if(href_list["rad"])
|
||||
irradiate = !irradiate
|
||||
|
||||
else if(href_list["mode"])
|
||||
scanmode += 1
|
||||
if(scanmode > 2)
|
||||
scanmode = 0
|
||||
|
||||
else if(href_list["radint"])
|
||||
var/amount = text2num(href_list["radint"])
|
||||
amount += intensity
|
||||
intensity = max(1,(min(20,amount)))
|
||||
|
||||
else if(href_list["radwav"])
|
||||
var/amount = text2num(href_list["radwav"])
|
||||
amount += wavelength
|
||||
wavelength = max(0,(min(120,amount)))
|
||||
|
||||
attack_self(usr)
|
||||
add_fingerprint(usr)
|
||||
return
|
||||
|
||||
/obj/item/device/shadowcloak
|
||||
name = "cloaker belt"
|
||||
desc = "Makes you invisible for short periods of time. Recharges in darkness."
|
||||
icon = 'icons/obj/clothing/belts.dmi'
|
||||
icon_state = "utilitybelt"
|
||||
item_state = "utility"
|
||||
slot_flags = SLOT_BELT
|
||||
attack_verb = list("whipped", "lashed", "disciplined")
|
||||
|
||||
var/mob/living/carbon/human/user = null
|
||||
var/charge = 300
|
||||
var/max_charge = 300
|
||||
var/on = 0
|
||||
var/old_alpha = 0
|
||||
actions_types = list(/datum/action/item_action/toggle)
|
||||
|
||||
/obj/item/device/shadowcloak/ui_action_click(mob/user)
|
||||
if(user.get_item_by_slot(slot_belt) == src)
|
||||
if(!on)
|
||||
Activate(usr)
|
||||
else
|
||||
Deactivate()
|
||||
return
|
||||
|
||||
/obj/item/device/shadowcloak/item_action_slot_check(slot, mob/user)
|
||||
if(slot == slot_belt)
|
||||
return 1
|
||||
|
||||
/obj/item/device/shadowcloak/proc/Activate(mob/living/carbon/human/user)
|
||||
if(!user)
|
||||
return
|
||||
user << "<span class='notice'>You activate [src].</span>"
|
||||
src.user = user
|
||||
START_PROCESSING(SSobj, src)
|
||||
old_alpha = user.alpha
|
||||
on = 1
|
||||
|
||||
/obj/item/device/shadowcloak/proc/Deactivate()
|
||||
user << "<span class='notice'>You deactivate [src].</span>"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(user)
|
||||
user.alpha = old_alpha
|
||||
on = 0
|
||||
user = null
|
||||
|
||||
/obj/item/device/shadowcloak/dropped(mob/user)
|
||||
..()
|
||||
if(user && user.get_item_by_slot(slot_belt) != src)
|
||||
Deactivate()
|
||||
|
||||
/obj/item/device/shadowcloak/process()
|
||||
if(user.get_item_by_slot(slot_belt) != src)
|
||||
Deactivate()
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(on)
|
||||
var/lumcount = T.get_lumcount()
|
||||
if(lumcount > 3)
|
||||
charge = max(0,charge - 25)//Quick decrease in light
|
||||
else
|
||||
charge = min(max_charge,charge + 50) //Charge in the dark
|
||||
animate(user,alpha = Clamp(255 - charge,0,255),time = 10)
|
||||
@@ -0,0 +1,213 @@
|
||||
/obj/item/device/transfer_valve
|
||||
icon = 'icons/obj/assemblies.dmi'
|
||||
name = "tank transfer valve"
|
||||
icon_state = "valve_1"
|
||||
item_state = "ttv"
|
||||
desc = "Regulates the transfer of air between two tanks"
|
||||
var/obj/item/weapon/tank/tank_one
|
||||
var/obj/item/weapon/tank/tank_two
|
||||
var/obj/item/device/attached_device
|
||||
var/mob/attacher = null
|
||||
var/valve_open = 0
|
||||
var/toggle = 1
|
||||
origin_tech = "materials=1;engineering=1"
|
||||
|
||||
/obj/item/device/transfer_valve/IsAssemblyHolder()
|
||||
return 1
|
||||
|
||||
/obj/item/device/transfer_valve/attackby(obj/item/item, mob/user, params)
|
||||
if(istype(item, /obj/item/weapon/tank))
|
||||
if(tank_one && tank_two)
|
||||
user << "<span class='warning'>There are already two tanks attached, remove one first!</span>"
|
||||
return
|
||||
|
||||
if(!tank_one)
|
||||
if(!user.unEquip(item))
|
||||
return
|
||||
tank_one = item
|
||||
item.loc = src
|
||||
user << "<span class='notice'>You attach the tank to the transfer valve.</span>"
|
||||
if(item.w_class > w_class)
|
||||
w_class = item.w_class
|
||||
else if(!tank_two)
|
||||
if(!user.unEquip(item))
|
||||
return
|
||||
tank_two = item
|
||||
item.loc = src
|
||||
user << "<span class='notice'>You attach the tank to the transfer valve.</span>"
|
||||
if(item.w_class > w_class)
|
||||
w_class = item.w_class
|
||||
|
||||
update_icon()
|
||||
//TODO: Have this take an assemblyholder
|
||||
else if(isassembly(item))
|
||||
var/obj/item/device/assembly/A = item
|
||||
if(A.secured)
|
||||
user << "<span class='notice'>The device is secured.</span>"
|
||||
return
|
||||
if(attached_device)
|
||||
user << "<span class='warning'>There is already a device attached to the valve, remove it first!</span>"
|
||||
return
|
||||
user.remove_from_mob(item)
|
||||
attached_device = A
|
||||
A.loc = src
|
||||
user << "<span class='notice'>You attach the [item] to the valve controls and secure it.</span>"
|
||||
A.holder = src
|
||||
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
|
||||
|
||||
bombers += "[key_name(user)] attached a [item] to a transfer valve."
|
||||
message_admins("[key_name_admin(user)] attached a [item] to a transfer valve.")
|
||||
log_game("[key_name_admin(user)] attached a [item] to a transfer valve.")
|
||||
attacher = user
|
||||
return
|
||||
|
||||
/obj/item/device/transfer_valve/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
var/dat = {"<B> Valve properties: </B>
|
||||
<BR> <B> Attachment one:</B> [tank_one] [tank_one ? "<A href='?src=\ref[src];tankone=1'>Remove</A>" : ""]
|
||||
<BR> <B> Attachment two:</B> [tank_two] [tank_two ? "<A href='?src=\ref[src];tanktwo=1'>Remove</A>" : ""]
|
||||
<BR> <B> Valve attachment:</B> [attached_device ? "<A href='?src=\ref[src];device=1'>[attached_device]</A>" : "None"] [attached_device ? "<A href='?src=\ref[src];rem_device=1'>Remove</A>" : ""]
|
||||
<BR> <B> Valve status: </B> [ valve_open ? "<A href='?src=\ref[src];open=1'>Closed</A> <B>Open</B>" : "<B>Closed</B> <A href='?src=\ref[src];open=1'>Open</A>"]"}
|
||||
|
||||
var/datum/browser/popup = new(user, "trans_valve", name)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/item/device/transfer_valve/Topic(href, href_list)
|
||||
..()
|
||||
if ( usr.stat || usr.restrained() )
|
||||
return
|
||||
if (src.loc == usr)
|
||||
if(tank_one && href_list["tankone"])
|
||||
split_gases()
|
||||
valve_open = 0
|
||||
tank_one.loc = get_turf(src)
|
||||
tank_one = null
|
||||
update_icon()
|
||||
if((!tank_two || tank_two.w_class < 4) && (w_class > 3))
|
||||
w_class = 3
|
||||
else if(tank_two && href_list["tanktwo"])
|
||||
split_gases()
|
||||
valve_open = 0
|
||||
tank_two.loc = get_turf(src)
|
||||
tank_two = null
|
||||
update_icon()
|
||||
if((!tank_one || tank_one.w_class < 4) && (w_class > 3))
|
||||
w_class = 3
|
||||
else if(href_list["open"])
|
||||
toggle_valve()
|
||||
else if(attached_device)
|
||||
if(href_list["rem_device"])
|
||||
attached_device.loc = get_turf(src)
|
||||
attached_device:holder = null
|
||||
attached_device = null
|
||||
update_icon()
|
||||
if(href_list["device"])
|
||||
attached_device.attack_self(usr)
|
||||
|
||||
src.attack_self(usr)
|
||||
src.add_fingerprint(usr)
|
||||
return
|
||||
return
|
||||
|
||||
/obj/item/device/transfer_valve/proc/process_activation(obj/item/device/D)
|
||||
if(toggle)
|
||||
toggle = 0
|
||||
toggle_valve()
|
||||
spawn(50) // To stop a signal being spammed from a proxy sensor constantly going off or whatever
|
||||
toggle = 1
|
||||
|
||||
/obj/item/device/transfer_valve/update_icon()
|
||||
cut_overlays()
|
||||
underlays = null
|
||||
|
||||
if(!tank_one && !tank_two && !attached_device)
|
||||
icon_state = "valve_1"
|
||||
return
|
||||
icon_state = "valve"
|
||||
|
||||
if(tank_one)
|
||||
add_overlay("[tank_one.icon_state]")
|
||||
if(tank_two)
|
||||
var/icon/J = new(icon, icon_state = "[tank_two.icon_state]")
|
||||
J.Shift(WEST, 13)
|
||||
underlays += J
|
||||
if(attached_device)
|
||||
add_overlay("device")
|
||||
|
||||
/obj/item/device/transfer_valve/proc/merge_gases()
|
||||
tank_two.air_contents.volume += tank_one.air_contents.volume
|
||||
var/datum/gas_mixture/temp
|
||||
temp = tank_one.air_contents.remove_ratio(1)
|
||||
tank_two.air_contents.merge(temp)
|
||||
|
||||
/obj/item/device/transfer_valve/proc/split_gases()
|
||||
if (!valve_open || !tank_one || !tank_two)
|
||||
return
|
||||
var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume
|
||||
var/datum/gas_mixture/temp
|
||||
temp = tank_two.air_contents.remove_ratio(ratio1)
|
||||
tank_one.air_contents.merge(temp)
|
||||
tank_two.air_contents.volume -= tank_one.air_contents.volume
|
||||
|
||||
/*
|
||||
Exadv1: I know this isn't how it's going to work, but this was just to check
|
||||
it explodes properly when it gets a signal (and it does).
|
||||
*/
|
||||
|
||||
/obj/item/device/transfer_valve/proc/toggle_valve()
|
||||
if(!valve_open && tank_one && tank_two)
|
||||
valve_open = 1
|
||||
var/turf/bombturf = get_turf(src)
|
||||
var/area/A = get_area(bombturf)
|
||||
|
||||
var/attachment = "no device"
|
||||
if(attached_device)
|
||||
if(istype(attached_device, /obj/item/device/assembly/signaler))
|
||||
attachment = "<A HREF='?_src_=holder;secrets=list_signalers'>[attached_device]</A>"
|
||||
else
|
||||
attachment = attached_device
|
||||
|
||||
var/attacher_name = ""
|
||||
if(!attacher)
|
||||
attacher_name = "Unknown"
|
||||
else
|
||||
attacher_name = "[key_name_admin(attacher)]"
|
||||
|
||||
var/log_str1 = "Bomb valve opened in "
|
||||
var/log_str2 = "with [attachment] attacher: [attacher_name]"
|
||||
|
||||
var/log_attacher = ""
|
||||
if(attacher)
|
||||
log_attacher = "(<A HREF='?_src_=holder;adminmoreinfo=\ref[attacher]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[attacher]'>FLW</A>)"
|
||||
|
||||
var/mob/mob = get_mob_by_key(src.fingerprintslast)
|
||||
var/last_touch_info = ""
|
||||
if(mob)
|
||||
last_touch_info = "(<A HREF='?_src_=holder;adminmoreinfo=\ref[mob]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[mob]'>FLW</A>)"
|
||||
|
||||
var/log_str3 = " Last touched by: [key_name_admin(mob)]"
|
||||
|
||||
var/bomb_message = "[log_str1] <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name]</a> [log_str2][log_attacher] [log_str3][last_touch_info]"
|
||||
|
||||
bombers += bomb_message
|
||||
|
||||
message_admins(bomb_message, 0, 1)
|
||||
log_game("[log_str1] [A.name]([A.x],[A.y],[A.z]) [log_str2] [log_str3]")
|
||||
merge_gases()
|
||||
spawn(20) // In case one tank bursts
|
||||
for (var/i=0,i<5,i++)
|
||||
src.update_icon()
|
||||
sleep(10)
|
||||
src.update_icon()
|
||||
|
||||
else if(valve_open && tank_one && tank_two)
|
||||
split_gases()
|
||||
valve_open = 0
|
||||
src.update_icon()
|
||||
|
||||
// this doesn't do anything but the timer etc. expects it to be here
|
||||
// eventually maybe have it update icon to show state (timer, prox etc.) like old bombs
|
||||
/obj/item/device/transfer_valve/proc/c_state()
|
||||
return
|
||||
@@ -0,0 +1,57 @@
|
||||
/obj/item/documents
|
||||
name = "secret documents"
|
||||
desc = "\"Top Secret\" documents."
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
icon_state = "docs_generic"
|
||||
item_state = "paper"
|
||||
throwforce = 0
|
||||
w_class = 1
|
||||
throw_range = 1
|
||||
throw_speed = 1
|
||||
layer = MOB_LAYER
|
||||
pressure_resistance = 1
|
||||
|
||||
/obj/item/documents/nanotrasen
|
||||
desc = "\"Top Secret\" Nanotrasen documents, filled with complex diagrams and lists of names, dates and coordinates."
|
||||
icon_state = "docs_verified"
|
||||
|
||||
/obj/item/documents/syndicate
|
||||
desc = "\"Top Secret\" documents detailing sensitive Syndicate operational intelligence."
|
||||
|
||||
/obj/item/documents/syndicate/red
|
||||
name = "red secret documents"
|
||||
desc = "\"Top Secret\" documents detailing sensitive Syndicate operational intelligence. These documents are verified with a red wax seal."
|
||||
icon_state = "docs_red"
|
||||
|
||||
/obj/item/documents/syndicate/blue
|
||||
name = "blue secret documents"
|
||||
desc = "\"Top Secret\" documents detailing sensitive Syndicate operational intelligence. These documents are verified with a blue wax seal."
|
||||
icon_state = "docs_blue"
|
||||
|
||||
/obj/item/documents/syndicate/mining
|
||||
desc = "\"Top Secret\" documents detailing Syndicate plasma mining operations."
|
||||
|
||||
/obj/item/documents/photocopy
|
||||
desc = "A copy of some top-secret documents. Nobody will notice they aren't the originals... right?"
|
||||
var/forgedseal = 0
|
||||
var/copy_type = null
|
||||
|
||||
/obj/item/documents/photocopy/New(loc, obj/item/documents/copy=null)
|
||||
..()
|
||||
if(copy)
|
||||
copy_type = copy.type
|
||||
if(istype(copy, /obj/item/documents/photocopy)) // Copy Of A Copy Of A Copy
|
||||
var/obj/item/documents/photocopy/C = copy
|
||||
copy_type = C.copy_type
|
||||
|
||||
/obj/item/documents/photocopy/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/toy/crayon/red) || istype(O, /obj/item/toy/crayon/blue))
|
||||
if (forgedseal)
|
||||
user << "<span class='warning'>You have already forged a seal on [src]!</span>"
|
||||
else
|
||||
var/obj/item/toy/crayon/C = O
|
||||
name = "[C.item_color] secret documents"
|
||||
icon_state = "docs_[C.item_color]"
|
||||
forgedseal = C.item_color
|
||||
user << "<span class='notice'>You forge the official seal with a [C.item_color] crayon. No one will notice... right?</span>"
|
||||
update_icon()
|
||||
@@ -0,0 +1,58 @@
|
||||
/obj/item/latexballon
|
||||
name = "latex glove"
|
||||
desc = "Sterile and airtight."
|
||||
icon_state = "latexballon"
|
||||
item_state = "lgloves"
|
||||
force = 0
|
||||
throwforce = 0
|
||||
w_class = 1
|
||||
throw_speed = 1
|
||||
throw_range = 7
|
||||
var/state
|
||||
var/datum/gas_mixture/air_contents = null
|
||||
|
||||
/obj/item/latexballon/proc/blow(obj/item/weapon/tank/tank, mob/user)
|
||||
if (icon_state == "latexballon_bursted")
|
||||
return
|
||||
icon_state = "latexballon_blow"
|
||||
item_state = "latexballon"
|
||||
user.update_inv_r_hand()
|
||||
user.update_inv_l_hand()
|
||||
user << "<span class='notice'>You blow up [src] with [tank].</span>"
|
||||
air_contents = tank.remove_air_volume(3)
|
||||
|
||||
/obj/item/latexballon/proc/burst()
|
||||
if (!air_contents || icon_state != "latexballon_blow")
|
||||
return
|
||||
playsound(src, 'sound/weapons/Gunshot.ogg', 100, 1)
|
||||
icon_state = "latexballon_bursted"
|
||||
item_state = "lgloves"
|
||||
if(istype(src.loc, /mob/living))
|
||||
var/mob/living/user = src.loc
|
||||
user.update_inv_r_hand()
|
||||
user.update_inv_l_hand()
|
||||
loc.assume_air(air_contents)
|
||||
|
||||
/obj/item/latexballon/ex_act(severity, target)
|
||||
burst()
|
||||
switch(severity)
|
||||
if (1)
|
||||
qdel(src)
|
||||
if (2)
|
||||
if (prob(50))
|
||||
qdel(src)
|
||||
|
||||
/obj/item/latexballon/bullet_act()
|
||||
burst()
|
||||
|
||||
/obj/item/latexballon/temperature_expose(datum/gas_mixture/air, temperature, volume)
|
||||
if(temperature > T0C+100)
|
||||
burst()
|
||||
|
||||
/obj/item/latexballon/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/tank))
|
||||
var/obj/item/weapon/tank/T = W
|
||||
blow(T, user)
|
||||
return
|
||||
if (is_sharp(W) || W.is_hot() || is_pointed(W))
|
||||
burst()
|
||||
@@ -0,0 +1,82 @@
|
||||
//Items for nuke theft traitor objective
|
||||
|
||||
//the nuke core - objective item
|
||||
/obj/item/nuke_core
|
||||
name = "plutonium core"
|
||||
desc = "Extremely radioactive. Wear goggles."
|
||||
icon = 'icons/obj/nuke_tools.dmi'
|
||||
icon_state = "plutonium_core"
|
||||
item_state = "plutoniumcore"
|
||||
var/pulse = 0
|
||||
var/cooldown = 0
|
||||
|
||||
/obj/item/nuke_core/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/nuke_core/attackby(obj/item/nuke_core_container/container, mob/user)
|
||||
if(istype(container))
|
||||
container.load(src, user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/nuke_core/process()
|
||||
if(cooldown < world.time - 60)
|
||||
cooldown = world.time
|
||||
flick("plutonium_core_pulse", src)
|
||||
radiation_pulse(get_turf(src), 1, 4, 40, 1)
|
||||
|
||||
//nuke core box, for carrying the core
|
||||
/obj/item/nuke_core_container
|
||||
name = "nuke core container"
|
||||
desc = "Solid container for radioactive objects."
|
||||
icon = 'icons/obj/nuke_tools.dmi'
|
||||
icon_state = "core_container_empty"
|
||||
item_state = "tile"
|
||||
var/obj/item/nuke_core/core = null
|
||||
|
||||
/obj/item/nuke_core_container/proc/load(obj/item/nuke_core/ncore, mob/user)
|
||||
if(core || !istype(ncore))
|
||||
return 0
|
||||
ncore.loc = src
|
||||
core = ncore
|
||||
icon_state = "core_container_loaded"
|
||||
user << "<span class='warning'>Container is sealing...</span>"
|
||||
addtimer(src, "seal", 50)
|
||||
return 1
|
||||
|
||||
/obj/item/nuke_core_container/proc/seal()
|
||||
if(istype(core))
|
||||
STOP_PROCESSING(SSobj, core)
|
||||
icon_state = "core_container_sealed"
|
||||
playsound(loc, 'sound/items/Deconstruct.ogg', 60, 1)
|
||||
if(ismob(loc))
|
||||
loc << "<span class='warning'>[src] is permanently sealed, [core]'s radiation is contained.</span>"
|
||||
|
||||
/obj/item/nuke_core_container/attackby(obj/item/nuke_core/core, mob/user)
|
||||
if(istype(core))
|
||||
if(!user.unEquip(core))
|
||||
user << "<span class='warning'>The [core] is stuck to your hand!</span>"
|
||||
return
|
||||
else
|
||||
load(core, user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
//snowflake screwdriver, works as a key to start nuke theft, traitor only
|
||||
/obj/item/weapon/screwdriver/nuke
|
||||
name = "screwdriver"
|
||||
desc = "A screwdriver with an ultra thin tip."
|
||||
icon = 'icons/obj/nuke_tools.dmi'
|
||||
icon_state = "screwdriver_nuke"
|
||||
toolspeed = 2
|
||||
|
||||
/obj/item/weapon/paper/nuke_instructions
|
||||
info = "How to break into a Nanotrasen self-destruct terminal and remove its plutonium core:<br>\
|
||||
<ul>\
|
||||
<li>Use a screwdriver with a very thin tip (provided) to unscrew the terminal's front panel</li>\
|
||||
<li>Dislodge and remove the front panel with a crowbar</li>\
|
||||
<li>Cut the inner metal plate with a welding tool</li>\
|
||||
<li>Pry off the inner plate with a crowbar to expose the radioactive core</li>\
|
||||
<li>Use the core container to remove the plutonium core; the container will take some time to seal</li>\
|
||||
<li>???</li>"
|
||||
@@ -0,0 +1,40 @@
|
||||
///AI Upgrades
|
||||
|
||||
|
||||
//Malf Picker
|
||||
/obj/item/device/malf_upgrade
|
||||
name = "combat software upgrade"
|
||||
desc = "A highly illegal, highly dangerous upgrade for artificial intelligence units, granting them a variety of powers as well as the ability to hack APCs."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "datadisk3"
|
||||
|
||||
|
||||
/obj/item/device/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user)
|
||||
if(!istype(AI))
|
||||
return
|
||||
if(AI.malf_picker)
|
||||
AI.malf_picker.processing_time += 50
|
||||
AI << "<span class='userdanger'>[user] has attempted to upgrade you with combat software that you already possess. You gain 50 points to spend on Malfunction Modules instead.</span>"
|
||||
else
|
||||
AI << "<span class='userdanger'>[user] has upgraded you with combat software!</span>"
|
||||
AI.add_malf_picker()
|
||||
user << "<span class='notice'>You upgrade [AI]. [src] is consumed in the process.</span>"
|
||||
qdel(src)
|
||||
|
||||
|
||||
//Lipreading
|
||||
/obj/item/device/surveillance_upgrade
|
||||
name = "surveillance software upgrade"
|
||||
desc = "A software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "datadisk3"
|
||||
|
||||
/obj/item/device/surveillance_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user)
|
||||
if(!istype(AI))
|
||||
return
|
||||
if(AI.eyeobj)
|
||||
AI.eyeobj.relay_speech = TRUE
|
||||
AI << "<span class='userdanger'>[user] has upgraded you with surveillance software!</span>"
|
||||
AI << "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations."
|
||||
user << "<span class='notice'>You upgrade [AI]. [src] is consumed in the process.</span>"
|
||||
qdel(src)
|
||||
@@ -0,0 +1,388 @@
|
||||
/**********************************************************************
|
||||
Cyborg Spec Items
|
||||
***********************************************************************/
|
||||
/obj/item/borg
|
||||
icon = 'icons/mob/robot_items.dmi'
|
||||
|
||||
|
||||
/obj/item/borg/stun
|
||||
name = "electrically-charged arm"
|
||||
icon_state = "elecarm"
|
||||
|
||||
/obj/item/borg/stun/attack(mob/living/M, mob/living/silicon/robot/user)
|
||||
if(!user.cell.use(30)) return
|
||||
|
||||
M.Weaken(5)
|
||||
M.apply_effect(STUTTER, 5)
|
||||
M.Stun(5)
|
||||
|
||||
M.visible_message("<span class='danger'>[user] has prodded [M] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] has prodded you with [src]!</span>")
|
||||
add_logs(user, M, "stunned", src, "(INTENT: [uppertext(user.a_intent)])")
|
||||
|
||||
/obj/item/borg/cyborghug
|
||||
name = "Hugging Module"
|
||||
icon_state = "hugmodule"
|
||||
desc = "For when a someone really needs a hug."
|
||||
var/mode = 0 //0 = Hugs 1 = "Hug" 2 = Shock 3 = CRUSH
|
||||
var/ccooldown = 0
|
||||
var/scooldown = 0
|
||||
var/shockallowed = 0//Can it be a stunarm when emagged. Only PK borgs get this by default.
|
||||
|
||||
/obj/item/borg/cyborghug/attack_self(mob/living/user)
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/P = user
|
||||
if(P.emagged&&shockallowed == 1)
|
||||
if(mode < 3)
|
||||
mode++
|
||||
else
|
||||
mode = 0
|
||||
else if(mode < 1)
|
||||
mode++
|
||||
else
|
||||
mode = 0
|
||||
switch(mode)
|
||||
if(0)
|
||||
user << "Power reset. Hugs!"
|
||||
if(1)
|
||||
user << "Power increased!"
|
||||
if(2)
|
||||
user << "BZZT. Electrifying arms..."
|
||||
if(3)
|
||||
user << "ERROR: ARM ACTUATORS OVERLOADED."
|
||||
|
||||
/obj/item/borg/cyborghug/attack(mob/living/M, mob/living/silicon/robot/user)
|
||||
switch(mode)
|
||||
if(0)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M))
|
||||
if(M.lying)
|
||||
user.visible_message("<span class='notice'>[user] shakes [M] trying to get \him up!</span>", \
|
||||
"<span class='notice'>You shake [M] trying to get \him up!</span>")
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] hugs [M] to make \him feel better!</span>", \
|
||||
"<span class='notice'>You hug [M] to make \him feel better!</span>")
|
||||
if(M.resting)
|
||||
M.resting = 0
|
||||
M.update_canmove()
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] pets [M]!</span>", \
|
||||
"<span class='notice'>You pet [M]!</span>")
|
||||
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
||||
if(1)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M))
|
||||
if(M.lying)
|
||||
user.visible_message("<span class='notice'>[user] shakes [M] trying to get \him up!</span>", \
|
||||
"<span class='notice'>You shake [M] trying to get \him up!</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] hugs [M] in a firm bear-hug! [M] looks uncomfortable...</span>", \
|
||||
"<span class='warning'>You hug [M] firmly to make \him feel better! [M] looks uncomfortable...</span>")
|
||||
if(M.resting)
|
||||
M.resting = 0
|
||||
M.update_canmove()
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] bops [M] on the head!</span>", \
|
||||
"<span class='warning'>You bop [M] on the head!</span>")
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, 1, -1)
|
||||
if(2)
|
||||
if(!scooldown)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M)||ismonkey(M))
|
||||
M.electrocute_act(5, "[user]", safety = 1)
|
||||
user.visible_message("<span class='userdanger'>[user] electrocutes [M] with their touch!</span>", \
|
||||
"<span class='danger'>You electrocute [M] with your touch!</span>")
|
||||
M.update_canmove()
|
||||
else
|
||||
if(!isrobot(M))
|
||||
M.adjustFireLoss(10)
|
||||
user.visible_message("<span class='userdanger'>[user] shocks [M]!</span>", \
|
||||
"<span class='danger'>You shock [M]!</span>")
|
||||
else
|
||||
user.visible_message("<span class='userdanger'>[user] shocks [M]. It does not seem to have an effect</span>", \
|
||||
"<span class='danger'>You shock [M] to no effect.</span>")
|
||||
playsound(loc, 'sound/effects/sparks2.ogg', 50, 1, -1)
|
||||
user.cell.charge -= 500
|
||||
scooldown = 1
|
||||
spawn(20)
|
||||
scooldown = 0
|
||||
if(3)
|
||||
if(!ccooldown)
|
||||
if(M.health >= 0)
|
||||
if(ishuman(M))
|
||||
user.visible_message("<span class='userdanger'>[user] crushes [M] in their grip!</span>", \
|
||||
"<span class='danger'>You crush [M] in your grip!</span>")
|
||||
else
|
||||
user.visible_message("<span class='userdanger'>[user] crushes [M]!</span>", \
|
||||
"<span class='danger'>You crush [M]!</span>")
|
||||
playsound(loc, 'sound/weapons/smash.ogg', 50, 1, -1)
|
||||
M.adjustBruteLoss(10)
|
||||
user.cell.charge -= 300
|
||||
ccooldown = 1
|
||||
spawn(10)
|
||||
ccooldown = 0
|
||||
|
||||
/obj/item/borg/cyborghug/peacekeeper
|
||||
shockallowed = 1
|
||||
|
||||
/obj/item/borg/charger
|
||||
name = "power connector"
|
||||
icon_state = "charger_draw"
|
||||
flags = NOBLUDGEON
|
||||
var/mode = "draw"
|
||||
var/list/charge_machines = list(/obj/machinery/cell_charger, /obj/machinery/recharger,
|
||||
/obj/machinery/recharge_station, /obj/machinery/mech_bay_recharge_port)
|
||||
var/list/charge_items = list(/obj/item/weapon/stock_parts/cell, /obj/item/weapon/gun/energy,
|
||||
)
|
||||
|
||||
/obj/item/borg/charger/update_icon()
|
||||
..()
|
||||
icon_state = "charger_[mode]"
|
||||
|
||||
/obj/item/borg/charger/attack_self(mob/user)
|
||||
if(mode == "draw")
|
||||
mode = "charge"
|
||||
else
|
||||
mode = "draw"
|
||||
user << "<span class='notice'>You toggle [src] to \"[mode]\" mode.</span>"
|
||||
update_icon()
|
||||
|
||||
/obj/item/borg/charger/afterattack(obj/item/target, mob/living/silicon/robot/user, proximity_flag)
|
||||
if(!proximity_flag || !isrobot(user))
|
||||
return
|
||||
if(mode == "draw")
|
||||
if(is_type_in_list(target, charge_machines))
|
||||
var/obj/machinery/M = target
|
||||
if((M.stat & (NOPOWER|BROKEN)) || !M.anchored)
|
||||
user << "<span class='warning'>[M] is unpowered!</span>"
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You connect to [M]'s power line...</span>"
|
||||
while(do_after(user, 15, target = M, progress = 0))
|
||||
if(!user || !user.cell || mode != "draw")
|
||||
return
|
||||
|
||||
if((M.stat & (NOPOWER|BROKEN)) || !M.anchored)
|
||||
break
|
||||
|
||||
if(!user.cell.give(150))
|
||||
break
|
||||
|
||||
M.use_power(200)
|
||||
|
||||
user << "<span class='notice'>You stop charging youself.</span>"
|
||||
|
||||
else if(is_type_in_list(target, charge_items))
|
||||
var/obj/item/weapon/stock_parts/cell/cell = target
|
||||
if(!istype(cell))
|
||||
cell = locate(/obj/item/weapon/stock_parts/cell) in target
|
||||
if(!cell)
|
||||
user << "<span class='warning'>[target] has no power cell!</span>"
|
||||
return
|
||||
|
||||
if(istype(target, /obj/item/weapon/gun/energy))
|
||||
var/obj/item/weapon/gun/energy/E = target
|
||||
if(!E.can_charge)
|
||||
user << "<span class='warning'>[target] has no power port!</span>"
|
||||
return
|
||||
|
||||
if(!cell.charge)
|
||||
user << "<span class='warning'>[target] has no power!</span>"
|
||||
|
||||
|
||||
user << "<span class='notice'>You connect to [target]'s power port...</span>"
|
||||
|
||||
while(do_after(user, 15, target = target, progress = 0))
|
||||
if(!user || !user.cell || mode != "draw")
|
||||
return
|
||||
|
||||
if(!cell || !target)
|
||||
return
|
||||
|
||||
if(cell != target && cell.loc != target)
|
||||
return
|
||||
|
||||
var/draw = min(cell.charge, cell.chargerate*0.5, user.cell.maxcharge-user.cell.charge)
|
||||
if(!cell.use(draw))
|
||||
break
|
||||
if(!user.cell.give(draw))
|
||||
break
|
||||
target.update_icon()
|
||||
|
||||
user << "<span class='notice'>You stop charging youself.</span>"
|
||||
|
||||
else if(is_type_in_list(target, charge_items))
|
||||
var/obj/item/weapon/stock_parts/cell/cell = target
|
||||
if(!istype(cell))
|
||||
cell = locate(/obj/item/weapon/stock_parts/cell) in target
|
||||
if(!cell)
|
||||
user << "<span class='warning'>[target] has no power cell!</span>"
|
||||
return
|
||||
|
||||
if(istype(target, /obj/item/weapon/gun/energy))
|
||||
var/obj/item/weapon/gun/energy/E = target
|
||||
if(!E.can_charge)
|
||||
user << "<span class='warning'>[target] has no power port!</span>"
|
||||
return
|
||||
|
||||
if(cell.charge >= cell.maxcharge)
|
||||
user << "<span class='warning'>[target] is already charged!</span>"
|
||||
|
||||
user << "<span class='notice'>You connect to [target]'s power port...</span>"
|
||||
|
||||
while(do_after(user, 15, target = target, progress = 0))
|
||||
if(!user || !user.cell || mode != "charge")
|
||||
return
|
||||
|
||||
if(!cell || !target)
|
||||
return
|
||||
|
||||
if(cell != target && cell.loc != target)
|
||||
return
|
||||
|
||||
var/draw = min(user.cell.charge, cell.chargerate*0.5, cell.maxcharge-cell.charge)
|
||||
if(!user.cell.use(draw))
|
||||
break
|
||||
if(!cell.give(draw))
|
||||
break
|
||||
target.update_icon()
|
||||
|
||||
user << "<span class='notice'>You stop charging [target].</span>"
|
||||
|
||||
/obj/item/device/harmalarm
|
||||
name = "Sonic Harm Prevention Tool"
|
||||
desc = "Releases a harmless blast that confuses most organics. For when the harm is JUST TOO MUCH"
|
||||
icon_state = "megaphone"
|
||||
var/cooldown = 0
|
||||
var/emagged = 0
|
||||
|
||||
/obj/item/device/harmalarm/emag_act(mob/user)
|
||||
emagged = !emagged
|
||||
if(emagged)
|
||||
user << "<font color='red'>You short out the safeties on the [src]!</font>"
|
||||
else
|
||||
user << "<font color='red'>You reset the safeties on the [src]!</font>"
|
||||
|
||||
/obj/item/device/harmalarm/attack_self(mob/user)
|
||||
var/safety = !emagged
|
||||
if(cooldown > world.time)
|
||||
user << "<font color='red'>The device is still recharging!</font>"
|
||||
return
|
||||
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(R.cell.charge < 1200)
|
||||
user << "<font color='red'>You don't have enough charge to do this!</font>"
|
||||
return
|
||||
R.cell.charge -= 1000
|
||||
if(R.emagged)
|
||||
safety = 0
|
||||
|
||||
if(safety == 1)
|
||||
user.visible_message("<font color='red' size='2'>[user] blares out a near-deafening siren from its speakers!</font>", \
|
||||
"<span class='userdanger'>The siren pierces your hearing and confuses you!</span>", \
|
||||
"<span class='danger'>The siren pierces your hearing!</span>")
|
||||
for(var/mob/living/M in get_hearers_in_view(9, user))
|
||||
if(iscarbon(M))
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
|
||||
continue
|
||||
M.confused += 6
|
||||
M << "<font color='red' size='7'>HUMAN HARM</font>"
|
||||
playsound(get_turf(src), 'sound/AI/harmalarm.ogg', 70, 3)
|
||||
cooldown = world.time + 200
|
||||
log_game("[user.ckey]([user]) used a Cyborg Harm Alarm in ([user.x],[user.y],[user.z])")
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
R.connected_ai << "<br><span class='notice'>NOTICE - Peacekeeping 'HARM ALARM' used by: [user]</span><br>"
|
||||
|
||||
return
|
||||
|
||||
if(safety == 0)
|
||||
for(var/mob/living/M in get_hearers_in_view(9, user))
|
||||
if(iscarbon(M))
|
||||
var/earsafety = 0
|
||||
if(istype(M, /mob/living/carbon/alien))
|
||||
continue
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/S = M
|
||||
if(istype(S.ears, /obj/item/clothing/ears/earmuffs))
|
||||
continue
|
||||
if(S.check_ear_prot())
|
||||
earsafety = 1
|
||||
if(earsafety)
|
||||
M.confused += 5
|
||||
M.stuttering += 10
|
||||
M.adjustEarDamage(0, 5)
|
||||
M.Jitter(10)
|
||||
user.visible_message("<font color='red' size='3'>[user] blares out a sonic screech from its speakers!</font>", \
|
||||
"<span class='userdanger'>You hear a sharp screech, before your thoughts are interrupted and you find yourself extremely disorientated.</span>", \
|
||||
"<span class='danger'>You hear a sonic screech and suddenly can't seem to walk straight!")
|
||||
else
|
||||
M.Weaken(2)
|
||||
M.confused += 10
|
||||
M.stuttering += 15
|
||||
M.adjustEarDamage(0, 20)
|
||||
M.Jitter(25)
|
||||
user.visible_message("<font color='red' size='3'>[user] blares out a sonic screech from its speakers!</font>", \
|
||||
"<span class='userdanger'>You hear a sharp screech before your thoughts are interrupted and you collapse, your ears ringing!</span>", \
|
||||
"<span class='danger'>You hear a sonic screech and collapse, your ears riniging!")
|
||||
M << "<font color='red' size='7'>BZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZT</font>"
|
||||
playsound(get_turf(src), 'sound/machines/warning-buzzer.ogg', 130, 3)
|
||||
cooldown = world.time + 600
|
||||
log_game("[user.ckey]([user]) used an emagged Cyborg Harm Alarm in ([user.x],[user.y],[user.z])")
|
||||
|
||||
/**********************************************************************
|
||||
HUD/SIGHT things
|
||||
***********************************************************************/
|
||||
/obj/item/borg/sight
|
||||
var/sight_mode = null
|
||||
|
||||
|
||||
/obj/item/borg/sight/xray
|
||||
name = "\proper x-ray Vision"
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
icon_state = "securearea"
|
||||
sight_mode = BORGXRAY
|
||||
|
||||
|
||||
/obj/item/borg/sight/thermal
|
||||
name = "\proper thermal vision"
|
||||
sight_mode = BORGTHERM
|
||||
icon_state = "thermal"
|
||||
|
||||
|
||||
/obj/item/borg/sight/meson
|
||||
name = "\proper meson vision"
|
||||
sight_mode = BORGMESON
|
||||
icon_state = "meson"
|
||||
|
||||
/obj/item/borg/sight/material
|
||||
name = "\proper material vision"
|
||||
sight_mode = BORGMATERIAL
|
||||
icon_state = "material"
|
||||
|
||||
/obj/item/borg/sight/hud
|
||||
name = "hud"
|
||||
var/obj/item/clothing/glasses/hud/hud = null
|
||||
|
||||
|
||||
/obj/item/borg/sight/hud/med
|
||||
name = "medical hud"
|
||||
icon_state = "healthhud"
|
||||
|
||||
/obj/item/borg/sight/hud/med/New()
|
||||
..()
|
||||
hud = new /obj/item/clothing/glasses/hud/health(src)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/borg/sight/hud/sec
|
||||
name = "security hud"
|
||||
icon_state = "securityhud"
|
||||
|
||||
/obj/item/borg/sight/hud/sec/New()
|
||||
..()
|
||||
hud = new /obj/item/clothing/glasses/hud/security(src)
|
||||
return
|
||||
@@ -0,0 +1,379 @@
|
||||
/obj/item/robot_parts
|
||||
name = "robot parts"
|
||||
icon = 'icons/obj/robot_parts.dmi'
|
||||
force = 4
|
||||
throwforce = 4
|
||||
item_state = "buildpipe"
|
||||
icon_state = "blank"
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
var/body_zone
|
||||
|
||||
/obj/item/robot_parts/l_arm
|
||||
name = "cyborg left arm"
|
||||
desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
|
||||
attack_verb = list("slapped", "punched")
|
||||
icon_state = "l_arm"
|
||||
body_zone = "l_arm"
|
||||
|
||||
/obj/item/robot_parts/r_arm
|
||||
name = "cyborg right arm"
|
||||
desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
|
||||
attack_verb = list("slapped", "punched")
|
||||
icon_state = "r_arm"
|
||||
body_zone = "r_arm"
|
||||
|
||||
/obj/item/robot_parts/l_leg
|
||||
name = "cyborg left leg"
|
||||
desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
|
||||
attack_verb = list("kicked", "stomped")
|
||||
icon_state = "l_leg"
|
||||
body_zone = "l_leg"
|
||||
|
||||
/obj/item/robot_parts/r_leg
|
||||
name = "cyborg right leg"
|
||||
desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
|
||||
attack_verb = list("kicked", "stomped")
|
||||
icon_state = "r_leg"
|
||||
body_zone = "r_leg"
|
||||
|
||||
/obj/item/robot_parts/chest
|
||||
name = "cyborg torso"
|
||||
desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell."
|
||||
icon_state = "chest"
|
||||
body_zone = "chest"
|
||||
var/wired = 0
|
||||
var/obj/item/weapon/stock_parts/cell/cell = null
|
||||
|
||||
/obj/item/robot_parts/head
|
||||
name = "cyborg head"
|
||||
desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals."
|
||||
icon_state = "head"
|
||||
body_zone = "head"
|
||||
var/obj/item/device/assembly/flash/handheld/flash1 = null
|
||||
var/obj/item/device/assembly/flash/handheld/flash2 = null
|
||||
|
||||
/obj/item/robot_parts/robot_suit
|
||||
name = "cyborg endoskeleton"
|
||||
desc = "A complex metal backbone with standard limb sockets and pseudomuscle anchors."
|
||||
icon_state = "robo_suit"
|
||||
var/obj/item/robot_parts/l_arm/l_arm = null
|
||||
var/obj/item/robot_parts/r_arm/r_arm = null
|
||||
var/obj/item/robot_parts/l_leg/l_leg = null
|
||||
var/obj/item/robot_parts/r_leg/r_leg = null
|
||||
var/obj/item/robot_parts/chest/chest = null
|
||||
var/obj/item/robot_parts/head/head = null
|
||||
|
||||
var/created_name = ""
|
||||
var/mob/living/silicon/ai/forced_ai
|
||||
var/locomotion = 1
|
||||
var/lawsync = 1
|
||||
var/aisync = 1
|
||||
var/panel_locked = 1
|
||||
|
||||
/obj/item/robot_parts/robot_suit/New()
|
||||
..()
|
||||
src.updateicon()
|
||||
|
||||
/obj/item/robot_parts/robot_suit/proc/updateicon()
|
||||
src.cut_overlays()
|
||||
if(src.l_arm)
|
||||
src.add_overlay("l_arm+o")
|
||||
if(src.r_arm)
|
||||
src.add_overlay("r_arm+o")
|
||||
if(src.chest)
|
||||
src.add_overlay("chest+o")
|
||||
if(src.l_leg)
|
||||
src.add_overlay("l_leg+o")
|
||||
if(src.r_leg)
|
||||
src.add_overlay("r_leg+o")
|
||||
if(src.head)
|
||||
src.add_overlay("head+o")
|
||||
|
||||
/obj/item/robot_parts/robot_suit/proc/check_completion()
|
||||
if(src.l_arm && src.r_arm)
|
||||
if(src.l_leg && src.r_leg)
|
||||
if(src.chest && src.head)
|
||||
feedback_inc("cyborg_frames_built",1)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/robot_parts/robot_suit/attackby(obj/item/W, mob/user, params)
|
||||
|
||||
if(istype(W, /obj/item/stack/sheet/metal))
|
||||
var/obj/item/stack/sheet/metal/M = W
|
||||
if(!l_arm && !r_arm && !l_leg && !r_leg && !chest && !head)
|
||||
if (M.use(1))
|
||||
var/obj/item/weapon/ed209_assembly/B = new /obj/item/weapon/ed209_assembly
|
||||
B.loc = get_turf(src)
|
||||
user << "<span class='notice'>You arm the robot frame.</span>"
|
||||
if (user.get_inactive_hand()==src)
|
||||
user.unEquip(src)
|
||||
user.put_in_inactive_hand(B)
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='warning'>You need one sheet of metal to start building ED-209!</span>"
|
||||
return
|
||||
else if(istype(W, /obj/item/robot_parts/l_leg))
|
||||
if(src.l_leg)
|
||||
return
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.l_leg = W
|
||||
src.updateicon()
|
||||
|
||||
else if(istype(W, /obj/item/robot_parts/r_leg))
|
||||
if(src.r_leg)
|
||||
return
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.r_leg = W
|
||||
src.updateicon()
|
||||
|
||||
else if(istype(W, /obj/item/robot_parts/l_arm))
|
||||
if(src.l_arm)
|
||||
return
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.l_arm = W
|
||||
src.updateicon()
|
||||
|
||||
else if(istype(W, /obj/item/robot_parts/r_arm))
|
||||
if(src.r_arm)
|
||||
return
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.r_arm = W
|
||||
src.updateicon()
|
||||
|
||||
else if(istype(W, /obj/item/robot_parts/chest))
|
||||
if(src.chest)
|
||||
return
|
||||
if(W:wired && W:cell)
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.chest = W
|
||||
src.updateicon()
|
||||
else if(!W:wired)
|
||||
user << "<span class='warning'>You need to attach wires to it first!</span>"
|
||||
else
|
||||
user << "<span class='warning'>You need to attach a cell to it first!</span>"
|
||||
|
||||
else if(istype(W, /obj/item/robot_parts/head))
|
||||
if(src.head)
|
||||
return
|
||||
if(W:flash2 && W:flash1)
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.head = W
|
||||
src.updateicon()
|
||||
else
|
||||
user << "<span class='warning'>You need to attach a flash to it first!</span>"
|
||||
|
||||
else if (istype(W, /obj/item/device/multitool))
|
||||
if(check_completion())
|
||||
Interact(user)
|
||||
else
|
||||
user << "<span class='warning'>The endoskeleton must be assembled before debugging can begin!</span>"
|
||||
|
||||
else if(istype(W, /obj/item/device/mmi))
|
||||
var/obj/item/device/mmi/M = W
|
||||
if(check_completion())
|
||||
if(!istype(loc,/turf))
|
||||
user << "<span class='warning'>You can't put the MMI in, the frame has to be standing on the ground to be perfectly precise!</span>"
|
||||
return
|
||||
if(!M.brainmob)
|
||||
user << "<span class='warning'>Sticking an empty MMI into the frame would sort of defeat the purpose!</span>"
|
||||
return
|
||||
|
||||
var/mob/living/carbon/brain/BM = M.brainmob
|
||||
if(!BM.key || !BM.mind)
|
||||
user << "<span class='warning'>The mmi indicates that their mind is completely unresponsive; there's no point!</span>"
|
||||
return
|
||||
|
||||
if(!BM.client) //braindead
|
||||
user << "<span class='warning'>The mmi indicates that their mind is currently inactive; it might change!</span>"
|
||||
return
|
||||
|
||||
if(BM.stat == DEAD || (M.brain && M.brain.damaged_brain))
|
||||
user << "<span class='warning'>Sticking a dead brain into the frame would sort of defeat the purpose!</span>"
|
||||
return
|
||||
|
||||
if(jobban_isbanned(BM, "Cyborg"))
|
||||
user << "<span class='warning'>This MMI does not seem to fit!</span>"
|
||||
return
|
||||
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
|
||||
var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(get_turf(loc))
|
||||
if(!O)
|
||||
return
|
||||
|
||||
if(M.hacked || M.clockwork)
|
||||
aisync = 0
|
||||
lawsync = 0
|
||||
var/datum/ai_laws/L
|
||||
if(M.clockwork)
|
||||
L = new/datum/ai_laws/ratvar
|
||||
else
|
||||
L = new/datum/ai_laws/syndicate_override
|
||||
O.laws = L
|
||||
L.associate(O)
|
||||
|
||||
O.invisibility = 0
|
||||
//Transfer debug settings to new mob
|
||||
O.custom_name = created_name
|
||||
O.locked = panel_locked
|
||||
if(!aisync)
|
||||
lawsync = 0
|
||||
O.connected_ai = null
|
||||
else
|
||||
O.notify_ai(1)
|
||||
if(forced_ai)
|
||||
O.connected_ai = forced_ai
|
||||
if(!lawsync)
|
||||
O.lawupdate = 0
|
||||
if(!M.hacked && !M.clockwork)
|
||||
O.make_laws()
|
||||
|
||||
ticker.mode.remove_antag_for_borging(BM.mind)
|
||||
BM.mind.transfer_to(O)
|
||||
|
||||
if(M.clockwork)
|
||||
add_servant_of_ratvar(O)
|
||||
|
||||
if(O.mind && O.mind.special_role)
|
||||
O.mind.store_memory("As a cyborg, you must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.")
|
||||
O << "<span class='userdanger'>You have been robotized!</span>"
|
||||
O << "<span class='danger'>You must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.</span>"
|
||||
|
||||
O.job = "Cyborg"
|
||||
|
||||
O.cell = chest.cell
|
||||
chest.cell.loc = O
|
||||
chest.cell = null
|
||||
W.loc = O//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
|
||||
if(O.mmi) //we delete the mmi created by robot/New()
|
||||
qdel(O.mmi)
|
||||
O.mmi = W //and give the real mmi to the borg.
|
||||
O.updatename()
|
||||
|
||||
feedback_inc("cyborg_birth",1)
|
||||
|
||||
src.loc = O
|
||||
O.robot_suit = src
|
||||
|
||||
if(!locomotion)
|
||||
O.lockcharge = 1
|
||||
O.update_canmove()
|
||||
O << "<span class='warning'>Error: Servo motors unresponsive.</span>"
|
||||
|
||||
else
|
||||
user << "<span class='warning'>The MMI must go in after everything else!</span>"
|
||||
|
||||
else if(istype(W,/obj/item/weapon/pen))
|
||||
user << "<span class='warning'>You need to use a multitool to name [src]!</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/robot_parts/robot_suit/proc/Interact(mob/user)
|
||||
var/t1 = text("Designation: <A href='?src=\ref[];Name=1'>[(created_name ? "[created_name]" : "Default Cyborg")]</a><br>\n",src)
|
||||
t1 += text("Master AI: <A href='?src=\ref[];Master=1'>[(forced_ai ? "[forced_ai.name]" : "Automatic")]</a><br><br>\n",src)
|
||||
|
||||
t1 += text("LawSync Port: <A href='?src=\ref[];Law=1'>[(lawsync ? "Open" : "Closed")]</a><br>\n",src)
|
||||
t1 += text("AI Connection Port: <A href='?src=\ref[];AI=1'>[(aisync ? "Open" : "Closed")]</a><br>\n",src)
|
||||
t1 += text("Servo Motor Functions: <A href='?src=\ref[];Loco=1'>[(locomotion ? "Unlocked" : "Locked")]</a><br>\n",src)
|
||||
t1 += text("Panel Lock: <A href='?src=\ref[];Panel=1'>[(panel_locked ? "Engaged" : "Disengaged")]</a><br>\n",src)
|
||||
var/datum/browser/popup = new(user, "robotdebug", "Cyborg Boot Debug", 310, 220)
|
||||
popup.set_content(t1)
|
||||
popup.open()
|
||||
|
||||
/obj/item/robot_parts/robot_suit/Topic(href, href_list)
|
||||
if(usr.lying || usr.stat || usr.stunned || !Adjacent(usr))
|
||||
return
|
||||
|
||||
var/mob/living/living_user = usr
|
||||
var/obj/item/item_in_hand = living_user.get_active_hand()
|
||||
if(!istype(item_in_hand, /obj/item/device/multitool))
|
||||
living_user << "<span class='warning'>You need a multitool!</span>"
|
||||
return
|
||||
|
||||
if(href_list["Name"])
|
||||
var/new_name = reject_bad_name(input(usr, "Enter new designation. Set to blank to reset to default.", "Cyborg Debug", src.created_name),1)
|
||||
if(!in_range(src, usr) && src.loc != usr)
|
||||
return
|
||||
if(new_name)
|
||||
created_name = new_name
|
||||
else
|
||||
created_name = ""
|
||||
|
||||
else if(href_list["Master"])
|
||||
forced_ai = select_active_ai(usr)
|
||||
if(!forced_ai)
|
||||
usr << "<span class='error'>No active AIs detected.</span>"
|
||||
|
||||
else if(href_list["Law"])
|
||||
lawsync = !lawsync
|
||||
else if(href_list["AI"])
|
||||
aisync = !aisync
|
||||
else if(href_list["Loco"])
|
||||
locomotion = !locomotion
|
||||
else if(href_list["Panel"])
|
||||
panel_locked = !panel_locked
|
||||
|
||||
add_fingerprint(usr)
|
||||
Interact(usr)
|
||||
return
|
||||
|
||||
/obj/item/robot_parts/chest/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/stock_parts/cell))
|
||||
if(src.cell)
|
||||
user << "<span class='warning'>You have already inserted a cell!</span>"
|
||||
return
|
||||
else
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
W.loc = src
|
||||
src.cell = W
|
||||
user << "<span class='notice'>You insert the cell.</span>"
|
||||
else if(istype(W, /obj/item/stack/cable_coil))
|
||||
if(src.wired)
|
||||
user << "<span class='warning'>You have already inserted wire!</span>"
|
||||
return
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
if (coil.use(1))
|
||||
src.wired = 1
|
||||
user << "<span class='notice'>You insert the wire.</span>"
|
||||
else
|
||||
user << "<span class='warning'>You need one length of coil to wire it!</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/robot_parts/head/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/assembly/flash/handheld))
|
||||
var/obj/item/device/assembly/flash/handheld/F = W
|
||||
if(src.flash1 && src.flash2)
|
||||
user << "<span class='warning'>You have already inserted the eyes!</span>"
|
||||
return
|
||||
else if(F.crit_fail)
|
||||
user << "<span class='warning'>You can't use a broken flash!</span>"
|
||||
return
|
||||
else
|
||||
if(!user.unEquip(W))
|
||||
return
|
||||
F.loc = src
|
||||
if(src.flash1)
|
||||
src.flash2 = F
|
||||
else
|
||||
src.flash1 = F
|
||||
user << "<span class='notice'>You insert the flash into the eye socket.</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
// robot_upgrades.dm
|
||||
// Contains various borg upgrades.
|
||||
|
||||
/obj/item/borg/upgrade
|
||||
name = "borg upgrade module."
|
||||
desc = "Protected by FRM."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "cyborg_upgrade"
|
||||
origin_tech = "programming=2"
|
||||
var/locked = 0
|
||||
var/installed = 0
|
||||
var/require_module = 0
|
||||
var/module_type = null
|
||||
|
||||
/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R)
|
||||
if(R.stat == DEAD)
|
||||
usr << "<span class='notice'>[src] will not function on a deceased cyborg.</span>"
|
||||
return 1
|
||||
if(module_type && !istype(R.module, module_type))
|
||||
R << "Upgrade mounting error! No suitable hardpoint detected!"
|
||||
usr << "There's no mounting point for the module!"
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/reset
|
||||
name = "cyborg module reset board"
|
||||
desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the cyborg."
|
||||
icon_state = "cyborg_upgrade1"
|
||||
require_module = 1
|
||||
|
||||
/obj/item/borg/upgrade/reset/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
R.notify_ai(2)
|
||||
|
||||
R.uneq_all()
|
||||
R.hands.icon_state = "nomod"
|
||||
R.icon_state = "robot"
|
||||
qdel(R.module)
|
||||
R.module = null
|
||||
|
||||
R.modtype = "robot"
|
||||
R.designation = "Default"
|
||||
R.updatename("Default")
|
||||
|
||||
R.update_icons()
|
||||
R.update_headlamp()
|
||||
|
||||
R.speed = 0 // Remove upgrades.
|
||||
R.ionpulse = FALSE
|
||||
R.magpulse = FALSE
|
||||
R.weather_immunities = initial(R.weather_immunities)
|
||||
|
||||
R.status_flags |= CANPUSH
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/rename
|
||||
name = "cyborg reclassification board"
|
||||
desc = "Used to rename a cyborg."
|
||||
icon_state = "cyborg_upgrade1"
|
||||
var/heldname = "default name"
|
||||
|
||||
/obj/item/borg/upgrade/rename/attack_self(mob/user)
|
||||
heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
|
||||
|
||||
/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
R.fully_replace_character_name(R.name, heldname)
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/obj/item/borg/upgrade/restart
|
||||
name = "cyborg emergency reboot module"
|
||||
desc = "Used to force a reboot of a disabled-but-repaired cyborg, bringing it back online."
|
||||
icon_state = "cyborg_upgrade1"
|
||||
|
||||
/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R)
|
||||
if(R.health < 0)
|
||||
usr << "<span class='warning'>You have to repair the cyborg before using this module!</span>"
|
||||
return 0
|
||||
|
||||
if(!R.key)
|
||||
for(var/mob/dead/observer/ghost in player_list)
|
||||
if(ghost.mind && ghost.mind.current == R)
|
||||
R.key = ghost.key
|
||||
|
||||
R.revive()
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/vtec
|
||||
name = "cyborg VTEC module"
|
||||
desc = "Used to kick in a cyborg's VTEC systems, increasing their speed."
|
||||
icon_state = "cyborg_upgrade2"
|
||||
require_module = 1
|
||||
origin_tech = "engineering=4;materials=5;programming=4"
|
||||
|
||||
/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
if(R.speed < 0)
|
||||
R << "<span class='notice'>A VTEC unit is already installed!</span>"
|
||||
usr << "<span class='notice'>There's no room for another VTEC unit!</span>"
|
||||
return
|
||||
|
||||
R.speed = -2 // Gotta go fast.
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/disablercooler
|
||||
name = "cyborg rapid disabler cooling module"
|
||||
desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
module_type = /obj/item/weapon/robot_module/security
|
||||
origin_tech = "engineering=4;powerstorage=4;combat=4"
|
||||
|
||||
/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/obj/item/weapon/gun/energy/disabler/cyborg/T = locate() in R.module.modules
|
||||
if(!T)
|
||||
usr << "<span class='notice'>There's no disabler in this unit!</span>"
|
||||
return
|
||||
if(T.charge_delay <= 2)
|
||||
R << "<span class='notice'>A cooling unit is already installed!</span>"
|
||||
usr << "<span class='notice'>There's no room for another cooling unit!</span>"
|
||||
return
|
||||
|
||||
T.charge_delay = max(2 , T.charge_delay - 4)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/thrusters
|
||||
name = "ion thruster upgrade"
|
||||
desc = "A energy-operated thruster system for cyborgs."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
origin_tech = "engineering=4;powerstorage=4"
|
||||
|
||||
/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(R.ionpulse)
|
||||
usr << "<span class='notice'>This unit already has ion thrusters installed!</span>"
|
||||
return
|
||||
|
||||
R.ionpulse = TRUE
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/ddrill
|
||||
name = "mining cyborg diamond drill"
|
||||
desc = "A diamond drill replacement for the mining module's standard drill."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
module_type = /obj/item/weapon/robot_module/miner
|
||||
origin_tech = "engineering=4;materials=5"
|
||||
|
||||
/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
for(var/obj/item/weapon/pickaxe/drill/cyborg/D in R.module.modules)
|
||||
qdel(D)
|
||||
for(var/obj/item/weapon/shovel/S in R.module.modules)
|
||||
qdel(S)
|
||||
|
||||
R.module.modules += new /obj/item/weapon/pickaxe/drill/cyborg/diamond(R.module)
|
||||
R.module.rebuild()
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/soh
|
||||
name = "mining cyborg satchel of holding"
|
||||
desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
module_type = /obj/item/weapon/robot_module/miner
|
||||
origin_tech = "engineering=4;materials=4;bluespace=4"
|
||||
|
||||
/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
for(var/obj/item/weapon/storage/bag/ore/cyborg/S in R.module.modules)
|
||||
qdel(S)
|
||||
|
||||
R.module.modules += new /obj/item/weapon/storage/bag/ore/holding(R.module)
|
||||
R.module.rebuild()
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/hyperka
|
||||
name = "mining cyborg hyper-kinetic accelerator"
|
||||
desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
module_type = /obj/item/weapon/robot_module/miner
|
||||
origin_tech = "materials=6;powerstorage=4;engineering=4;magnets=4;combat=4"
|
||||
|
||||
/obj/item/borg/upgrade/hyperka/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
for(var/obj/item/weapon/gun/energy/kinetic_accelerator/cyborg/H in R.module.modules)
|
||||
qdel(H)
|
||||
|
||||
R.module.modules += new /obj/item/weapon/gun/energy/kinetic_accelerator/hyper/cyborg(R.module)
|
||||
R.module.rebuild()
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/syndicate
|
||||
name = "illegal equipment module"
|
||||
desc = "Unlocks the hidden, deadlier functions of a cyborg"
|
||||
icon_state = "cyborg_upgrade3"
|
||||
require_module = 1
|
||||
origin_tech = "combat=4;syndicate=1"
|
||||
|
||||
/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(R.emagged)
|
||||
return
|
||||
|
||||
R.SetEmagged(1)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/lavaproof
|
||||
name = "mining cyborg lavaproof tracks"
|
||||
desc = "An upgrade kit to apply specialized coolant systems and insulation layers to mining cyborg tracks, enabling them to withstand exposure to molten rock."
|
||||
icon_state = "ash_plating"
|
||||
require_module = 1
|
||||
module_type = /obj/item/weapon/robot_module/miner
|
||||
origin_tech = "engineering=4;materials=4;plasmatech=4"
|
||||
|
||||
/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
R.weather_immunities += "lava"
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/selfrepair
|
||||
name = "self-repair module"
|
||||
desc = "This module will repair the cyborg over time."
|
||||
icon_state = "cyborg_upgrade5"
|
||||
require_module = 1
|
||||
var/repair_amount = -1
|
||||
var/repair_tick = 1
|
||||
var/msg_cooldown = 0
|
||||
var/on = 0
|
||||
var/powercost = 10
|
||||
var/mob/living/silicon/robot/cyborg
|
||||
|
||||
/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/obj/item/borg/upgrade/selfrepair/U = locate() in R
|
||||
if(U)
|
||||
usr << "<span class='warning'>This unit is already equipped with a self-repair module.</span>"
|
||||
return 0
|
||||
|
||||
cyborg = R
|
||||
icon_state = "selfrepair_off"
|
||||
var/datum/action/A = new /datum/action/item_action/toggle(src)
|
||||
A.Grant(R)
|
||||
return 1
|
||||
|
||||
/obj/item/borg/upgrade/selfrepair/ui_action_click()
|
||||
on = !on
|
||||
if(on)
|
||||
cyborg << "<span class='notice'>You activate the self-repair module.</span>"
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
cyborg << "<span class='notice'>You deactivate the self-repair module.</span>"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/borg/upgrade/selfrepair/update_icon()
|
||||
if(cyborg)
|
||||
icon_state = "selfrepair_[on ? "on" : "off"]"
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
else
|
||||
icon_state = "cyborg_upgrade5"
|
||||
|
||||
/obj/item/borg/upgrade/selfrepair/proc/deactivate()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
on = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/borg/upgrade/selfrepair/process()
|
||||
if(!repair_tick)
|
||||
repair_tick = 1
|
||||
return
|
||||
|
||||
if(cyborg && (cyborg.stat != DEAD) && on)
|
||||
if(!cyborg.cell)
|
||||
cyborg << "<span class='warning'>Self-repair module deactivated. Please, insert the power cell.</span>"
|
||||
deactivate()
|
||||
return
|
||||
|
||||
if(cyborg.cell.charge < powercost * 2)
|
||||
cyborg << "<span class='warning'>Self-repair module deactivated. Please recharge.</span>"
|
||||
deactivate()
|
||||
return
|
||||
|
||||
if(cyborg.health < cyborg.maxHealth)
|
||||
if(cyborg.health < 0)
|
||||
repair_amount = -2.5
|
||||
powercost = 30
|
||||
else
|
||||
repair_amount = -1
|
||||
powercost = 10
|
||||
cyborg.adjustBruteLoss(repair_amount)
|
||||
cyborg.adjustFireLoss(repair_amount)
|
||||
cyborg.updatehealth()
|
||||
cyborg.cell.use(powercost)
|
||||
else
|
||||
cyborg.cell.use(5)
|
||||
repair_tick = 0
|
||||
|
||||
if((world.time - 2000) > msg_cooldown )
|
||||
var/msgmode = "standby"
|
||||
if(cyborg.health < 0)
|
||||
msgmode = "critical"
|
||||
else if(cyborg.health < cyborg.maxHealth)
|
||||
msgmode = "normal"
|
||||
cyborg << "<span class='notice'>Self-repair is active in <span class='boldnotice'>[msgmode]</span> mode.</span>"
|
||||
msg_cooldown = world.time
|
||||
else
|
||||
deactivate()
|
||||
@@ -0,0 +1,92 @@
|
||||
/obj/item/target
|
||||
name = "shooting target"
|
||||
desc = "A shooting target."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "target_h"
|
||||
density = 0
|
||||
var/hp = 1800
|
||||
var/obj/structure/target_stake/pinnedLoc
|
||||
|
||||
/obj/item/target/Destroy()
|
||||
removeOverlays()
|
||||
if(pinnedLoc)
|
||||
pinnedLoc.nullPinnedTarget()
|
||||
return ..()
|
||||
|
||||
/obj/item/target/proc/nullPinnedLoc()
|
||||
pinnedLoc = null
|
||||
density = 0
|
||||
|
||||
/obj/item/target/proc/removeOverlays()
|
||||
cut_overlays()
|
||||
|
||||
/obj/item/target/Move()
|
||||
..()
|
||||
if(pinnedLoc)
|
||||
pinnedLoc.loc = loc
|
||||
|
||||
/obj/item/target/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(WT.remove_fuel(0, user))
|
||||
removeOverlays()
|
||||
user << "<span class='notice'>You slice off [src]'s uneven chunks of aluminium and scorch marks.</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/target/attack_hand(mob/user)
|
||||
if(pinnedLoc)
|
||||
pinnedLoc.removeTarget(user)
|
||||
..()
|
||||
|
||||
/obj/item/target/syndicate
|
||||
icon_state = "target_s"
|
||||
desc = "A shooting target that looks like a syndicate scum."
|
||||
hp = 2600
|
||||
|
||||
/obj/item/target/alien
|
||||
icon_state = "target_q"
|
||||
desc = "A shooting target that looks like a xenomorphic alien."
|
||||
hp = 2350
|
||||
|
||||
/obj/item/target/clown
|
||||
icon_state = "target_c"
|
||||
desc = "A shooting target that looks like a useless clown."
|
||||
hp = 2000
|
||||
|
||||
#define DECALTYPE_SCORCH 1
|
||||
#define DECALTYPE_BULLET 2
|
||||
|
||||
/obj/item/target/clown/bullet_act(obj/item/projectile/P)
|
||||
..()
|
||||
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
|
||||
|
||||
/obj/item/target/bullet_act(obj/item/projectile/P)
|
||||
var/p_x = P.p_x + pick(0,0,0,0,0,-1,1) // really ugly way of coding "sometimes offset P.p_x!"
|
||||
var/p_y = P.p_y + pick(0,0,0,0,0,-1,1)
|
||||
var/decaltype = DECALTYPE_SCORCH
|
||||
if(istype(/obj/item/projectile/bullet, P))
|
||||
decaltype = DECALTYPE_BULLET
|
||||
var/icon/C = icon(icon,icon_state)
|
||||
if(C.GetPixel(p_x, p_y) && P.original == src && overlays.len <= 35) // if the located pixel isn't blank (null)
|
||||
hp -= P.damage
|
||||
if(hp <= 0)
|
||||
visible_message("<span class='danger'>[src] breaks into tiny pieces and collapses!</span>")
|
||||
qdel(src)
|
||||
var/image/I = image("icon"='icons/effects/effects.dmi', "icon_state"="scorch", "layer"=OBJ_LAYER+0.5)
|
||||
I.pixel_x = p_x - 1 //offset correction
|
||||
I.pixel_y = p_y - 1
|
||||
if(decaltype == DECALTYPE_SCORCH)
|
||||
I.setDir(pick(NORTH,SOUTH,EAST,WEST))// random scorch design
|
||||
if(P.damage >= 20 || istype(P, /obj/item/projectile/beam/practice))
|
||||
I.setDir(pick(NORTH,SOUTH,EAST,WEST))
|
||||
else
|
||||
I.icon_state = "light_scorch"
|
||||
else
|
||||
I.icon_state = "dent"
|
||||
add_overlay(I)
|
||||
return
|
||||
return -1
|
||||
|
||||
#undef DECALTYPE_SCORCH
|
||||
#undef DECALTYPE_BULLET
|
||||
@@ -0,0 +1,49 @@
|
||||
/obj/item/stack/spacecash
|
||||
name = "space cash"
|
||||
desc = "It's worth 1 credit."
|
||||
singular_name = "bill"
|
||||
icon = 'icons/obj/economy.dmi'
|
||||
icon_state = "spacecash"
|
||||
amount = 1
|
||||
max_amount = 20
|
||||
throwforce = 0
|
||||
throw_speed = 2
|
||||
throw_range = 2
|
||||
w_class = 1
|
||||
burn_state = FLAMMABLE
|
||||
var/value = 1
|
||||
|
||||
/obj/item/stack/spacecash/c10
|
||||
icon_state = "spacecash10"
|
||||
desc = "It's worth 10 credits."
|
||||
value = 10
|
||||
|
||||
/obj/item/stack/spacecash/c20
|
||||
icon_state = "spacecash20"
|
||||
desc = "It's worth 20 credits."
|
||||
value = 20
|
||||
|
||||
/obj/item/stack/spacecash/c50
|
||||
icon_state = "spacecash50"
|
||||
desc = "It's worth 50 credits."
|
||||
value = 50
|
||||
|
||||
/obj/item/stack/spacecash/c100
|
||||
icon_state = "spacecash100"
|
||||
desc = "It's worth 100 credits."
|
||||
value = 100
|
||||
|
||||
/obj/item/stack/spacecash/c200
|
||||
icon_state = "spacecash200"
|
||||
desc = "It's worth 200 credits."
|
||||
value = 200
|
||||
|
||||
/obj/item/stack/spacecash/c500
|
||||
icon_state = "spacecash500"
|
||||
desc = "It's worth 500 credits."
|
||||
value = 500
|
||||
|
||||
/obj/item/stack/spacecash/c1000
|
||||
icon_state = "spacecash1000"
|
||||
desc = "It's worth 1000 credits."
|
||||
value = 1000
|
||||
@@ -0,0 +1,139 @@
|
||||
/obj/item/stack/medical
|
||||
name = "medical pack"
|
||||
singular_name = "medical pack"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
amount = 6
|
||||
max_amount = 6
|
||||
w_class = 1
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
burn_state = FLAMMABLE
|
||||
burntime = 5
|
||||
var/heal_brute = 0
|
||||
var/heal_burn = 0
|
||||
var/stop_bleeding = 0
|
||||
var/self_delay = 50
|
||||
|
||||
/obj/item/stack/medical/attack(mob/living/M, mob/user)
|
||||
|
||||
if(M.stat == 2)
|
||||
var/t_him = "it"
|
||||
if(M.gender == MALE)
|
||||
t_him = "him"
|
||||
else if(M.gender == FEMALE)
|
||||
t_him = "her"
|
||||
user << "<span class='danger'>\The [M] is dead, you cannot help [t_him]!</span>"
|
||||
return
|
||||
|
||||
if(!istype(M, /mob/living/carbon) && !istype(M, /mob/living/simple_animal))
|
||||
user << "<span class='danger'>You don't know how to apply \the [src] to [M]!</span>"
|
||||
return 1
|
||||
|
||||
var/obj/item/bodypart/affecting
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
affecting = H.get_bodypart(check_zone(user.zone_selected))
|
||||
if(!affecting) //Missing limb?
|
||||
user << "<span class='warning'>[H] doesn't have \a [parse_zone(user.zone_selected)]!</span>"
|
||||
return
|
||||
if(stop_bleeding)
|
||||
if(H.bleedsuppress)
|
||||
user << "<span class='warning'>[H]'s bleeding is already bandaged!</span>"
|
||||
return
|
||||
else if(!H.bleed_rate)
|
||||
user << "<span class='warning'>[H] isn't bleeding!</span>"
|
||||
return
|
||||
|
||||
|
||||
if(isliving(M))
|
||||
if(!M.can_inject(user, 1))
|
||||
return
|
||||
|
||||
if(user)
|
||||
if (M != user)
|
||||
if (istype(M, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/critter = M
|
||||
if (!(critter.healable))
|
||||
user << "<span class='notice'> You cannot use [src] on [M]!</span>"
|
||||
return
|
||||
else if (critter.health == critter.maxHealth)
|
||||
user << "<span class='notice'> [M] is at full health.</span>"
|
||||
return
|
||||
else if(src.heal_brute < 1)
|
||||
user << "<span class='notice'> [src] won't help [M] at all.</span>"
|
||||
return
|
||||
user.visible_message("<span class='green'>[user] applies [src] on [M].</span>", "<span class='green'>You apply [src] on [M].</span>")
|
||||
else
|
||||
var/t_himself = "itself"
|
||||
if(user.gender == MALE)
|
||||
t_himself = "himself"
|
||||
else if(user.gender == FEMALE)
|
||||
t_himself = "herself"
|
||||
user.visible_message("<span class='notice'>[user] starts to apply [src] on [t_himself]...</span>", "<span class='notice'>You begin applying [src] on yourself...</span>")
|
||||
if(!do_mob(user, M, self_delay))
|
||||
return
|
||||
user.visible_message("<span class='green'>[user] applies [src] on [t_himself].</span>", "<span class='green'>You apply [src] on yourself.</span>")
|
||||
|
||||
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
affecting = H.get_bodypart(check_zone(user.zone_selected))
|
||||
if(!affecting) //Missing limb?
|
||||
user << "<span class='warning'>[H] doesn't have \a [parse_zone(user.zone_selected)]!</span>"
|
||||
return
|
||||
if(stop_bleeding)
|
||||
if(!H.bleedsuppress) //so you can't stack bleed suppression
|
||||
H.suppress_bloodloss(stop_bleeding)
|
||||
if(affecting.status == ORGAN_ORGANIC) //Limb must be organic to be healed - RR
|
||||
if(affecting.heal_damage(src.heal_brute, src.heal_burn, 0))
|
||||
H.update_damage_overlays(0)
|
||||
|
||||
M.updatehealth()
|
||||
else
|
||||
user << "<span class='notice'>Medicine won't work on a robotic limb!</span>"
|
||||
else
|
||||
M.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2))
|
||||
|
||||
|
||||
use(1)
|
||||
|
||||
|
||||
|
||||
/obj/item/stack/medical/bruise_pack
|
||||
name = "bruise pack"
|
||||
singular_name = "bruise pack"
|
||||
desc = "A theraputic gel pack and bandages designed to treat blunt-force trauma."
|
||||
icon_state = "brutepack"
|
||||
heal_brute = 40
|
||||
origin_tech = "biotech=2"
|
||||
self_delay = 20
|
||||
|
||||
/obj/item/stack/medical/gauze
|
||||
name = "medical gauze"
|
||||
desc = "A roll of elastic cloth that is extremely effective at stopping bleeding, but does not heal wounds."
|
||||
gender = PLURAL
|
||||
singular_name = "medical gauze"
|
||||
icon_state = "gauze"
|
||||
stop_bleeding = 1800
|
||||
self_delay = 20
|
||||
|
||||
/obj/item/stack/medical/gauze/improvised
|
||||
name = "improvised gauze"
|
||||
singular_name = "improvised gauze"
|
||||
desc = "A roll of cloth roughly cut from something that can stop bleeding, but does not heal wounds."
|
||||
stop_bleeding = 900
|
||||
|
||||
/obj/item/stack/medical/gauze/cyborg/
|
||||
materials = list()
|
||||
is_cyborg = 1
|
||||
cost = 250
|
||||
|
||||
/obj/item/stack/medical/ointment
|
||||
name = "ointment"
|
||||
desc = "Used to treat those nasty burn wounds."
|
||||
gender = PLURAL
|
||||
singular_name = "ointment"
|
||||
icon_state = "ointment"
|
||||
heal_burn = 40
|
||||
origin_tech = "biotech=2"
|
||||
self_delay = 20
|
||||
@@ -0,0 +1,75 @@
|
||||
var/global/list/datum/stack_recipe/rod_recipes = list ( \
|
||||
new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 25, one_per_turf = 0), \
|
||||
)
|
||||
|
||||
/obj/item/stack/rods
|
||||
name = "metal rod"
|
||||
desc = "Some rods. Can be used for building, or something."
|
||||
singular_name = "metal rod"
|
||||
icon_state = "rods"
|
||||
item_state = "rods"
|
||||
flags = CONDUCT
|
||||
w_class = 3
|
||||
force = 9
|
||||
throwforce = 10
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
materials = list(MAT_METAL=1000)
|
||||
max_amount = 50
|
||||
attack_verb = list("hit", "bludgeoned", "whacked")
|
||||
hitsound = 'sound/weapons/grenadelaunch.ogg'
|
||||
|
||||
/obj/item/stack/rods/New(var/loc, var/amount=null)
|
||||
..()
|
||||
|
||||
recipes = rod_recipes
|
||||
update_icon()
|
||||
|
||||
/obj/item/stack/rods/update_icon()
|
||||
var/amount = get_amount()
|
||||
if((amount <= 5) && (amount > 0))
|
||||
icon_state = "rods-[amount]"
|
||||
else
|
||||
icon_state = "rods"
|
||||
|
||||
/obj/item/stack/rods/attackby(obj/item/W, mob/user, params)
|
||||
if (istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
|
||||
if(get_amount() < 2)
|
||||
user << "<span class='warning'>You need at least two rods to do this!</span>"
|
||||
return
|
||||
|
||||
if(WT.remove_fuel(0,user))
|
||||
var/obj/item/stack/sheet/metal/new_item = new(usr.loc)
|
||||
user.visible_message("[user.name] shaped [src] into metal with the welding tool.", \
|
||||
"<span class='notice'>You shape [src] into metal with the welding tool.</span>", \
|
||||
"<span class='italics'>You hear welding.</span>")
|
||||
var/obj/item/stack/rods/R = src
|
||||
src = null
|
||||
var/replace = (user.get_inactive_hand()==R)
|
||||
R.use(2)
|
||||
if (!R && replace)
|
||||
user.put_in_hands(new_item)
|
||||
|
||||
else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks))
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/S = W
|
||||
if(amount != 1)
|
||||
user << "<span class='warning'>You must use a single rod!</span>"
|
||||
else if(S.w_class > 2)
|
||||
user << "<span class='warning'>The ingredient is too big for [src]!</span>"
|
||||
else
|
||||
var/obj/item/weapon/reagent_containers/food/snacks/customizable/A = new/obj/item/weapon/reagent_containers/food/snacks/customizable/kebab(get_turf(src))
|
||||
A.initialize_custom_food(src, S, user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/rods/cyborg/
|
||||
materials = list()
|
||||
is_cyborg = 1
|
||||
cost = 250
|
||||
|
||||
/obj/item/stack/rods/cyborg/update_icon()
|
||||
return
|
||||
@@ -0,0 +1,362 @@
|
||||
/* Glass stack types
|
||||
* Contains:
|
||||
* Glass sheets
|
||||
* Reinforced glass sheets
|
||||
* Glass shards - TODO: Move this into code/game/object/item/weapons
|
||||
*/
|
||||
|
||||
/*
|
||||
* Glass sheets
|
||||
*/
|
||||
/obj/item/stack/sheet/glass
|
||||
name = "glass"
|
||||
desc = "HOLY SHEET! That is a lot of glass."
|
||||
singular_name = "glass sheet"
|
||||
icon_state = "sheet-glass"
|
||||
materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
|
||||
origin_tech = "materials=1"
|
||||
|
||||
/obj/item/stack/sheet/glass/cyborg
|
||||
materials = list()
|
||||
is_cyborg = 1
|
||||
cost = 500
|
||||
|
||||
/obj/item/stack/sheet/glass/fifty
|
||||
amount = 50
|
||||
|
||||
/obj/item/stack/sheet/glass/attack_self(mob/user)
|
||||
construct_window(user)
|
||||
|
||||
/obj/item/stack/sheet/glass/attackby(obj/item/W, mob/user, params)
|
||||
add_fingerprint(user)
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/CC = W
|
||||
if (get_amount() < 1 || CC.get_amount() < 5)
|
||||
user << "<span class='warning>You need five lengths of coil and one sheet of glass to make wired glass!</span>"
|
||||
return
|
||||
CC.use(5)
|
||||
use(1)
|
||||
user << "<span class='notice'>You attach wire to the [name].</span>"
|
||||
var/obj/item/stack/light_w/new_tile = new(user.loc)
|
||||
new_tile.add_fingerprint(user)
|
||||
else if(istype(W, /obj/item/stack/rods))
|
||||
var/obj/item/stack/rods/V = W
|
||||
if (V.get_amount() >= 1 && src.get_amount() >= 1)
|
||||
var/obj/item/stack/sheet/rglass/RG = new (user.loc)
|
||||
RG.add_fingerprint(user)
|
||||
var/obj/item/stack/sheet/glass/G = src
|
||||
src = null
|
||||
var/replace = (user.get_inactive_hand()==G)
|
||||
V.use(1)
|
||||
G.use(1)
|
||||
if (!G && replace)
|
||||
user.put_in_hands(RG)
|
||||
else
|
||||
user << "<span class='warning'>You need one rod and one sheet of glass to make reinforced glass!</span>"
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/glass/proc/construct_window(mob/user)
|
||||
if(!user || !src)
|
||||
return 0
|
||||
if(!istype(user.loc,/turf))
|
||||
return 0
|
||||
if(!user.IsAdvancedToolUser())
|
||||
user << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
||||
return 0
|
||||
if(zero_amount())
|
||||
return 0
|
||||
var/title = "Sheet-Glass"
|
||||
title += " ([src.get_amount()] sheet\s left)"
|
||||
switch(alert(title, "Would you like full tile glass or one direction?", "One Direction", "Full Window", "Cancel", null))
|
||||
if("One Direction")
|
||||
if(!src)
|
||||
return 1
|
||||
if(src.loc != user)
|
||||
return 1
|
||||
|
||||
var/list/directions = new/list(cardinal)
|
||||
var/i = 0
|
||||
for (var/obj/structure/window/win in user.loc)
|
||||
i++
|
||||
if(i >= 4)
|
||||
user << "<span class='warning'>There are too many windows in this location.</span>"
|
||||
return 1
|
||||
directions-=win.dir
|
||||
if(!(win.ini_dir in cardinal))
|
||||
user << "<span class='danger'>Can't let you do that.</span>"
|
||||
return 1
|
||||
|
||||
//Determine the direction. It will first check in the direction the person making the window is facing, if it finds an already made window it will try looking at the next cardinal direction, etc.
|
||||
var/dir_to_set = 2
|
||||
for(var/direction in list( user.dir, turn(user.dir,90), turn(user.dir,180), turn(user.dir,270) ))
|
||||
var/found = 0
|
||||
for(var/obj/structure/window/WT in user.loc)
|
||||
if(WT.dir == direction)
|
||||
found = 1
|
||||
if(!found)
|
||||
dir_to_set = direction
|
||||
break
|
||||
|
||||
var/obj/structure/window/W
|
||||
W = new /obj/structure/window( user.loc, 0 )
|
||||
W.setDir(dir_to_set)
|
||||
W.ini_dir = W.dir
|
||||
W.anchored = 0
|
||||
W.air_update_turf(1)
|
||||
src.use(1)
|
||||
W.add_fingerprint(user)
|
||||
if("Full Window")
|
||||
if(!src)
|
||||
return 1
|
||||
if(src.loc != user)
|
||||
return 1
|
||||
if(src.get_amount() < 2)
|
||||
user << "<span class='warning'>You need more glass to do that!</span>"
|
||||
return 1
|
||||
if(locate(/obj/structure/window) in user.loc)
|
||||
user << "<span class='warning'>There is a window in the way!</span>"
|
||||
return 1
|
||||
var/obj/structure/window/W
|
||||
W = new /obj/structure/window/fulltile( user.loc, 0 )
|
||||
W.anchored = 0
|
||||
W.air_update_turf(1)
|
||||
W.add_fingerprint(user)
|
||||
src.use(2)
|
||||
return 0
|
||||
|
||||
|
||||
/*
|
||||
* Reinforced glass sheets
|
||||
*/
|
||||
/obj/item/stack/sheet/rglass
|
||||
name = "reinforced glass"
|
||||
desc = "Glass which seems to have rods or something stuck in them."
|
||||
singular_name = "reinforced glass sheet"
|
||||
icon_state = "sheet-rglass"
|
||||
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT/2, MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
|
||||
origin_tech = "materials=2"
|
||||
|
||||
/obj/item/stack/sheet/rglass/cyborg
|
||||
materials = list()
|
||||
var/datum/robot_energy_storage/metsource
|
||||
var/datum/robot_energy_storage/glasource
|
||||
var/metcost = 250
|
||||
var/glacost = 500
|
||||
|
||||
/obj/item/stack/sheet/rglass/cyborg/get_amount()
|
||||
return min(round(metsource.energy / metcost), round(glasource.energy / glacost))
|
||||
|
||||
/obj/item/stack/sheet/rglass/cyborg/use(amount) // Requires special checks, because it uses two storages
|
||||
metsource.use_charge(amount * metcost)
|
||||
glasource.use_charge(amount * glacost)
|
||||
return
|
||||
|
||||
/obj/item/stack/sheet/rglass/cyborg/add(amount)
|
||||
metsource.add_charge(amount * metcost)
|
||||
glasource.add_charge(amount * glacost)
|
||||
return
|
||||
|
||||
/obj/item/stack/sheet/rglass/attack_self(mob/user)
|
||||
construct_window(user)
|
||||
|
||||
/obj/item/stack/sheet/rglass/proc/construct_window(mob/user)
|
||||
if(!user || !src)
|
||||
return 0
|
||||
if(!istype(user.loc,/turf))
|
||||
return 0
|
||||
if(!user.IsAdvancedToolUser())
|
||||
user << "<span class='warning'>You don't have the dexterity to do this!</span>"
|
||||
return 0
|
||||
var/title = "Sheet Reinf. Glass"
|
||||
title += " ([src.get_amount()] sheet\s left)"
|
||||
switch(input(title, "Would you like full tile glass a one direction glass pane or a windoor?") in list("One Direction", "Full Window", "Windoor", "Cancel"))
|
||||
if("One Direction")
|
||||
if(!src)
|
||||
return 1
|
||||
if(src.loc != user)
|
||||
return 1
|
||||
var/list/directions = new/list(cardinal)
|
||||
var/i = 0
|
||||
for (var/obj/structure/window/win in user.loc)
|
||||
i++
|
||||
if(i >= 4)
|
||||
user << "<span class='danger'>There are too many windows in this location.</span>"
|
||||
return 1
|
||||
directions-=win.dir
|
||||
if(!(win.ini_dir in cardinal))
|
||||
user << "<span class='danger'>Can't let you do that.</span>"
|
||||
return 1
|
||||
|
||||
//Determine the direction. It will first check in the direction the person making the window is facing, if it finds an already made window it will try looking at the next cardinal direction, etc.
|
||||
var/dir_to_set = 2
|
||||
for(var/direction in list( user.dir, turn(user.dir,90), turn(user.dir,180), turn(user.dir,270) ))
|
||||
var/found = 0
|
||||
for(var/obj/structure/window/WT in user.loc)
|
||||
if(WT.dir == direction)
|
||||
found = 1
|
||||
if(!found)
|
||||
dir_to_set = direction
|
||||
break
|
||||
|
||||
var/obj/structure/window/W
|
||||
W = new /obj/structure/window/reinforced( user.loc, 1 )
|
||||
W.state = 0
|
||||
W.setDir(dir_to_set)
|
||||
W.ini_dir = W.dir
|
||||
W.anchored = 0
|
||||
W.add_fingerprint(user)
|
||||
src.use(1)
|
||||
|
||||
if("Full Window")
|
||||
if(!src)
|
||||
return 1
|
||||
if(src.loc != user)
|
||||
return 1
|
||||
if(src.get_amount() < 2)
|
||||
user << "<span class='warning'>You need more glass to do that!</span>"
|
||||
return 1
|
||||
if(locate(/obj/structure/window) in user.loc)
|
||||
user << "<span class='warning'>There is a window in the way!</span>"
|
||||
return 1
|
||||
var/obj/structure/window/W
|
||||
W = new /obj/structure/window/reinforced/fulltile(user.loc, 1)
|
||||
W.state = 0
|
||||
W.anchored = 0
|
||||
W.add_fingerprint(user)
|
||||
src.use(2)
|
||||
|
||||
if("Windoor")
|
||||
if(!src || src.loc != user || !isturf(user.loc))
|
||||
return 1
|
||||
|
||||
for(var/obj/structure/windoor_assembly/WA in user.loc)
|
||||
if(WA.dir == user.dir)
|
||||
user << "<span class='warning'>There is already a windoor assembly in that location!</span>"
|
||||
return 1
|
||||
|
||||
for(var/obj/machinery/door/window/W in user.loc)
|
||||
if(W.dir == user.dir)
|
||||
user << "<span class='warning'>There is already a windoor in that location!</span>"
|
||||
return 1
|
||||
|
||||
if(src.get_amount() < 5)
|
||||
user << "<span class='warning'>You need more glass to do that!</span>"
|
||||
return 1
|
||||
|
||||
var/obj/structure/windoor_assembly/WD = new(user.loc)
|
||||
WD.state = "01"
|
||||
WD.anchored = 0
|
||||
WD.add_fingerprint(user)
|
||||
src.use(5)
|
||||
switch(user.dir)
|
||||
if(SOUTH)
|
||||
WD.setDir(SOUTH)
|
||||
WD.ini_dir = SOUTH
|
||||
if(EAST)
|
||||
WD.setDir(EAST)
|
||||
WD.ini_dir = EAST
|
||||
if(WEST)
|
||||
WD.setDir(WEST)
|
||||
WD.ini_dir = WEST
|
||||
else //If the user is facing northeast. northwest, southeast, southwest or north, default to north
|
||||
WD.setDir(NORTH)
|
||||
WD.ini_dir = NORTH
|
||||
else
|
||||
return 1
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
/obj/item/weapon/shard
|
||||
name = "shard"
|
||||
desc = "A nasty looking shard of glass."
|
||||
icon = 'icons/obj/shards.dmi'
|
||||
icon_state = "large"
|
||||
w_class = 1
|
||||
force = 5
|
||||
throwforce = 10
|
||||
item_state = "shard-glass"
|
||||
materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
|
||||
attack_verb = list("stabbed", "slashed", "sliced", "cut")
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/cooldown = 0
|
||||
sharpness = IS_SHARP
|
||||
|
||||
/obj/item/weapon/shard/suicide_act(mob/user)
|
||||
user.visible_message(pick("<span class='suicide'>[user] is slitting \his wrists with the shard of glass! It looks like \he's trying to commit suicide.</span>", \
|
||||
"<span class='suicide'>[user] is slitting \his throat with the shard of glass! It looks like \he's trying to commit suicide.</span>"))
|
||||
return (BRUTELOSS)
|
||||
|
||||
|
||||
/obj/item/weapon/shard/New()
|
||||
icon_state = pick("large", "medium", "small")
|
||||
switch(icon_state)
|
||||
if("small")
|
||||
pixel_x = rand(-12, 12)
|
||||
pixel_y = rand(-12, 12)
|
||||
if("medium")
|
||||
pixel_x = rand(-8, 8)
|
||||
pixel_y = rand(-8, 8)
|
||||
if("large")
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
|
||||
/obj/item/weapon/shard/afterattack(atom/A as mob|obj, mob/user, proximity)
|
||||
if(!proximity || !(src in user))
|
||||
return
|
||||
if(isturf(A))
|
||||
return
|
||||
if(istype(A, /obj/item/weapon/storage))
|
||||
return
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!H.gloves && !(PIERCEIMMUNE in H.dna.species.specflags)) // golems, etc
|
||||
H << "<span class='warning'>[src] cuts into your hand!</span>"
|
||||
var/organ = (H.hand ? "l_" : "r_") + "arm"
|
||||
var/obj/item/bodypart/affecting = H.get_bodypart(organ)
|
||||
if(affecting && affecting.take_damage(force / 2))
|
||||
H.update_damage_overlays(0)
|
||||
else if(ismonkey(user))
|
||||
var/mob/living/carbon/monkey/M = user
|
||||
M << "<span class='warning'>[src] cuts into your hand!</span>"
|
||||
M.adjustBruteLoss(force / 2)
|
||||
|
||||
|
||||
/obj/item/weapon/shard/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(WT.remove_fuel(0, user))
|
||||
var/obj/item/stack/sheet/glass/NG = new (user.loc)
|
||||
for(var/obj/item/stack/sheet/glass/G in user.loc)
|
||||
if(G == NG)
|
||||
continue
|
||||
if(G.amount >= G.max_amount)
|
||||
continue
|
||||
G.attackby(NG, user)
|
||||
user << "<span class='notice'>You add the newly-formed glass to the stack. It now contains [NG.amount] sheet\s.</span>"
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/shard/Crossed(mob/AM)
|
||||
if(istype(AM) && has_gravity(loc))
|
||||
playsound(loc, 'sound/effects/glass_step.ogg', 50, 1)
|
||||
if(ishuman(AM))
|
||||
var/mob/living/carbon/human/H = AM
|
||||
if(PIERCEIMMUNE in H.dna.species.specflags)
|
||||
return
|
||||
var/picked_def_zone = pick("l_leg", "r_leg")
|
||||
var/obj/item/bodypart/O = H.get_bodypart(picked_def_zone)
|
||||
if(!istype(O))
|
||||
return
|
||||
if(!H.shoes)
|
||||
H.apply_damage(5, BRUTE, picked_def_zone)
|
||||
H.Weaken(3)
|
||||
if(cooldown < world.time - 10) //cooldown to avoid message spam.
|
||||
H.visible_message("<span class='danger'>[H] steps in the broken glass!</span>", \
|
||||
"<span class='userdanger'>You step in the broken glass!</span>")
|
||||
cooldown = world.time
|
||||
@@ -0,0 +1,210 @@
|
||||
/obj/item/stack/sheet/animalhide
|
||||
name = "hide"
|
||||
desc = "Something went wrong."
|
||||
origin_tech = "biotech=3"
|
||||
|
||||
/obj/item/stack/sheet/animalhide/human
|
||||
name = "human skin"
|
||||
desc = "The by-product of human farming."
|
||||
singular_name = "human skin piece"
|
||||
icon_state = "sheet-hide"
|
||||
|
||||
var/global/list/datum/stack_recipe/human_recipes = list( \
|
||||
new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/animalhide/human/New(var/loc, var/amount=null)
|
||||
recipes = human_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/animalhide/generic
|
||||
name = "generic skin"
|
||||
desc = "A piece of generic skin."
|
||||
singular_name = "generic skin piece"
|
||||
icon_state = "sheet-hide"
|
||||
|
||||
/obj/item/stack/sheet/animalhide/corgi
|
||||
name = "corgi hide"
|
||||
desc = "The by-product of corgi farming."
|
||||
singular_name = "corgi hide piece"
|
||||
icon_state = "sheet-corgi"
|
||||
|
||||
var/global/list/datum/stack_recipe/corgi_recipes = list ( \
|
||||
new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/animalhide/corgi/New(var/loc, var/amount=null)
|
||||
recipes = corgi_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/animalhide/cat
|
||||
name = "cat hide"
|
||||
desc = "The by-product of cat farming."
|
||||
singular_name = "cat hide piece"
|
||||
icon_state = "sheet-cat"
|
||||
|
||||
/obj/item/stack/sheet/animalhide/monkey
|
||||
name = "monkey hide"
|
||||
desc = "The by-product of monkey farming."
|
||||
singular_name = "monkey hide piece"
|
||||
icon_state = "sheet-monkey"
|
||||
|
||||
var/global/list/datum/stack_recipe/monkey_recipes = list ( \
|
||||
new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/monkeysuit, 2, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/animalhide/monkey/New(var/loc, var/amount=null)
|
||||
recipes = monkey_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/animalhide/lizard
|
||||
name = "lizard skin"
|
||||
desc = "Sssssss..."
|
||||
singular_name = "lizard skin piece"
|
||||
icon_state = "sheet-lizard"
|
||||
|
||||
/obj/item/stack/sheet/animalhide/xeno
|
||||
name = "alien hide"
|
||||
desc = "The skin of a terrible creature."
|
||||
singular_name = "alien hide piece"
|
||||
icon_state = "sheet-xeno"
|
||||
|
||||
var/global/list/datum/stack_recipe/xeno_recipes = list ( \
|
||||
new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/xenos, 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/xenos, 2, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/animalhide/xeno/New(var/loc, var/amount=null)
|
||||
recipes = xeno_recipes
|
||||
return ..()
|
||||
|
||||
//don't see anywhere else to put these, maybe together they could be used to make the xenos suit?
|
||||
/obj/item/stack/sheet/xenochitin
|
||||
name = "alien chitin"
|
||||
desc = "A piece of the hide of a terrible creature."
|
||||
singular_name = "alien hide piece"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "chitin"
|
||||
origin_tech = null
|
||||
|
||||
/obj/item/xenos_claw
|
||||
name = "alien claw"
|
||||
desc = "The claw of a terrible creature."
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "claw"
|
||||
origin_tech = null
|
||||
|
||||
/obj/item/weed_extract
|
||||
name = "weed extract"
|
||||
desc = "A piece of slimy, purplish weed."
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "weed_extract"
|
||||
origin_tech = null
|
||||
|
||||
/obj/item/stack/sheet/hairlesshide
|
||||
name = "hairless hide"
|
||||
desc = "This hide was stripped of it's hair, but still needs tanning."
|
||||
singular_name = "hairless hide piece"
|
||||
icon_state = "sheet-hairlesshide"
|
||||
origin_tech = null
|
||||
|
||||
/obj/item/stack/sheet/wetleather
|
||||
name = "wet leather"
|
||||
desc = "This leather has been cleaned but still needs to be dried."
|
||||
singular_name = "wet leather piece"
|
||||
icon_state = "sheet-wetleather"
|
||||
origin_tech = null
|
||||
var/wetness = 30 //Reduced when exposed to high temperautres
|
||||
var/drying_threshold_temperature = 500 //Kelvin to start drying
|
||||
|
||||
/obj/item/stack/sheet/leather
|
||||
name = "leather"
|
||||
desc = "The by-product of mob grinding."
|
||||
singular_name = "leather piece"
|
||||
icon_state = "sheet-leather"
|
||||
origin_tech = "materials=2"
|
||||
|
||||
/obj/item/stack/sheet/sinew
|
||||
name = "watcher sinew"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
desc = "Long stringy filaments which presumably came from a watcher's wings."
|
||||
singular_name = "watcher sinew"
|
||||
icon_state = "sinew"
|
||||
origin_tech = "biotech=4"
|
||||
|
||||
|
||||
var/global/list/datum/stack_recipe/sinew_recipes = list ( \
|
||||
new/datum/stack_recipe("sinew restraints", /obj/item/weapon/restraints/handcuffs/sinew, 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/sinew/New(var/loc, var/amount=null)
|
||||
recipes = sinew_recipes
|
||||
return ..()
|
||||
/*
|
||||
* Plates
|
||||
*/
|
||||
|
||||
/obj/item/stack/sheet/animalhide/goliath_hide
|
||||
name = "goliath hide plates"
|
||||
desc = "Pieces of a goliath's rocky hide, these might be able to make your suit a bit more durable to attack from the local fauna."
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "goliath_hide"
|
||||
singular_name = "hide plate"
|
||||
flags = NOBLUDGEON
|
||||
w_class = 3
|
||||
layer = MOB_LAYER
|
||||
|
||||
/obj/item/stack/sheet/animalhide/ashdrake
|
||||
name = "ash drake hide"
|
||||
desc = "The strong, scaled hide of an ash drake."
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "dragon_hide"
|
||||
singular_name = "drake plate"
|
||||
flags = NOBLUDGEON
|
||||
w_class = 3
|
||||
layer = MOB_LAYER
|
||||
|
||||
|
||||
//Step one - dehairing.
|
||||
|
||||
/obj/item/stack/sheet/animalhide/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(is_sharp(W))
|
||||
playsound(loc, 'sound/weapons/slice.ogg', 50, 1, -1)
|
||||
user.visible_message("[user] starts cutting hair off \the [src].", "<span class='notice'>You start cutting the hair off \the [src]...</span>", "<span class='italics'>You hear the sound of a knife rubbing against flesh.</span>")
|
||||
if(do_after(user,50, target = src))
|
||||
user << "<span class='notice'>You cut the hair from this [src.singular_name].</span>"
|
||||
//Try locating an exisitng stack on the tile and add to there if possible
|
||||
for(var/obj/item/stack/sheet/hairlesshide/HS in user.loc)
|
||||
if(HS.amount < 50)
|
||||
HS.amount++
|
||||
use(1)
|
||||
break
|
||||
//If it gets to here it means it did not find a suitable stack on the tile.
|
||||
var/obj/item/stack/sheet/hairlesshide/HS = new(user.loc)
|
||||
HS.amount = 1
|
||||
use(1)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
//Step two - washing..... it's actually in washing machine code.
|
||||
|
||||
//Step three - drying
|
||||
/obj/item/stack/sheet/wetleather/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
..()
|
||||
if(exposed_temperature >= drying_threshold_temperature)
|
||||
wetness--
|
||||
if(wetness == 0)
|
||||
//Try locating an exisitng stack on the tile and add to there if possible
|
||||
for(var/obj/item/stack/sheet/leather/HS in src.loc)
|
||||
if(HS.amount < 50)
|
||||
HS.amount++
|
||||
src.use(1)
|
||||
wetness = initial(wetness)
|
||||
break
|
||||
//If it gets to here it means it did not find a suitable stack on the tile.
|
||||
var/obj/item/stack/sheet/leather/HS = new(src.loc)
|
||||
HS.amount = 1
|
||||
wetness = initial(wetness)
|
||||
src.use(1)
|
||||
@@ -0,0 +1,38 @@
|
||||
/obj/item/stack/light_w
|
||||
name = "wired glass tile"
|
||||
singular_name = "wired glass floor tile"
|
||||
desc = "A glass tile, which is wired, somehow."
|
||||
icon = 'icons/obj/tiles.dmi'
|
||||
icon_state = "glass_wire"
|
||||
w_class = 3
|
||||
force = 3
|
||||
throwforce = 5
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
flags = CONDUCT
|
||||
max_amount = 60
|
||||
|
||||
/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
|
||||
|
||||
if(istype(O,/obj/item/weapon/wirecutters))
|
||||
var/obj/item/stack/cable_coil/CC = new (user.loc)
|
||||
CC.amount = 5
|
||||
CC.add_fingerprint(user)
|
||||
amount--
|
||||
var/obj/item/stack/sheet/glass/G = new (user.loc)
|
||||
G.add_fingerprint(user)
|
||||
if(amount <= 0)
|
||||
user.unEquip(src, 1)
|
||||
qdel(src)
|
||||
|
||||
else if(istype(O, /obj/item/stack/sheet/metal))
|
||||
var/obj/item/stack/sheet/metal/M = O
|
||||
if (M.use(1))
|
||||
use(1)
|
||||
var/obj/item/stack/tile/light/L = new (user.loc)
|
||||
user << "<span class='notice'>You make a light tile.</span>"
|
||||
L.add_fingerprint(user)
|
||||
else
|
||||
user << "<span class='warning'>You need one metal sheet to finish the light tile!</span>"
|
||||
else
|
||||
return ..()
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
Mineral Sheets
|
||||
Contains:
|
||||
- Sandstone
|
||||
- Sandbags
|
||||
- Diamond
|
||||
- Snow
|
||||
- Uranium
|
||||
- Plasma
|
||||
- Gold
|
||||
- Silver
|
||||
- Clown
|
||||
Others:
|
||||
- Adamantine
|
||||
- Mythril
|
||||
- Enriched Uranium
|
||||
- Abductor
|
||||
*/
|
||||
|
||||
/obj/item/stack/sheet/mineral
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
|
||||
/*
|
||||
* Sandstone
|
||||
*/
|
||||
|
||||
var/global/list/datum/stack_recipe/sandstone_recipes = list ( \
|
||||
new/datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Assistant Statue", /obj/structure/statue/sandstone/assistant, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Breakdown into sand", /obj/item/weapon/ore/glass, 1, one_per_turf = 0, on_floor = 1), \
|
||||
/* new/datum/stack_recipe("sandstone wall", ???), \
|
||||
new/datum/stack_recipe("sandstone floor", ???),\ */
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/sandstone
|
||||
name = "sandstone brick"
|
||||
desc = "This appears to be a combination of both sand and stone."
|
||||
singular_name = "sandstone brick"
|
||||
icon_state = "sheet-sandstone"
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
origin_tech = "materials=1"
|
||||
materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
|
||||
sheettype = "sandstone"
|
||||
|
||||
/obj/item/stack/sheet/mineral/sandstone/New(var/loc, var/amount=null)
|
||||
recipes = sandstone_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/obj/item/stack/sheet/mineral/sandstone/thirty
|
||||
amount = 30
|
||||
|
||||
/*
|
||||
* Sandbags
|
||||
*/
|
||||
|
||||
/obj/item/stack/sheet/mineral/sandbags
|
||||
name = "sandbags"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "sandbags"
|
||||
singular_name = "sandbag"
|
||||
layer = LOW_ITEM_LAYER
|
||||
origin_tech = "materials=2"
|
||||
|
||||
var/global/list/datum/stack_recipe/sandbag_recipes = list ( \
|
||||
new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 25, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/sandbags/New(var/loc, var/amount=null)
|
||||
recipes = sandbag_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/*
|
||||
* Diamond
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/diamond
|
||||
name = "diamond"
|
||||
icon_state = "sheet-diamond"
|
||||
singular_name = "diamond"
|
||||
origin_tech = "materials=6"
|
||||
sheettype = "diamond"
|
||||
materials = list(MAT_DIAMOND=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
var/global/list/datum/stack_recipe/diamond_recipes = list ( \
|
||||
new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20), \
|
||||
new/datum/stack_recipe("Captain Statue", /obj/structure/statue/diamond/captain, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("AI Hologram Statue", /obj/structure/statue/diamond/ai1, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("AI Core Statue", /obj/structure/statue/diamond/ai2, 5, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/diamond/New(var/loc, var/amount=null)
|
||||
recipes = diamond_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/*
|
||||
* Uranium
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/uranium
|
||||
name = "uranium"
|
||||
icon_state = "sheet-uranium"
|
||||
singular_name = "uranium sheet"
|
||||
origin_tech = "materials=5"
|
||||
sheettype = "uranium"
|
||||
materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
var/global/list/datum/stack_recipe/uranium_recipes = list ( \
|
||||
new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20), \
|
||||
new/datum/stack_recipe("Nuke Statue", /obj/structure/statue/uranium/nuke, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Engineer Statue", /obj/structure/statue/uranium/eng, 5, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/uranium/New(var/loc, var/amount=null)
|
||||
recipes = uranium_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/*
|
||||
* Plasma
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/plasma
|
||||
name = "solid plasma"
|
||||
icon_state = "sheet-plasma"
|
||||
singular_name = "plasma sheet"
|
||||
origin_tech = "plasmatech=2;materials=2"
|
||||
sheettype = "plasma"
|
||||
burn_state = FLAMMABLE
|
||||
burntime = 5
|
||||
materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
var/global/list/datum/stack_recipe/plasma_recipes = list ( \
|
||||
new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20), \
|
||||
new/datum/stack_recipe("Scientist Statue", /obj/structure/statue/plasma/scientist, 5, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/plasma/New(var/loc, var/amount=null)
|
||||
recipes = plasma_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/obj/item/stack/sheet/mineral/plasma/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
|
||||
if(W.is_hot() > 300)//If the temperature of the object is over 300, then ignite
|
||||
message_admins("Plasma sheets ignited by [key_name_admin(user)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("Plasma sheets ignited by [key_name(user)] in ([x],[y],[z])")
|
||||
fire_act()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/mineral/plasma/fire_act()
|
||||
atmos_spawn_air("plasma=[amount*10];TEMP=1000")
|
||||
qdel(src)
|
||||
|
||||
/*
|
||||
* Gold
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/gold
|
||||
name = "gold"
|
||||
icon_state = "sheet-gold"
|
||||
singular_name = "gold bar"
|
||||
origin_tech = "materials=4"
|
||||
sheettype = "gold"
|
||||
materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
var/global/list/datum/stack_recipe/gold_recipes = list ( \
|
||||
new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20), \
|
||||
new/datum/stack_recipe("HoS Statue", /obj/structure/statue/gold/hos, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("HoP Statue", /obj/structure/statue/gold/hop, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("CE Statue", /obj/structure/statue/gold/ce, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("RD Statue", /obj/structure/statue/gold/rd, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("CMO Statue", /obj/structure/statue/gold/cmo, 5, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/gold/New(var/loc, var/amount=null)
|
||||
recipes = gold_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/*
|
||||
* Silver
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/silver
|
||||
name = "silver"
|
||||
icon_state = "sheet-silver"
|
||||
singular_name = "silver bar"
|
||||
origin_tech = "materials=4"
|
||||
sheettype = "silver"
|
||||
materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
var/global/list/datum/stack_recipe/silver_recipes = list ( \
|
||||
new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20), \
|
||||
new/datum/stack_recipe("Med Officer Statue", /obj/structure/statue/silver/md, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Janitor Statue", /obj/structure/statue/silver/janitor, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Sec Officer Statue", /obj/structure/statue/silver/sec, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Sec Borg Statue", /obj/structure/statue/silver/secborg, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Med Borg Statue", /obj/structure/statue/silver/medborg, 5, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/silver/New(var/loc, var/amount=null)
|
||||
recipes = silver_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/*
|
||||
* Clown
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/bananium
|
||||
name = "bananium"
|
||||
icon_state = "sheet-clown"
|
||||
singular_name = "bananium sheet"
|
||||
origin_tech = "materials=4"
|
||||
sheettype = "clown"
|
||||
materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
var/global/list/datum/stack_recipe/clown_recipes = list ( \
|
||||
new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20), \
|
||||
new/datum/stack_recipe("Clown Statue", /obj/structure/statue/bananium/clown, 5, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/bananium/New(var/loc, var/amount=null)
|
||||
recipes = clown_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/*
|
||||
* Snow
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/snow
|
||||
name = "snow"
|
||||
icon_state = "sheet-snow"
|
||||
singular_name = "snow block"
|
||||
force = 1
|
||||
throwforce = 2
|
||||
origin_tech = "materials=1"
|
||||
sheettype = "snow"
|
||||
|
||||
var/global/list/datum/stack_recipe/snow_recipes = list ( \
|
||||
new/datum/stack_recipe("Snow Wall",/turf/closed/wall/mineral/snow, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Snowman", /obj/structure/statue/snow/snowman, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Snowball", /obj/item/toy/snowball, 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/snow/New(var/loc, var/amount=null)
|
||||
recipes = snow_recipes
|
||||
pixel_x = rand(0,4)-4
|
||||
pixel_y = rand(0,4)-4
|
||||
..()
|
||||
|
||||
/****************************** Others ****************************/
|
||||
|
||||
/*
|
||||
* Enriched Uranium
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/enruranium
|
||||
name = "enriched uranium"
|
||||
icon_state = "sheet-enruranium"
|
||||
singular_name = "enriched uranium sheet"
|
||||
origin_tech = "materials=6"
|
||||
materials = list(MAT_URANIUM=3000)
|
||||
|
||||
/*
|
||||
* Adamantine
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/adamantine
|
||||
name = "adamantine"
|
||||
icon_state = "sheet-adamantine"
|
||||
singular_name = "adamantine sheet"
|
||||
origin_tech = "materials=4"
|
||||
|
||||
/*
|
||||
* Mythril
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/mythril
|
||||
name = "mythril"
|
||||
icon_state = "sheet-mythril"
|
||||
singular_name = "mythril sheet"
|
||||
origin_tech = "materials=4"
|
||||
|
||||
/*
|
||||
* Alien Alloy
|
||||
*/
|
||||
/obj/item/stack/sheet/mineral/abductor
|
||||
name = "alien alloy"
|
||||
icon = 'icons/obj/abductor.dmi'
|
||||
icon_state = "sheet-abductor"
|
||||
singular_name = "alien alloy sheet"
|
||||
origin_tech = "materials=6;abductor=1"
|
||||
sheettype = "abductor"
|
||||
|
||||
var/global/list/datum/stack_recipe/abductor_recipes = list ( \
|
||||
/* new/datum/stack_recipe("alien chair", /obj/structure/chair, one_per_turf = 1, on_floor = 1), \ */
|
||||
new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 1, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 20, one_per_turf = 1, on_floor = 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20), \
|
||||
/* null, \
|
||||
new/datum/stack_recipe("Abductor Agent Statue", /obj/structure/statue/bananium/clown, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("Abductor Sciencist Statue", /obj/structure/statue/bananium/clown, 5, one_per_turf = 1, on_floor = 1)*/
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/abductor/New(var/loc, var/amount=null)
|
||||
recipes = abductor_recipes
|
||||
..()
|
||||
@@ -0,0 +1,290 @@
|
||||
/* Diffrent misc types of sheets
|
||||
* Contains:
|
||||
* Metal
|
||||
* Plasteel
|
||||
* Wood
|
||||
* Cloth
|
||||
* Cardboard
|
||||
* Runed Metal (cult)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Metal
|
||||
*/
|
||||
var/global/list/datum/stack_recipe/metal_recipes = list ( \
|
||||
new/datum/stack_recipe("stool", /obj/structure/chair/stool, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("chair", /obj/structure/chair, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("swivel chair", /obj/structure/chair/office/dark, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("comfy chair", /obj/structure/chair/comfy/beige, 2, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("bed", /obj/structure/bed, 2, one_per_turf = 1, on_floor = 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("rack parts", /obj/item/weapon/rack_parts), \
|
||||
new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("canister", /obj/machinery/portable_atmospherics/canister, 10, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("floor tile", /obj/item/stack/tile/plasteel, 1, 4, 20), \
|
||||
new/datum/stack_recipe("metal rod", /obj/item/stack/rods, 1, 2, 60), \
|
||||
null, \
|
||||
new/datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 40, one_per_turf = 1, on_floor = 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 25, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 25, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("airlock assembly", /obj/structure/door_assembly, 4, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 25, one_per_turf = 1, on_floor = 1), \
|
||||
/* new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 25, one_per_turf = 1, on_floor = 1), \*/
|
||||
null, \
|
||||
new/datum/stack_recipe("grenade casing", /obj/item/weapon/grenade/chem_grenade), \
|
||||
new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2), \
|
||||
new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2), \
|
||||
new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2), \
|
||||
new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2), \
|
||||
new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2), \
|
||||
new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1), \
|
||||
null, \
|
||||
new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/metal
|
||||
name = "metal"
|
||||
desc = "Sheets made out of metal."
|
||||
singular_name = "metal sheet"
|
||||
icon_state = "sheet-metal"
|
||||
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT)
|
||||
throwforce = 10
|
||||
flags = CONDUCT
|
||||
origin_tech = "materials=1"
|
||||
|
||||
/obj/item/stack/sheet/metal/narsie_act()
|
||||
if(prob(20))
|
||||
new /obj/item/stack/sheet/runed_metal(loc, amount)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/stack/sheet/metal/fifty
|
||||
amount = 50
|
||||
|
||||
/obj/item/stack/sheet/metal/five
|
||||
amount = 5
|
||||
|
||||
/obj/item/stack/sheet/metal/cyborg
|
||||
materials = list()
|
||||
is_cyborg = 1
|
||||
cost = 500
|
||||
|
||||
/obj/item/stack/sheet/metal/New(var/loc, var/amount=null)
|
||||
recipes = metal_recipes
|
||||
return ..()
|
||||
|
||||
/*
|
||||
* Plasteel
|
||||
*/
|
||||
var/global/list/datum/stack_recipe/plasteel_recipes = list ( \
|
||||
new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1), \
|
||||
new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 50), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/plasteel
|
||||
name = "plasteel"
|
||||
singular_name = "plasteel sheet"
|
||||
desc = "This sheet is an alloy of iron and plasma."
|
||||
icon_state = "sheet-plasteel"
|
||||
item_state = "sheet-metal"
|
||||
materials = list(MAT_METAL=6000, MAT_PLASMA=6000)
|
||||
throwforce = 10
|
||||
flags = CONDUCT
|
||||
origin_tech = "materials=2"
|
||||
|
||||
/obj/item/stack/sheet/plasteel/New(var/loc, var/amount=null)
|
||||
recipes = plasteel_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/plasteel/twenty
|
||||
amount = 20
|
||||
|
||||
/obj/item/stack/sheet/plasteel/fifty
|
||||
amount = 50
|
||||
|
||||
/*
|
||||
* Wood
|
||||
*/
|
||||
var/global/list/datum/stack_recipe/wood_recipes = list ( \
|
||||
new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1), \
|
||||
new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20), \
|
||||
new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 10), \
|
||||
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \
|
||||
new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/normal, 3, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 20, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 15, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 10, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("wooden buckler", /obj/item/weapon/shield/riot/buckler, 20, time = 40), \
|
||||
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\
|
||||
new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 10),\
|
||||
new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 50, one_per_turf = 1, on_floor = 1),\
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/mineral/wood
|
||||
name = "wooden plank"
|
||||
desc = "One can only guess that this is a bunch of wood."
|
||||
singular_name = "wood plank"
|
||||
icon_state = "sheet-wood"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
origin_tech = "materials=1;biotech=1"
|
||||
sheettype = "wood"
|
||||
burn_state = FLAMMABLE
|
||||
|
||||
/obj/item/stack/sheet/mineral/wood/New(var/loc, var/amount=null)
|
||||
recipes = wood_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/mineral/wood/fifty
|
||||
amount = 50
|
||||
|
||||
/*
|
||||
* Cloth
|
||||
*/
|
||||
var/global/list/datum/stack_recipe/cloth_recipes = list ( \
|
||||
new/datum/stack_recipe("grey jumpsuit", /obj/item/clothing/under/color/grey, 3), \
|
||||
null, \
|
||||
new/datum/stack_recipe("backpack", /obj/item/weapon/storage/backpack, 4), \
|
||||
new/datum/stack_recipe("dufflebag", /obj/item/weapon/storage/backpack/dufflebag, 6), \
|
||||
null, \
|
||||
new/datum/stack_recipe("plant bag", /obj/item/weapon/storage/bag/plants, 4), \
|
||||
new/datum/stack_recipe("book bag", /obj/item/weapon/storage/bag/books, 4), \
|
||||
new/datum/stack_recipe("mining satchel", /obj/item/weapon/storage/bag/ore, 4), \
|
||||
new/datum/stack_recipe("chemistry bag", /obj/item/weapon/storage/bag/chemistry, 4), \
|
||||
new/datum/stack_recipe("bio bag", /obj/item/weapon/storage/bag/bio, 4), \
|
||||
null, \
|
||||
new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6), \
|
||||
new/datum/stack_recipe("rag", /obj/item/weapon/reagent_containers/glass/rag, 1), \
|
||||
new/datum/stack_recipe("black shoes", /obj/item/clothing/shoes/sneakers/black, 2), \
|
||||
new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 3), \
|
||||
new/datum/stack_recipe("empty sandbag", /obj/item/weapon/emptysandbag, 4), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/cloth
|
||||
name = "cloth"
|
||||
desc = "Is it cotton? Linen? Denim? Burlap? Canvas? You can't tell."
|
||||
singular_name = "cloth roll"
|
||||
icon_state = "sheet-cloth"
|
||||
origin_tech = "materials=2"
|
||||
burn_state = FLAMMABLE
|
||||
force = 0
|
||||
throwforce = 0
|
||||
|
||||
/obj/item/stack/sheet/cloth/New(var/loc, var/amount=null)
|
||||
recipes = cloth_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/cloth/ten
|
||||
amount = 10
|
||||
|
||||
/*
|
||||
* Cardboard
|
||||
*/
|
||||
var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
|
||||
new/datum/stack_recipe("box", /obj/item/weapon/storage/box), \
|
||||
new/datum/stack_recipe("light tubes", /obj/item/weapon/storage/box/lights/tubes), \
|
||||
new/datum/stack_recipe("light bulbs", /obj/item/weapon/storage/box/lights/bulbs), \
|
||||
new/datum/stack_recipe("mouse traps", /obj/item/weapon/storage/box/mousetraps), \
|
||||
new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3), \
|
||||
new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg), \
|
||||
new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \
|
||||
new/datum/stack_recipe("folder", /obj/item/weapon/folder), \
|
||||
new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4), \
|
||||
new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/cardboard //BubbleWrap //it's cardboard you fuck
|
||||
name = "cardboard"
|
||||
desc = "Large sheets of card, like boxes folded flat."
|
||||
singular_name = "cardboard sheet"
|
||||
icon_state = "sheet-card"
|
||||
origin_tech = "materials=1"
|
||||
burn_state = FLAMMABLE
|
||||
|
||||
/obj/item/stack/sheet/cardboard/New(var/loc, var/amount=null)
|
||||
recipes = cardboard_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/cardboard/fifty
|
||||
amount = 50
|
||||
|
||||
/*
|
||||
* Runed Metal
|
||||
*/
|
||||
|
||||
var/global/list/datum/stack_recipe/runed_metal_recipes = list ( \
|
||||
new/datum/stack_recipe("runed door", /obj/machinery/door/airlock/cult, 3, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("runed girder", /obj/structure/girder/cult, 1, time = 50, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("pylon", /obj/structure/cult/pylon, 3, time = 40, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("forge", /obj/structure/cult/forge, 5, time = 40, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("archives", /obj/structure/cult/tome, 2, time = 40, one_per_turf = 1, on_floor = 1), \
|
||||
new/datum/stack_recipe("altar", /obj/structure/cult/talisman, 5, time = 40, one_per_turf = 1, on_floor = 1), \
|
||||
)
|
||||
|
||||
/obj/item/stack/sheet/runed_metal
|
||||
name = "runed metal"
|
||||
desc = "Sheets of cold metal with shifting inscriptions writ upon them."
|
||||
singular_name = "runed metal"
|
||||
icon_state = "sheet-runed"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
sheettype = "runed"
|
||||
|
||||
/obj/item/stack/sheet/runed_metal/attack_self(mob/living/user)
|
||||
if(!iscultist(user))
|
||||
user << "<span class='warning'>Only one with forbidden knowledge could hope to work this metal...</span>"
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/runed_metal/attack(atom/target, mob/living/user)
|
||||
if(!iscultist(user))
|
||||
user << "<span class='warning'>Only one with forbidden knowledge could hope to work this metal...</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/stack/sheet/runed_metal/fifty
|
||||
amount = 50
|
||||
|
||||
/obj/item/stack/sheet/runed_metal/New(var/loc, var/amount=null)
|
||||
recipes = runed_metal_recipes
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/lessergem
|
||||
name = "lesser gems"
|
||||
desc = "Rare kind of gems which are only gained by blood sacrifice to minor deities. They are needed in crafting powerful objects."
|
||||
singular_name = "lesser gem"
|
||||
icon_state = "sheet-lessergem"
|
||||
origin_tech = "materials=4"
|
||||
|
||||
|
||||
/obj/item/stack/sheet/greatergem
|
||||
name = "greater gems"
|
||||
desc = "Rare kind of gems which are only gained by blood sacrifice to minor deities. They are needed in crafting powerful objects."
|
||||
singular_name = "greater gem"
|
||||
icon_state = "sheet-greatergem"
|
||||
origin_tech = "materials=7"
|
||||
|
||||
/*
|
||||
* Bones
|
||||
*/
|
||||
/obj/item/stack/sheet/bone
|
||||
name = "bones"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "bone"
|
||||
singular_name = "bone"
|
||||
desc = "Someone's been drinking their milk."
|
||||
force = 7
|
||||
throwforce = 5
|
||||
w_class = 3
|
||||
throw_speed = 1
|
||||
throw_range = 3
|
||||
origin_tech = "materials=2;biotech=2"
|
||||
@@ -0,0 +1,11 @@
|
||||
/obj/item/stack/sheet
|
||||
name = "sheet"
|
||||
w_class = 3
|
||||
force = 5
|
||||
throwforce = 5
|
||||
max_amount = 50
|
||||
throw_speed = 1
|
||||
throw_range = 3
|
||||
attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "smashed")
|
||||
var/perunit = MINERAL_MATERIAL_AMOUNT
|
||||
var/sheettype = null //this is used for girders in the creation of walls/false walls
|
||||
@@ -0,0 +1,277 @@
|
||||
/* Stack type objects!
|
||||
* Contains:
|
||||
* Stacks
|
||||
* Recipe datum
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stacks
|
||||
*/
|
||||
/obj/item/stack
|
||||
origin_tech = "materials=1"
|
||||
gender = PLURAL
|
||||
var/list/datum/stack_recipe/recipes
|
||||
var/singular_name
|
||||
var/amount = 1
|
||||
var/max_amount = 50 //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount
|
||||
var/is_cyborg = 0 // It's 1 if module is used by a cyborg, and uses its storage
|
||||
var/datum/robot_energy_storage/source
|
||||
var/cost = 1 // How much energy from storage it costs
|
||||
var/merge_type = null // This path and its children should merge with this stack, defaults to src.type
|
||||
|
||||
/obj/item/stack/New(var/loc, var/amount=null)
|
||||
..()
|
||||
if (amount)
|
||||
src.amount = amount
|
||||
if(!merge_type)
|
||||
merge_type = src.type
|
||||
return
|
||||
|
||||
/obj/item/stack/Destroy()
|
||||
if (usr && usr.machine==src)
|
||||
usr << browse(null, "window=stack")
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/examine(mob/user)
|
||||
..()
|
||||
if (is_cyborg)
|
||||
if(src.singular_name)
|
||||
user << "There is enough energy for [src.get_amount()] [src.singular_name]\s."
|
||||
else
|
||||
user << "There is enough energy for [src.get_amount()]."
|
||||
return
|
||||
if(src.singular_name)
|
||||
if(src.get_amount()>1)
|
||||
user << "There are [src.get_amount()] [src.singular_name]\s in the stack."
|
||||
else
|
||||
user << "There is [src.get_amount()] [src.singular_name] in the stack."
|
||||
else if(src.get_amount()>1)
|
||||
user << "There are [src.get_amount()] in the stack."
|
||||
else
|
||||
user << "There is [src.get_amount()] in the stack."
|
||||
|
||||
/obj/item/stack/proc/get_amount()
|
||||
if (is_cyborg)
|
||||
return round(source.energy / cost)
|
||||
else
|
||||
return (amount)
|
||||
|
||||
/obj/item/stack/attack_self(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/item/stack/interact(mob/user)
|
||||
if (!recipes)
|
||||
return
|
||||
if (!src || get_amount() <= 0)
|
||||
user << browse(null, "window=stack")
|
||||
return
|
||||
user.set_machine(src) //for correct work of onclose
|
||||
var/t1 = text("<HTML><HEAD><title>Constructions from []</title></HEAD><body><TT>Amount Left: []<br>", src, src.get_amount())
|
||||
for(var/i=1;i<=recipes.len,i++)
|
||||
var/datum/stack_recipe/R = recipes[i]
|
||||
if (isnull(R))
|
||||
t1 += "<hr>"
|
||||
continue
|
||||
if (i>1 && !isnull(recipes[i-1]))
|
||||
t1+="<br>"
|
||||
var/max_multiplier = round(src.get_amount() / R.req_amount)
|
||||
var/title as text
|
||||
var/can_build = 1
|
||||
can_build = can_build && (max_multiplier>0)
|
||||
/*
|
||||
if (R.one_per_turf)
|
||||
can_build = can_build && !(locate(R.result_type) in usr.loc)
|
||||
if (R.on_floor)
|
||||
can_build = can_build && istype(usr.loc, /turf/open/floor)
|
||||
*/
|
||||
if (R.res_amount>1)
|
||||
title+= "[R.res_amount]x [R.title]\s"
|
||||
else
|
||||
title+= "[R.title]"
|
||||
title+= " ([R.req_amount] [src.singular_name]\s)"
|
||||
if (can_build)
|
||||
t1 += text("<A href='?src=\ref[];make=[];multiplier=1'>[]</A> ", src, i, title)
|
||||
else
|
||||
t1 += text("[]", title)
|
||||
continue
|
||||
if (R.max_res_amount>1 && max_multiplier>1)
|
||||
max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount))
|
||||
t1 += " |"
|
||||
var/list/multipliers = list(5,10,25)
|
||||
for (var/n in multipliers)
|
||||
if (max_multiplier>=n)
|
||||
t1 += " <A href='?src=\ref[src];make=[i];multiplier=[n]'>[n*R.res_amount]x</A>"
|
||||
if (!(max_multiplier in multipliers))
|
||||
t1 += " <A href='?src=\ref[src];make=[i];multiplier=[max_multiplier]'>[max_multiplier*R.res_amount]x</A>"
|
||||
|
||||
t1 += "</TT></body></HTML>"
|
||||
user << browse(t1, "window=stack")
|
||||
onclose(user, "stack")
|
||||
return
|
||||
|
||||
/obj/item/stack/Topic(href, href_list)
|
||||
..()
|
||||
if ((usr.restrained() || usr.stat || usr.get_active_hand() != src))
|
||||
return
|
||||
if (href_list["make"])
|
||||
if (src.get_amount() < 1) qdel(src) //Never should happen
|
||||
|
||||
var/datum/stack_recipe/R = recipes[text2num(href_list["make"])]
|
||||
var/multiplier = text2num(href_list["multiplier"])
|
||||
if (!multiplier ||(multiplier <= 0)) //href protection
|
||||
return
|
||||
if(!building_checks(R, multiplier))
|
||||
return
|
||||
if (R.time)
|
||||
usr.visible_message("<span class='notice'>[usr] starts building [R.title].</span>", "<span class='notice'>You start building [R.title]...</span>")
|
||||
if (!do_after(usr, R.time, target = usr))
|
||||
return
|
||||
if(!building_checks(R, multiplier))
|
||||
return
|
||||
|
||||
var/atom/O = new R.result_type( usr.loc )
|
||||
O.setDir(usr.dir)
|
||||
use(R.req_amount * multiplier)
|
||||
|
||||
//is it a stack ?
|
||||
if (R.max_res_amount > 1)
|
||||
var/obj/item/stack/new_item = O
|
||||
new_item.amount = R.res_amount*multiplier
|
||||
|
||||
if(new_item.amount <= 0)//if the stack is empty, i.e it has been merged with an existing stack and has been garbage collected
|
||||
return
|
||||
|
||||
if (istype(O,/obj/item))
|
||||
usr.put_in_hands(O)
|
||||
O.add_fingerprint(usr)
|
||||
|
||||
//BubbleWrap - so newly formed boxes are empty
|
||||
if ( istype(O, /obj/item/weapon/storage) )
|
||||
for (var/obj/item/I in O)
|
||||
qdel(I)
|
||||
//BubbleWrap END
|
||||
|
||||
if (src && usr.machine==src) //do not reopen closed window
|
||||
spawn( 0 )
|
||||
src.interact(usr)
|
||||
return
|
||||
return
|
||||
|
||||
/obj/item/stack/proc/building_checks(datum/stack_recipe/R, multiplier)
|
||||
if (src.get_amount() < R.req_amount*multiplier)
|
||||
if (R.req_amount*multiplier>1)
|
||||
usr << "<span class='warning'>You haven't got enough [src] to build \the [R.req_amount*multiplier] [R.title]\s!</span>"
|
||||
else
|
||||
usr << "<span class='warning'>You haven't got enough [src] to build \the [R.title]!</span>"
|
||||
return 0
|
||||
if (R.one_per_turf && (locate(R.result_type) in usr.loc))
|
||||
usr << "<span class='warning'>There is another [R.title] here!</span>"
|
||||
return 0
|
||||
if (R.on_floor && !istype(usr.loc, /turf/open/floor))
|
||||
usr << "<span class='warning'>\The [R.title] must be constructed on the floor!</span>"
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/item/stack/proc/use(var/used) // return 0 = borked; return 1 = had enough
|
||||
if(zero_amount())
|
||||
return 0
|
||||
if (is_cyborg)
|
||||
return source.use_charge(used * cost)
|
||||
if (amount < used)
|
||||
return 0
|
||||
amount -= used
|
||||
zero_amount()
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/item/stack/proc/zero_amount()
|
||||
if(is_cyborg)
|
||||
return source.energy < cost
|
||||
if(amount < 1)
|
||||
qdel(src)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/stack/proc/add(amount)
|
||||
if (is_cyborg)
|
||||
source.add_charge(amount * cost)
|
||||
else
|
||||
src.amount += amount
|
||||
update_icon()
|
||||
|
||||
/obj/item/stack/proc/merge(obj/item/stack/S) //Merge src into S, as much as possible
|
||||
var/transfer = get_amount()
|
||||
if(S.is_cyborg)
|
||||
transfer = min(transfer, round((S.source.max_energy - S.source.energy) / S.cost))
|
||||
else
|
||||
transfer = min(transfer, S.max_amount - S.amount)
|
||||
if(pulledby)
|
||||
pulledby.start_pulling(S)
|
||||
S.copy_evidences(src)
|
||||
use(transfer)
|
||||
S.add(transfer)
|
||||
|
||||
/obj/item/stack/Crossed(obj/o)
|
||||
if(istype(o, merge_type) && !o.throwing)
|
||||
merge(o)
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/hitby(atom/movable/AM, skip, hitpush)
|
||||
if(istype(AM, merge_type))
|
||||
merge(AM)
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/attack_hand(mob/user)
|
||||
if (user.get_inactive_hand() == src)
|
||||
if(zero_amount())
|
||||
return
|
||||
var/obj/item/stack/F = new src.type(user, 1)
|
||||
. = F
|
||||
F.copy_evidences(src)
|
||||
user.put_in_hands(F)
|
||||
src.add_fingerprint(user)
|
||||
F.add_fingerprint(user)
|
||||
use(1)
|
||||
if (src && usr.machine==src)
|
||||
spawn(0) src.interact(usr)
|
||||
else
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/stack/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, merge_type))
|
||||
var/obj/item/stack/S = W
|
||||
merge(S)
|
||||
user << "<span class='notice'>Your [S.name] stack now contains [S.get_amount()] [S.singular_name]\s.</span>"
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj)
|
||||
src.blood_DNA = from.blood_DNA
|
||||
src.fingerprints = from.fingerprints
|
||||
src.fingerprintshidden = from.fingerprintshidden
|
||||
src.fingerprintslast = from.fingerprintslast
|
||||
//TODO bloody overlay
|
||||
|
||||
/*
|
||||
* Recipe datum
|
||||
*/
|
||||
/datum/stack_recipe
|
||||
var/title = "ERROR"
|
||||
var/result_type
|
||||
var/req_amount = 1
|
||||
var/res_amount = 1
|
||||
var/max_res_amount = 1
|
||||
var/time = 0
|
||||
var/one_per_turf = 0
|
||||
var/on_floor = 0
|
||||
|
||||
/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0)
|
||||
src.title = title
|
||||
src.result_type = result_type
|
||||
src.req_amount = req_amount
|
||||
src.res_amount = res_amount
|
||||
src.max_res_amount = max_res_amount
|
||||
src.time = time
|
||||
src.one_per_turf = one_per_turf
|
||||
src.on_floor = on_floor
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user