Merge branch 'ParadiseSS13/master' into runtime-fix-2

This commit is contained in:
joep van der velden
2020-03-18 16:59:49 +01:00
1748 changed files with 191532 additions and 184661 deletions
+107 -107
View File
@@ -1,107 +1,107 @@
/obj/item/aicard
name = "inteliCard"
icon = 'icons/obj/aicards.dmi'
icon_state = "aicard" // aicard-full
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
flags = NOBLUDGEON
var/flush = null
origin_tech = "programming=3;materials=3"
/obj/item/aicard/afterattack(atom/target, mob/user, proximity)
..()
if(!proximity || !target)
return
var/mob/living/silicon/ai/AI = locate(/mob/living/silicon/ai) in src
if(AI) //AI is on the card, implies user wants to upload it.
target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src)
add_attack_logs(user, AI, "Carded with [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_state() //Whatever happened, update the card's state (icon, name) to match.
/obj/item/aicard/proc/update_state()
var/mob/living/silicon/ai/AI = locate(/mob/living/silicon/ai) in src //AI is inside.
if(AI)
name = "intelliCard - [AI.name]"
if(AI.stat == DEAD)
icon_state = "aicard-404"
else
icon_state = "aicard-full"
AI.cancel_camera() //AI are forced to move when transferred, so do this whenver one is downloaded.
else
icon_state = "aicard"
name = "intelliCard"
overlays.Cut()
/obj/item/aicard/attack_self(mob/user)
ui_interact(user)
/obj/item/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = inventory_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "aicard.tmpl", "[name]", 600, 400, state = state)
ui.open()
ui.set_auto_update(1)
/obj/item/aicard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
var/data[0]
var/mob/living/silicon/ai/AI = locate() in src
if(istype(AI))
data["has_ai"] = 1
data["name"] = AI.name
data["hardware_integrity"] = ((AI.health + 100) / 2)
data["radio"] = !AI.aiRadio.disabledAi
data["wireless"] = !AI.control_disabled
data["operational"] = AI.stat != DEAD
data["flushing"] = flush
var/laws[0]
for(var/datum/ai_law/AL in AI.laws.all_laws())
laws[++laws.len] = list("index" = AL.get_index(), "law" = sanitize(AL.law))
data["laws"] = laws
data["has_laws"] = laws.len
return data
/obj/item/aicard/Topic(href, href_list, nowindow, state)
if(..())
return 1
var/mob/living/silicon/ai/AI = locate() in src
if(!istype(AI))
return 1
var/user = usr
if(href_list["wipe"])
var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No")
if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE))
msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].", ATKLOG_FEW)
add_attack_logs(user, AI, "Wiped with [src].")
flush = 1
AI.suiciding = 1
to_chat(AI, "Your core files are being wiped!")
while(AI && AI.stat != DEAD)
AI.adjustOxyLoss(2)
sleep(10)
flush = 0
if(href_list["radio"])
AI.aiRadio.disabledAi = text2num(href_list["radio"])
to_chat(AI, "<span class='warning'>Your Subspace Transceiver has been [AI.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [AI.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>")
if(href_list["wireless"])
AI.control_disabled = text2num(href_list["wireless"])
to_chat(AI, "<span class='warning'>Your wireless interface has been [AI.control_disabled ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [AI.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>")
update_icon()
return 1
/obj/item/aicard
name = "inteliCard"
icon = 'icons/obj/aicards.dmi'
icon_state = "aicard" // aicard-full
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
flags = NOBLUDGEON
var/flush = null
origin_tech = "programming=3;materials=3"
/obj/item/aicard/afterattack(atom/target, mob/user, proximity)
..()
if(!proximity || !target)
return
var/mob/living/silicon/ai/AI = locate(/mob/living/silicon/ai) in src
if(AI) //AI is on the card, implies user wants to upload it.
target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src)
add_attack_logs(user, AI, "Carded with [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_state() //Whatever happened, update the card's state (icon, name) to match.
/obj/item/aicard/proc/update_state()
var/mob/living/silicon/ai/AI = locate(/mob/living/silicon/ai) in src //AI is inside.
if(AI)
name = "intelliCard - [AI.name]"
if(AI.stat == DEAD)
icon_state = "aicard-404"
else
icon_state = "aicard-full"
AI.cancel_camera() //AI are forced to move when transferred, so do this whenver one is downloaded.
else
icon_state = "aicard"
name = "intelliCard"
overlays.Cut()
/obj/item/aicard/attack_self(mob/user)
ui_interact(user)
/obj/item/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = inventory_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "aicard.tmpl", "[name]", 600, 400, state = state)
ui.open()
ui.set_auto_update(1)
/obj/item/aicard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = inventory_state)
var/data[0]
var/mob/living/silicon/ai/AI = locate() in src
if(istype(AI))
data["has_ai"] = 1
data["name"] = AI.name
data["hardware_integrity"] = ((AI.health + 100) / 2)
data["radio"] = !AI.aiRadio.disabledAi
data["wireless"] = !AI.control_disabled
data["operational"] = AI.stat != DEAD
data["flushing"] = flush
var/laws[0]
for(var/datum/ai_law/AL in AI.laws.all_laws())
laws[++laws.len] = list("index" = AL.get_index(), "law" = sanitize(AL.law))
data["laws"] = laws
data["has_laws"] = laws.len
return data
/obj/item/aicard/Topic(href, href_list, nowindow, state)
if(..())
return 1
var/mob/living/silicon/ai/AI = locate() in src
if(!istype(AI))
return 1
var/user = usr
if(href_list["wipe"])
var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No")
if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE))
msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].", ATKLOG_FEW)
add_attack_logs(user, AI, "Wiped with [src].")
flush = 1
AI.suiciding = 1
to_chat(AI, "Your core files are being wiped!")
while(AI && AI.stat != DEAD)
AI.adjustOxyLoss(2)
sleep(10)
flush = 0
if(href_list["radio"])
AI.aiRadio.disabledAi = text2num(href_list["radio"])
to_chat(AI, "<span class='warning'>Your Subspace Transceiver has been [AI.aiRadio.disabledAi ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [AI.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.</span>")
if(href_list["wireless"])
AI.control_disabled = text2num(href_list["wireless"])
to_chat(AI, "<span class='warning'>Your wireless interface has been [AI.control_disabled ? "disabled" : "enabled"]!</span>")
to_chat(user, "<span class='notice'>You [AI.control_disabled ? "disable" : "enable"] the AI's wireless interface.</span>")
update_icon()
return 1
+258 -258
View File
@@ -1,258 +1,258 @@
/obj/item/chameleon
name = "chameleon-projector"
icon = 'icons/obj/device.dmi'
icon_state = "shield0"
flags = CONDUCT
slot_flags = SLOT_BELT
item_state = "electronic"
throwforce = 5.0
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
origin_tech = "syndicate=4;magnets=4"
var/can_use = 1
var/obj/effect/dummy/chameleon/active_dummy = null
var/saved_item = /obj/item/cigbutt
var/saved_icon = 'icons/obj/clothing/masks.dmi'
var/saved_icon_state = "cigbutt"
var/saved_overlays = null
var/saved_underlays = null
/obj/item/chameleon/dropped()
disrupt()
/obj/item/chameleon/equipped()
disrupt()
/obj/item/chameleon/attack_self()
toggle()
/obj/item/chameleon/afterattack(atom/target, mob/user , proximity)
if(!proximity) return
if(!active_dummy)
if(istype(target,/obj/item) && !istype(target, /obj/item/disk/nuclear))
playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6)
to_chat(user, "<span class='notice'>Scanned [target].</span>")
saved_item = target.type
saved_icon = target.icon
saved_icon_state = target.icon_state
saved_overlays = target.overlays
saved_underlays = target.underlays
/obj/item/chameleon/proc/toggle()
if(!can_use || !saved_item) return
if(active_dummy)
eject_all()
playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6)
QDEL_NULL(active_dummy)
to_chat(usr, "<span class='notice'>You deactivate [src].</span>")
var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src))
T.icon = 'icons/effects/effects.dmi'
flick("emppulse",T)
spawn(8)
qdel(T)
else
playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6)
var/obj/O = new saved_item(src)
if(!O) return
var/obj/effect/dummy/chameleon/C = new/obj/effect/dummy/chameleon(usr.loc)
C.activate(O, usr, saved_icon, saved_icon_state, saved_overlays, saved_underlays, src)
qdel(O)
to_chat(usr, "<span class='notice'>You activate [src].</span>")
var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src))
T.icon = 'icons/effects/effects.dmi'
flick("emppulse",T)
spawn(8)
qdel(T)
/obj/item/chameleon/proc/disrupt(var/delete_dummy = 1)
if(active_dummy)
do_sparks(5, 0, src)
eject_all()
if(delete_dummy)
qdel(active_dummy)
active_dummy = null
can_use = 0
spawn(50) can_use = 1
/obj/item/chameleon/proc/eject_all()
for(var/atom/movable/A in active_dummy)
A.loc = active_dummy.loc
if(ismob(A))
var/mob/M = A
M.reset_perspective(null)
/obj/effect/dummy/chameleon
name = ""
desc = ""
density = 0
anchored = 1
var/can_move = 1
var/obj/item/chameleon/master = null
/obj/effect/dummy/chameleon/proc/activate(var/obj/O, var/mob/M, new_icon, new_iconstate, new_overlays, new_underlays, var/obj/item/chameleon/C)
name = O.name
desc = O.desc
icon = new_icon
icon_state = new_iconstate
overlays = new_overlays
underlays = new_underlays
dir = O.dir
M.loc = src
master = C
master.active_dummy = src
/obj/effect/dummy/chameleon/attackby()
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
master.disrupt()
/obj/effect/dummy/chameleon/attack_hand()
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
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(severity) //no longer bomb-proof
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
spawn()
M.ex_act(severity)
master.disrupt()
/obj/effect/dummy/chameleon/bullet_act()
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
..()
master.disrupt()
/obj/effect/dummy/chameleon/relaymove(var/mob/user, direction)
if(istype(loc, /turf/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 ..()
/obj/item/borg_chameleon
name = "cyborg chameleon projector"
icon = 'icons/obj/device.dmi'
icon_state = "shield0"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
var/active = FALSE
var/activationCost = 300
var/activationUpkeep = 50
var/disguise = "landmate"
var/mob/living/silicon/robot/syndicate/saboteur/S
/obj/item/borg_chameleon/Destroy()
if(S)
S.cham_proj = null
return ..()
/obj/item/borg_chameleon/dropped(mob/user)
. = ..()
disrupt(user)
/obj/item/borg_chameleon/equipped(mob/user)
. = ..()
disrupt(user)
/obj/item/borg_chameleon/attack_self(mob/living/silicon/robot/syndicate/saboteur/user)
if(user && user.cell && user.cell.charge > activationCost)
if(isturf(user.loc))
toggle(user)
else
to_chat(user, "<span class='warning'>You can't use [src] while inside something!</span>")
else
to_chat(user, "<span class='warning'>You need at least [activationCost] charge in your cell to use [src]!</span>")
/obj/item/borg_chameleon/proc/toggle(mob/living/silicon/robot/syndicate/saboteur/user)
if(active)
playsound(src, 'sound/effects/pop.ogg', 100, 1, -6)
to_chat(user, "<span class='notice'>You deactivate [src].</span>")
deactivate(user)
else
to_chat(user, "<span class='notice'>You activate [src].</span>")
var/start = user.filters.len
var/X
var/Y
var/rsq
var/i
var/f
for(i in 1 to 7)
do
X = 60 * rand() - 30
Y = 60 * rand() - 30
rsq = X * X + Y * Y
while(rsq < 100 || rsq > 900)
user.filters += filter(type = "wave", x = X, y = Y, size = rand() * 2.5 + 0.5, offset = rand())
for(i in 1 to 7)
f = user.filters[start+i]
animate(f, offset = f:offset, time = 0, loop = 3, flags = ANIMATION_PARALLEL)
animate(offset = f:offset - 1, time = rand() * 20 + 10)
if(do_after(user, 50, target = user) && user.cell.use(activationCost))
playsound(src, 'sound/effects/bamf.ogg', 100, 1, -6)
to_chat(user, "<span class='notice'>You are now disguised as a Nanotrasen engineering cyborg.</span>")
activate(user)
else
to_chat(user, "<span class='warning'>The chameleon field fizzles.</span>")
do_sparks(3, FALSE, user)
for(i in 1 to min(7, user.filters.len)) // removing filters that are animating does nothing, we gotta stop the animations first
f = user.filters[start + i]
animate(f)
user.filters = null
/obj/item/borg_chameleon/process()
if(S)
if(!S.cell || !S.cell.use(activationUpkeep))
disrupt(S)
else
return PROCESS_KILL
/obj/item/borg_chameleon/proc/activate(mob/living/silicon/robot/syndicate/saboteur/user)
START_PROCESSING(SSobj, src)
S = user
user.base_icon = disguise
user.icon_state = disguise
user.cham_proj = src
active = TRUE
user.update_icons()
/obj/item/borg_chameleon/proc/deactivate(mob/living/silicon/robot/syndicate/saboteur/user)
STOP_PROCESSING(SSobj, src)
S = user
user.base_icon = initial(user.base_icon)
user.icon_state = initial(user.icon_state)
active = FALSE
user.update_icons()
/obj/item/borg_chameleon/proc/disrupt(mob/living/silicon/robot/syndicate/saboteur/user)
if(active)
to_chat(user, "<span class='danger'>Your chameleon field deactivates.</span>")
deactivate(user)
/obj/item/chameleon
name = "chameleon-projector"
icon = 'icons/obj/device.dmi'
icon_state = "shield0"
flags = CONDUCT
slot_flags = SLOT_BELT
item_state = "electronic"
throwforce = 5.0
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
origin_tech = "syndicate=4;magnets=4"
var/can_use = 1
var/obj/effect/dummy/chameleon/active_dummy = null
var/saved_item = /obj/item/cigbutt
var/saved_icon = 'icons/obj/clothing/masks.dmi'
var/saved_icon_state = "cigbutt"
var/saved_overlays = null
var/saved_underlays = null
/obj/item/chameleon/dropped()
disrupt()
/obj/item/chameleon/equipped()
disrupt()
/obj/item/chameleon/attack_self()
toggle()
/obj/item/chameleon/afterattack(atom/target, mob/user , proximity)
if(!proximity) return
if(!active_dummy)
if(istype(target,/obj/item) && !istype(target, /obj/item/disk/nuclear))
playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6)
to_chat(user, "<span class='notice'>Scanned [target].</span>")
saved_item = target.type
saved_icon = target.icon
saved_icon_state = target.icon_state
saved_overlays = target.overlays
saved_underlays = target.underlays
/obj/item/chameleon/proc/toggle()
if(!can_use || !saved_item) return
if(active_dummy)
eject_all()
playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6)
QDEL_NULL(active_dummy)
to_chat(usr, "<span class='notice'>You deactivate [src].</span>")
var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src))
T.icon = 'icons/effects/effects.dmi'
flick("emppulse",T)
spawn(8)
qdel(T)
else
playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6)
var/obj/O = new saved_item(src)
if(!O) return
var/obj/effect/dummy/chameleon/C = new/obj/effect/dummy/chameleon(usr.loc)
C.activate(O, usr, saved_icon, saved_icon_state, saved_overlays, saved_underlays, src)
qdel(O)
to_chat(usr, "<span class='notice'>You activate [src].</span>")
var/obj/effect/overlay/T = new/obj/effect/overlay(get_turf(src))
T.icon = 'icons/effects/effects.dmi'
flick("emppulse",T)
spawn(8)
qdel(T)
/obj/item/chameleon/proc/disrupt(var/delete_dummy = 1)
if(active_dummy)
do_sparks(5, 0, src)
eject_all()
if(delete_dummy)
qdel(active_dummy)
active_dummy = null
can_use = 0
spawn(50) can_use = 1
/obj/item/chameleon/proc/eject_all()
for(var/atom/movable/A in active_dummy)
A.loc = active_dummy.loc
if(ismob(A))
var/mob/M = A
M.reset_perspective(null)
/obj/effect/dummy/chameleon
name = ""
desc = ""
density = 0
anchored = 1
var/can_move = 1
var/obj/item/chameleon/master = null
/obj/effect/dummy/chameleon/proc/activate(var/obj/O, var/mob/M, new_icon, new_iconstate, new_overlays, new_underlays, var/obj/item/chameleon/C)
name = O.name
desc = O.desc
icon = new_icon
icon_state = new_iconstate
overlays = new_overlays
underlays = new_underlays
dir = O.dir
M.loc = src
master = C
master.active_dummy = src
/obj/effect/dummy/chameleon/attackby()
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
master.disrupt()
/obj/effect/dummy/chameleon/attack_hand()
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
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(severity) //no longer bomb-proof
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
spawn()
M.ex_act(severity)
master.disrupt()
/obj/effect/dummy/chameleon/bullet_act()
for(var/mob/M in src)
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
..()
master.disrupt()
/obj/effect/dummy/chameleon/relaymove(var/mob/user, direction)
if(istype(loc, /turf/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 ..()
/obj/item/borg_chameleon
name = "cyborg chameleon projector"
icon = 'icons/obj/device.dmi'
icon_state = "shield0"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
var/active = FALSE
var/activationCost = 300
var/activationUpkeep = 50
var/disguise = "landmate"
var/mob/living/silicon/robot/syndicate/saboteur/S
/obj/item/borg_chameleon/Destroy()
if(S)
S.cham_proj = null
return ..()
/obj/item/borg_chameleon/dropped(mob/user)
. = ..()
disrupt(user)
/obj/item/borg_chameleon/equipped(mob/user)
. = ..()
disrupt(user)
/obj/item/borg_chameleon/attack_self(mob/living/silicon/robot/syndicate/saboteur/user)
if(user && user.cell && user.cell.charge > activationCost)
if(isturf(user.loc))
toggle(user)
else
to_chat(user, "<span class='warning'>You can't use [src] while inside something!</span>")
else
to_chat(user, "<span class='warning'>You need at least [activationCost] charge in your cell to use [src]!</span>")
/obj/item/borg_chameleon/proc/toggle(mob/living/silicon/robot/syndicate/saboteur/user)
if(active)
playsound(src, 'sound/effects/pop.ogg', 100, 1, -6)
to_chat(user, "<span class='notice'>You deactivate [src].</span>")
deactivate(user)
else
to_chat(user, "<span class='notice'>You activate [src].</span>")
var/start = user.filters.len
var/X
var/Y
var/rsq
var/i
var/f
for(i in 1 to 7)
do
X = 60 * rand() - 30
Y = 60 * rand() - 30
rsq = X * X + Y * Y
while(rsq < 100 || rsq > 900)
user.filters += filter(type = "wave", x = X, y = Y, size = rand() * 2.5 + 0.5, offset = rand())
for(i in 1 to 7)
f = user.filters[start+i]
animate(f, offset = f:offset, time = 0, loop = 3, flags = ANIMATION_PARALLEL)
animate(offset = f:offset - 1, time = rand() * 20 + 10)
if(do_after(user, 50, target = user) && user.cell.use(activationCost))
playsound(src, 'sound/effects/bamf.ogg', 100, 1, -6)
to_chat(user, "<span class='notice'>You are now disguised as a Nanotrasen engineering cyborg.</span>")
activate(user)
else
to_chat(user, "<span class='warning'>The chameleon field fizzles.</span>")
do_sparks(3, FALSE, user)
for(i in 1 to min(7, user.filters.len)) // removing filters that are animating does nothing, we gotta stop the animations first
f = user.filters[start + i]
animate(f)
user.filters = null
/obj/item/borg_chameleon/process()
if(S)
if(!S.cell || !S.cell.use(activationUpkeep))
disrupt(S)
else
return PROCESS_KILL
/obj/item/borg_chameleon/proc/activate(mob/living/silicon/robot/syndicate/saboteur/user)
START_PROCESSING(SSobj, src)
S = user
user.base_icon = disguise
user.icon_state = disguise
user.cham_proj = src
active = TRUE
user.update_icons()
/obj/item/borg_chameleon/proc/deactivate(mob/living/silicon/robot/syndicate/saboteur/user)
STOP_PROCESSING(SSobj, src)
S = user
user.base_icon = initial(user.base_icon)
user.icon_state = initial(user.icon_state)
active = FALSE
user.update_icons()
/obj/item/borg_chameleon/proc/disrupt(mob/living/silicon/robot/syndicate/saboteur/user)
if(active)
to_chat(user, "<span class='danger'>Your chameleon field deactivates.</span>")
deactivate(user)
@@ -93,4 +93,4 @@
for(var/mob/living/M in T)
M.visible_message("\The [M] gets obliterated!")
M.gib()
M.gib()
+398 -397
View File
@@ -1,397 +1,398 @@
/obj/item/flashlight
name = "flashlight"
desc = "A hand-held emergency light."
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight"
item_state = "flashlight"
w_class = WEIGHT_CLASS_SMALL
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 = FALSE
var/brightness_on = 4 //luminosity when on
var/togglesound = 'sound/weapons/empty.ogg'
/obj/item/flashlight/Initialize()
. = ..()
if(on)
icon_state = "[initial(icon_state)]-on"
set_light(brightness_on)
else
icon_state = initial(icon_state)
set_light(0)
/obj/item/flashlight/proc/update_brightness(var/mob/user = null)
if(on)
icon_state = "[initial(icon_state)]-on"
set_light(brightness_on)
else
icon_state = initial(icon_state)
set_light(0)
/obj/item/flashlight/attack_self(mob/user)
if(!isturf(user.loc))
to_chat(user, "You cannot turn the light on while in this [user.loc].")//To prevent some lighting anomalities.
return 0
on = !on
playsound(user, togglesound, 100, 1)
update_brightness(user)
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
return 1
/obj/item/flashlight/attack(mob/living/M as mob, mob/living/user as mob)
add_fingerprint(user)
if(on && user.zone_selected == "eyes")
if(((CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
if(!(istype(user, /mob/living/carbon/human) || SSticker) && SSticker.mode.name != "monkey") //don't have dexterity
to_chat(user, "<span class='notice'>You don't have the dexterity to do this!</span>")
return
var/mob/living/carbon/human/H = M //mob has protective eyewear
if(istype(H) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags_cover & GLASSESCOVERSEYES)))
to_chat(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("<span class='notice'>[M] directs [src] to [M.p_their()] eyes.</span>", \
"<span class='notice'>You wave the light in front of your eyes! Trippy!</span>")
else
M.visible_message("<span class='notice'>[M] directs [src] to [M.p_their()] eyes.</span>", \
"<span class='notice'>You wave the light in front of your eyes.</span>")
else
user.visible_message("<span class='notice'>[user] directs [src] to [M]'s eyes.</span>", \
"<span class='notice'>You direct [src] to [M]'s eyes.</span>")
if(istype(H)) //robots and aliens are unaffected
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
if(M.stat == DEAD || !eyes || M.disabilities & BLIND) //mob is dead or fully blind
to_chat(user, "<span class='notice'>[M]'s pupils are unresponsive to the light!</span>")
else if((XRAY in M.mutations) || eyes.see_in_dark >= 8) //The mob's either got the X-RAY vision or has a tapetum lucidum (extreme nightvision, i.e. Vulp/Tajara with COLOURBLIND & their monkey forms).
to_chat(user, "<span class='notice'>[M]'s pupils glow eerily!</span>")
else //they're okay!
if(M.flash_eyes(visual = 1))
to_chat(user, "<span class='notice'>[M]'s pupils narrow.</span>")
else
return ..()
/obj/item/flashlight/extinguish_light()
if(on)
on = FALSE
update_brightness()
/obj/item/flashlight/pen
name = "penlight"
desc = "A pen-sized light, used by medical staff."
icon_state = "penlight"
item_state = ""
w_class = WEIGHT_CLASS_TINY
slot_flags = SLOT_BELT | SLOT_EARS
flags = CONDUCT
brightness_on = 2
/obj/item/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'
/obj/item/flashlight/drone
name = "low-power flashlight"
desc = "A miniature lamp, that might be used by small robots."
icon_state = "penlight"
item_state = ""
flags = CONDUCT
brightness_on = 2
w_class = WEIGHT_CLASS_TINY
// the desk lamps are a bit special
/obj/item/flashlight/lamp
name = "desk lamp"
desc = "A desk lamp with an adjustable mount."
icon_state = "lamp"
item_state = "lamp"
brightness_on = 5
w_class = WEIGHT_CLASS_BULKY
flags = CONDUCT
materials = list()
on = TRUE
// green-shaded desk lamp
/obj/item/flashlight/lamp/green
desc = "A classic green-shaded desk lamp."
icon_state = "lampgreen"
item_state = "lampgreen"
/obj/item/flashlight/lamp/verb/toggle_light()
set name = "Toggle light"
set category = "Object"
set src in oview(1)
if(!usr.stat)
attack_self(usr)
//Bananalamp
/obj/item/flashlight/lamp/bananalamp
name = "banana lamp"
desc = "Only a clown would think to make a ghetto banana-shaped lamp. Even has a goofy pullstring."
icon_state = "bananalamp"
item_state = "bananalamp"
// FLARES
/obj/item/flashlight/flare
name = "flare"
desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
brightness_on = 8
light_color = "#ff0000"
icon_state = "flare"
item_state = "flare"
togglesound = 'sound/goonstation/misc/matchstick_light.ogg'
var/fuel = 0
var/on_damage = 7
var/produce_heat = 1500
var/fuel_lower = 800
var/fuel_upp = 1000
/obj/item/flashlight/flare/New()
fuel = rand(fuel_lower, fuel_upp)
..()
/obj/item/flashlight/flare/process()
var/turf/pos = get_turf(src)
if(pos && produce_heat)
pos.hotspot_expose(produce_heat, 5)
fuel = max(fuel - 1, 0)
if(!fuel || !on)
turn_off()
if(!fuel)
src.icon_state = "[initial(icon_state)]-empty"
STOP_PROCESSING(SSobj, src)
/obj/item/flashlight/flare/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/flashlight/flare/proc/turn_off()
on = 0
src.force = initial(src.force)
src.damtype = initial(src.damtype)
if(ismob(loc))
var/mob/U = loc
update_brightness(U)
else
update_brightness(null)
/obj/item/flashlight/flare/update_brightness(var/mob/user = null)
..()
if(on)
item_state = "[initial(item_state)]-on"
else
item_state = "[initial(item_state)]"
/obj/item/flashlight/flare/attack_self(mob/user)
// Usual checks
if(!fuel)
to_chat(user, "<span class='notice'>[src] is out of fuel.</span>")
return
if(on)
to_chat(user, "<span class='notice'>[src] is already on.</span>")
return
. = ..()
// All good, turn it on.
if(.)
user.visible_message("<span class='notice'>[user] activates [src].</span>", "<span class='notice'>You activate [src].</span>")
src.force = on_damage
src.damtype = "fire"
START_PROCESSING(SSobj, src)
// GLOWSTICKS
/obj/item/flashlight/flare/glowstick
name = "green glowstick"
desc = "A military-grade glowstick."
brightness_on = 4
color = LIGHT_COLOR_GREEN
icon_state = "glowstick"
item_state = "glowstick"
togglesound = 'sound/effects/bone_break_1.ogg'
produce_heat = 0
fuel_lower = 1600
fuel_upp = 2000
/obj/item/flashlight/flare/glowstick/Initialize()
light_color = color
..()
/obj/item/flashlight/flare/glowstick/update_icon()
item_state = "glowstick"
cut_overlays()
if(!fuel)
icon_state = "glowstick-empty"
cut_overlays()
update_brightness(0)
else if(on)
var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
glowstick_overlay.color = color
add_overlay(glowstick_overlay)
item_state = "glowstick-on"
update_brightness(brightness_on)
else
icon_state = "glowstick"
cut_overlays()
/obj/item/flashlight/flare/glowstick/red
name = "red glowstick"
color = LIGHT_COLOR_RED
/obj/item/flashlight/flare/glowstick/blue
name = "blue glowstick"
color = LIGHT_COLOR_BLUE
/obj/item/flashlight/flare/glowstick/orange
name = "orange glowstick"
color = LIGHT_COLOR_ORANGE
/obj/item/flashlight/flare/glowstick/yellow
name = "yellow glowstick"
color = LIGHT_COLOR_YELLOW
/obj/item/flashlight/flare/glowstick/pink
name = "pink glowstick"
color = LIGHT_COLOR_PINK
/obj/item/flashlight/flare/glowstick/emergency
name = "emergency glowstick"
desc = "A cheap looking, mass produced glowstick. You can practically feel it was made on a tight budget."
color = LIGHT_COLOR_BLUE
fuel_lower = 30
fuel_upp = 90
/obj/item/flashlight/flare/glowstick/random
name = "random colored glowstick"
icon_state = "random_glowstick"
color = null
/obj/item/flashlight/flare/glowstick/random/Initialize()
. = ..()
var/T = pick(typesof(/obj/item/flashlight/flare/glowstick) - /obj/item/flashlight/flare/glowstick/random - /obj/item/flashlight/flare/glowstick/emergency)
new T(loc)
qdel(src) // return INITIALIZE_HINT_QDEL <-- Doesn't work
/obj/item/flashlight/flare/extinguish_light()
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/flare/torch
name = "torch"
desc = "A torch fashioned from some leaves and a log."
w_class = WEIGHT_CLASS_BULKY
brightness_on = 7
icon_state = "torch"
item_state = "torch"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
light_color = LIGHT_COLOR_ORANGE
on_damage = 10
/obj/item/flashlight/slime
gender = PLURAL
name = "glowing slime extract"
desc = "A glowing ball of what appears to be amber."
icon = 'icons/obj/lighting.dmi'
icon_state = "floor1" //not a slime extract sprite but... something close enough!
item_state = "slime"
w_class = WEIGHT_CLASS_TINY
brightness_on = 6
light_color = "#FFBF00"
materials = list()
on = TRUE //Bio-luminesence has one setting, on.
/obj/item/flashlight/slime/New()
set_light(brightness_on)
spawn(1) //Might be sloppy, but seems to be necessary to prevent further runtimes and make these work as intended... don't judge me!
update_brightness()
icon_state = initial(icon_state)
/obj/item/flashlight/slime/attack_self(mob/user)
return //Bio-luminescence does not toggle.
/obj/item/flashlight/slime/extinguish_light()
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/emp
origin_tech = "magnets=3;syndicate=1"
var/emp_max_charges = 4
var/emp_cur_charges = 4
var/charge_tick = 0
/obj/item/flashlight/emp/New()
..()
START_PROCESSING(SSobj, src)
/obj/item/flashlight/emp/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/flashlight/emp/process()
charge_tick++
if(charge_tick < 10)
return FALSE
charge_tick = 0
emp_cur_charges = min(emp_cur_charges+1, emp_max_charges)
return TRUE
/obj/item/flashlight/emp/attack(mob/living/M as mob, mob/living/user as mob)
if(on && user.zone_selected == "eyes") // call original attack proc only if aiming at the eyes
..()
return
/obj/item/flashlight/emp/afterattack(atom/A as mob|obj, mob/user, proximity)
if(!proximity) return
if(emp_cur_charges > 0)
emp_cur_charges -= 1
A.visible_message("<span class='danger'>[user] blinks \the [src] at \the [A].", \
"<span class='userdanger'>[user] blinks \the [src] at \the [A].")
if(ismob(A))
var/mob/M = A
add_attack_logs(user, M, "Hit with EMP-light")
to_chat(user, "[src] now has [emp_cur_charges] charge\s.")
A.emp_act(1)
else
to_chat(user, "<span class='warning'>\The [src] needs time to recharge!</span>")
return
/obj/item/flashlight/spotlight //invisible lighting source
name = "disco light"
desc = "Groovy..."
icon_state = null
light_color = null
brightness_on = 0
light_range = 0
light_power = 10
alpha = 0
layer = 0
on = TRUE
anchored = TRUE
var/range = null
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/item/flashlight
name = "flashlight"
desc = "A hand-held emergency light."
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight"
item_state = "flashlight"
w_class = WEIGHT_CLASS_SMALL
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 = FALSE
var/brightness_on = 4 //luminosity when on
var/togglesound = 'sound/weapons/empty.ogg'
/obj/item/flashlight/Initialize()
. = ..()
if(on)
icon_state = "[initial(icon_state)]-on"
set_light(brightness_on)
else
icon_state = initial(icon_state)
set_light(0)
/obj/item/flashlight/proc/update_brightness(var/mob/user = null)
if(on)
icon_state = "[initial(icon_state)]-on"
set_light(brightness_on)
else
icon_state = initial(icon_state)
set_light(0)
/obj/item/flashlight/attack_self(mob/user)
if(!isturf(user.loc))
to_chat(user, "You cannot turn the light on while in this [user.loc].")//To prevent some lighting anomalities.
return 0
on = !on
playsound(user, togglesound, 100, 1)
update_brightness(user)
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
return 1
/obj/item/flashlight/attack(mob/living/M as mob, mob/living/user as mob)
add_fingerprint(user)
if(on && user.zone_selected == "eyes")
if(((CLUMSY in user.mutations) || user.getBrainLoss() >= 60) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
if(!(istype(user, /mob/living/carbon/human) || SSticker) && SSticker.mode.name != "monkey") //don't have dexterity
to_chat(user, "<span class='notice'>You don't have the dexterity to do this!</span>")
return
var/mob/living/carbon/human/H = M //mob has protective eyewear
if(istype(H) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags_cover & GLASSESCOVERSEYES)))
to_chat(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("<span class='notice'>[M] directs [src] to [M.p_their()] eyes.</span>", \
"<span class='notice'>You wave the light in front of your eyes! Trippy!</span>")
else
M.visible_message("<span class='notice'>[M] directs [src] to [M.p_their()] eyes.</span>", \
"<span class='notice'>You wave the light in front of your eyes.</span>")
else
user.visible_message("<span class='notice'>[user] directs [src] to [M]'s eyes.</span>", \
"<span class='notice'>You direct [src] to [M]'s eyes.</span>")
if(istype(H)) //robots and aliens are unaffected
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
if(M.stat == DEAD || !eyes || M.disabilities & BLIND) //mob is dead or fully blind
to_chat(user, "<span class='notice'>[M]'s pupils are unresponsive to the light!</span>")
else if((XRAY in M.mutations) || eyes.see_in_dark >= 8) //The mob's either got the X-RAY vision or has a tapetum lucidum (extreme nightvision, i.e. Vulp/Tajara with COLOURBLIND & their monkey forms).
to_chat(user, "<span class='notice'>[M]'s pupils glow eerily!</span>")
else //they're okay!
if(M.flash_eyes(visual = 1))
to_chat(user, "<span class='notice'>[M]'s pupils narrow.</span>")
else
return ..()
/obj/item/flashlight/extinguish_light()
if(on)
on = FALSE
update_brightness()
/obj/item/flashlight/pen
name = "penlight"
desc = "A pen-sized light, used by medical staff."
icon_state = "penlight"
item_state = ""
w_class = WEIGHT_CLASS_TINY
slot_flags = SLOT_BELT | SLOT_EARS
flags = CONDUCT
brightness_on = 2
/obj/item/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'
/obj/item/flashlight/drone
name = "low-power flashlight"
desc = "A miniature lamp, that might be used by small robots."
icon_state = "penlight"
item_state = ""
flags = CONDUCT
brightness_on = 2
w_class = WEIGHT_CLASS_TINY
// the desk lamps are a bit special
/obj/item/flashlight/lamp
name = "desk lamp"
desc = "A desk lamp with an adjustable mount."
icon_state = "lamp"
item_state = "lamp"
brightness_on = 5
w_class = WEIGHT_CLASS_BULKY
flags = CONDUCT
materials = list()
on = TRUE
// green-shaded desk lamp
/obj/item/flashlight/lamp/green
desc = "A classic green-shaded desk lamp."
icon_state = "lampgreen"
item_state = "lampgreen"
/obj/item/flashlight/lamp/verb/toggle_light()
set name = "Toggle light"
set category = "Object"
set src in oview(1)
if(!usr.stat)
attack_self(usr)
//Bananalamp
/obj/item/flashlight/lamp/bananalamp
name = "banana lamp"
desc = "Only a clown would think to make a ghetto banana-shaped lamp. Even has a goofy pullstring."
icon_state = "bananalamp"
item_state = "bananalamp"
// FLARES
/obj/item/flashlight/flare
name = "flare"
desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
brightness_on = 8
light_color = "#ff0000"
icon_state = "flare"
item_state = "flare"
togglesound = 'sound/goonstation/misc/matchstick_light.ogg'
var/fuel = 0
var/on_damage = 7
var/produce_heat = 1500
var/fuel_lower = 800
var/fuel_upp = 1000
/obj/item/flashlight/flare/New()
fuel = rand(fuel_lower, fuel_upp)
..()
/obj/item/flashlight/flare/process()
var/turf/pos = get_turf(src)
if(pos && produce_heat)
pos.hotspot_expose(produce_heat, 5)
fuel = max(fuel - 1, 0)
if(!fuel || !on)
turn_off()
if(!fuel)
src.icon_state = "[initial(icon_state)]-empty"
STOP_PROCESSING(SSobj, src)
/obj/item/flashlight/flare/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/flashlight/flare/proc/turn_off()
on = 0
src.force = initial(src.force)
src.damtype = initial(src.damtype)
if(ismob(loc))
var/mob/U = loc
update_brightness(U)
else
update_brightness(null)
/obj/item/flashlight/flare/update_brightness(var/mob/user = null)
..()
if(on)
item_state = "[initial(item_state)]-on"
else
item_state = "[initial(item_state)]"
/obj/item/flashlight/flare/attack_self(mob/user)
// Usual checks
if(!fuel)
to_chat(user, "<span class='notice'>[src] is out of fuel.</span>")
return
if(on)
to_chat(user, "<span class='notice'>[src] is already on.</span>")
return
. = ..()
// All good, turn it on.
if(.)
user.visible_message("<span class='notice'>[user] activates [src].</span>", "<span class='notice'>You activate [src].</span>")
src.force = on_damage
src.damtype = "fire"
START_PROCESSING(SSobj, src)
// GLOWSTICKS
/obj/item/flashlight/flare/glowstick
name = "green glowstick"
desc = "A military-grade glowstick."
brightness_on = 4
color = LIGHT_COLOR_GREEN
icon_state = "glowstick"
item_state = "glowstick"
togglesound = 'sound/effects/bone_break_1.ogg'
produce_heat = 0
fuel_lower = 1600
fuel_upp = 2000
/obj/item/flashlight/flare/glowstick/Initialize()
light_color = color
..()
/obj/item/flashlight/flare/glowstick/update_icon()
item_state = "glowstick"
cut_overlays()
if(!fuel)
icon_state = "glowstick-empty"
cut_overlays()
update_brightness(0)
else if(on)
var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
glowstick_overlay.color = color
add_overlay(glowstick_overlay)
item_state = "glowstick-on"
update_brightness(brightness_on)
else
icon_state = "glowstick"
cut_overlays()
/obj/item/flashlight/flare/glowstick/red
name = "red glowstick"
color = LIGHT_COLOR_RED
/obj/item/flashlight/flare/glowstick/blue
name = "blue glowstick"
color = LIGHT_COLOR_BLUE
/obj/item/flashlight/flare/glowstick/orange
name = "orange glowstick"
color = LIGHT_COLOR_ORANGE
/obj/item/flashlight/flare/glowstick/yellow
name = "yellow glowstick"
color = LIGHT_COLOR_YELLOW
/obj/item/flashlight/flare/glowstick/pink
name = "pink glowstick"
color = LIGHT_COLOR_PINK
/obj/item/flashlight/flare/glowstick/emergency
name = "emergency glowstick"
desc = "A cheap looking, mass produced glowstick. You can practically feel it was made on a tight budget."
color = LIGHT_COLOR_BLUE
fuel_lower = 30
fuel_upp = 90
/obj/item/flashlight/flare/glowstick/random
name = "random colored glowstick"
icon_state = "random_glowstick"
color = null
/obj/item/flashlight/flare/glowstick/random/Initialize()
. = ..()
var/T = pick(typesof(/obj/item/flashlight/flare/glowstick) - /obj/item/flashlight/flare/glowstick/random - /obj/item/flashlight/flare/glowstick/emergency)
new T(loc)
qdel(src) // return INITIALIZE_HINT_QDEL <-- Doesn't work
/obj/item/flashlight/flare/extinguish_light()
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/flare/torch
name = "torch"
desc = "A torch fashioned from some leaves and a log."
w_class = WEIGHT_CLASS_BULKY
brightness_on = 7
icon_state = "torch"
item_state = "torch"
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
light_color = LIGHT_COLOR_ORANGE
on_damage = 10
/obj/item/flashlight/slime
gender = PLURAL
name = "glowing slime extract"
desc = "A glowing ball of what appears to be amber."
icon = 'icons/obj/lighting.dmi'
icon_state = "floor1" //not a slime extract sprite but... something close enough!
item_state = "slime"
w_class = WEIGHT_CLASS_TINY
brightness_on = 6
light_color = "#FFBF00"
materials = list()
on = TRUE //Bio-luminesence has one setting, on.
/obj/item/flashlight/slime/New()
..()
set_light(brightness_on)
spawn(1) //Might be sloppy, but seems to be necessary to prevent further runtimes and make these work as intended... don't judge me!
update_brightness()
icon_state = initial(icon_state)
/obj/item/flashlight/slime/attack_self(mob/user)
return //Bio-luminescence does not toggle.
/obj/item/flashlight/slime/extinguish_light()
visible_message("<span class='danger'>[src] dims slightly before scattering the shadows around it.</span>")
/obj/item/flashlight/emp
origin_tech = "magnets=3;syndicate=1"
var/emp_max_charges = 4
var/emp_cur_charges = 4
var/charge_tick = 0
/obj/item/flashlight/emp/New()
..()
START_PROCESSING(SSobj, src)
/obj/item/flashlight/emp/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/flashlight/emp/process()
charge_tick++
if(charge_tick < 10)
return FALSE
charge_tick = 0
emp_cur_charges = min(emp_cur_charges+1, emp_max_charges)
return TRUE
/obj/item/flashlight/emp/attack(mob/living/M as mob, mob/living/user as mob)
if(on && user.zone_selected == "eyes") // call original attack proc only if aiming at the eyes
..()
return
/obj/item/flashlight/emp/afterattack(atom/A as mob|obj, mob/user, proximity)
if(!proximity) return
if(emp_cur_charges > 0)
emp_cur_charges -= 1
A.visible_message("<span class='danger'>[user] blinks \the [src] at \the [A].", \
"<span class='userdanger'>[user] blinks \the [src] at \the [A].")
if(ismob(A))
var/mob/M = A
add_attack_logs(user, M, "Hit with EMP-light")
to_chat(user, "[src] now has [emp_cur_charges] charge\s.")
A.emp_act(1)
else
to_chat(user, "<span class='warning'>\The [src] needs time to recharge!</span>")
return
/obj/item/flashlight/spotlight //invisible lighting source
name = "disco light"
desc = "Groovy..."
icon_state = null
light_color = null
brightness_on = 0
light_range = 0
light_power = 10
alpha = 0
layer = 0
on = TRUE
anchored = TRUE
var/range = null
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
@@ -14,12 +14,12 @@
flags = CONDUCT
slot_flags = SLOT_BELT
var/static/list/allowed_states = list("arrival", "arrivalcorner", "bar", "barber", "blackcorner", "blue", "bluecorner",
var/static/list/allowed_states = list("arrival", "arrivalcorner", "bar", "barber", "bcircuit", "blackcorner", "blue", "bluecorner",
"bluefull", "bluered", "blueyellow", "blueyellowfull", "bot", "brown", "browncorner", "browncornerold", "brownold",
"cafeteria", "caution", "cautioncorner", "chapel", "cmo", "dark", "delivery", "escape", "escapecorner", "floor",
"freezerfloor", "green", "greenblue", "greenbluefull", "greencorner", "greenfull", "greenyellow",
"freezerfloor", "gcircuit", "green", "greenblue", "greenbluefull", "greencorner", "greenfull", "greenyellow",
"greenyellowfull", "grimy", "loadingarea", "neutral", "neutralcorner", "neutralfull", "orange", "orangecorner",
"orangefull", "purple", "purplecorner", "purplefull", "rampbottom", "ramptop", "red", "redblue", "redbluefull",
"orangefull", "purple", "purplecorner", "purplefull", "rcircuit", "rampbottom", "ramptop", "red", "redblue", "redbluefull",
"redcorner", "redfull", "redgreen", "redgreenfull", "redyellow", "redyellowfull", "warning", "warningcorner", "warnwhite",
"warnwhitecorner", "white", "whiteblue", "whitebluecorner", "whitebluefull", "whitebot", "whitecorner", "whitedelivery",
"whitegreen", "whitegreencorner", "whitegreenfull", "whitehall", "whitepurple", "whitepurplecorner", "whitepurplefull",
@@ -88,4 +88,4 @@
/obj/item/handheld_defibrillator/proc/recharge()
cooldown = FALSE
icon_state = "[icon_base]-on"
playsound(loc, "sound/weapons/flash.ogg", 75, 1)
playsound(loc, "sound/weapons/flash.ogg", 75, 1)
@@ -167,7 +167,7 @@
reqs = list(/obj/item/stack/sheet/wood = 5,
/obj/item/stack/cable_coil = 6,
/obj/item/stack/tape_roll = 5)
tools = list(/obj/item/screwdriver, /obj/item/wirecutters)
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
time = 80
category = CAT_MISC
@@ -177,7 +177,7 @@
reqs = list(/obj/item/stack/sheet/wood = 5,
/obj/item/stack/cable_coil = 6,
/obj/item/stack/tape_roll = 5)
tools = list(/obj/item/screwdriver, /obj/item/wirecutters)
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
time = 80
category = CAT_MISC
@@ -187,6 +187,6 @@
reqs = list(/obj/item/stack/sheet/metal = 5,
/obj/item/stack/cable_coil = 6,
/obj/item/stack/tape_roll = 5)
tools = list(/obj/item/screwdriver, /obj/item/wirecutters)
tools = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
time = 80
category = CAT_MISC
category = CAT_MISC
+269 -269
View File
@@ -1,269 +1,269 @@
// 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/lightreplacer
name = "light replacer"
desc = "A device to automatically replace lights. Refill with broken or working light bulbs, or sheets of glass."
icon = 'icons/obj/janitor.dmi'
icon_state = "lightreplacer0"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
flags = CONDUCT
slot_flags = SLOT_BELT
origin_tech = "magnets=3;engineering=4"
force = 8
var/emagged = FALSE
var/max_uses = 20
var/uses = 10
// 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/lightreplacer/examine(mob/user)
. = ..()
. += status_string()
/obj/item/lightreplacer/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = I
if(uses >= max_uses)
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
else if(G.use(decrement))
AddUses(increment)
to_chat(user, "<span class='notice'>You insert a piece of glass into [src]. You have [uses] light\s remaining.</span>")
return
else
to_chat(user, "<span class='warning'>You need one sheet of glass to replace lights!</span>")
return
if(istype(I, /obj/item/shard))
if(uses >= max_uses)
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
if(!user.unEquip(I))
return
AddUses(round(increment * 0.75))
to_chat(user, "<span class='notice'>You insert a shard of glass into [src]. You have [uses] light\s remaining.</span>")
qdel(I)
return
if(istype(I, /obj/item/light))
var/obj/item/light/L = I
if(L.status == 0) // LIGHT OKAY
if(uses < max_uses)
if(!user.unEquip(L))
return
AddUses(1)
qdel(L)
else
if(!user.unEquip(L))
return
to_chat(user, "<span class='notice'>You insert [L] into [src].</span>")
AddShards(1, user)
qdel(L)
return
if(istype(I, /obj/item/storage))
var/obj/item/storage/S = I
var/found_lightbulbs = FALSE
var/replaced_something = TRUE
for(var/obj/item/IT in S.contents)
if(istype(IT, /obj/item/light))
var/obj/item/light/L = IT
found_lightbulbs = TRUE
if(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, user)
qdel(L)
if(!found_lightbulbs)
to_chat(user, "<span class='warning'>[S] contains no bulbs.</span>")
return
if(!replaced_something && uses == max_uses)
to_chat(user, "<span class='warning'>[src] is full!</span>")
return
to_chat(user, "<span class='notice'>You fill [src] with lights from [S]. " + status_string() + "</span>")
return
return ..()
/obj/item/lightreplacer/emag_act(user as mob)
if(!emagged)
Emag()
/obj/item/lightreplacer/attack_self(mob/user)
for(var/obj/machinery/light/target in user.loc)
ReplaceLight(target, user)
to_chat(user, status_string())
/obj/item/lightreplacer/update_icon()
icon_state = "lightreplacer[emagged]"
/obj/item/lightreplacer/proc/status_string()
return "It has [uses] light\s remaining (plus [bulb_shards] fragment\s)."
/obj/item/lightreplacer/proc/Use(mob/user)
playsound(loc, 'sound/machines/click.ogg', 50, TRUE)
AddUses(-1)
return 1
// Negative numbers will subtract
/obj/item/lightreplacer/proc/AddUses(amount = 1)
uses = Clamp(uses + amount, 0, max_uses)
/obj/item/lightreplacer/proc/AddShards(amount = 1, user)
bulb_shards += amount
var/new_bulbs = round(bulb_shards / shards_required)
if(new_bulbs > 0)
AddUses(new_bulbs)
bulb_shards = bulb_shards % shards_required
if(new_bulbs != 0)
to_chat(user, "<span class='notice'>[src] has fabricated a new bulb from the broken glass it has stored. It now has [uses] uses.</span>")
playsound(loc, 'sound/machines/ding.ogg', 50, TRUE)
return new_bulbs
/obj/item/lightreplacer/proc/Charge(var/mob/user)
charge += 1
if(charge > 3)
AddUses(1)
charge = 1
/obj/item/lightreplacer/proc/ReplaceLight(obj/machinery/light/target, mob/living/U)
if(target.status != LIGHT_OK)
if(CanUse(U))
if(!Use(U))
return
to_chat(U, "<span class='notice'>You replace [target.fitting] with [src].</span>")
if(target.status != LIGHT_EMPTY)
AddShards(1, U)
target.status = LIGHT_EMPTY
target.update()
var/obj/item/light/L2 = new target.light_type()
target.status = L2.status
target.switchcount = L2.switchcount
target.rigged = emagged
target.brightness_range = L2.brightness_range
target.brightness_power = L2.brightness_power
target.brightness_color = L2.brightness_color
target.on = target.has_power()
target.update()
qdel(L2)
if(target.on && target.rigged)
target.explode()
return
else
to_chat(U, "[src]'s refill light blinks red.")
return
else
to_chat(U, "<span class='warning'>There is a working [target.fitting] already inserted!</span>")
return
/obj/item/lightreplacer/proc/Emag()
emagged = !emagged
playsound(loc, "sparks", 100, TRUE)
if(emagged)
name = "shortcircuited [initial(name)]"
else
name = initial(name)
update_icon()
/obj/item/lightreplacer/proc/CanUse(mob/living/user)
add_fingerprint(user)
if(uses > 0)
return 1
else
return 0
/obj/item/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)
to_chat(U, "[src]'s refill light blinks red.")
/obj/item/lightreplacer/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
J.put_in_cart(src, user)
J.myreplacer = src
J.update_icon()
/obj/item/lightreplacer/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
return
#undef LIGHT_OK
#undef LIGHT_EMPTY
#undef LIGHT_BROKEN
#undef LIGHT_BURNED
// 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/lightreplacer
name = "light replacer"
desc = "A device to automatically replace lights. Refill with broken or working light bulbs, or sheets of glass."
icon = 'icons/obj/janitor.dmi'
icon_state = "lightreplacer0"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
flags = CONDUCT
slot_flags = SLOT_BELT
origin_tech = "magnets=3;engineering=4"
force = 8
var/emagged = FALSE
var/max_uses = 20
var/uses = 10
// 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/lightreplacer/examine(mob/user)
. = ..()
. += status_string()
/obj/item/lightreplacer/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/G = I
if(uses >= max_uses)
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
else if(G.use(decrement))
AddUses(increment)
to_chat(user, "<span class='notice'>You insert a piece of glass into [src]. You have [uses] light\s remaining.</span>")
return
else
to_chat(user, "<span class='warning'>You need one sheet of glass to replace lights!</span>")
return
if(istype(I, /obj/item/shard))
if(uses >= max_uses)
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
if(!user.unEquip(I))
return
AddUses(round(increment * 0.75))
to_chat(user, "<span class='notice'>You insert a shard of glass into [src]. You have [uses] light\s remaining.</span>")
qdel(I)
return
if(istype(I, /obj/item/light))
var/obj/item/light/L = I
if(L.status == 0) // LIGHT OKAY
if(uses < max_uses)
if(!user.unEquip(L))
return
AddUses(1)
qdel(L)
else
if(!user.unEquip(L))
return
to_chat(user, "<span class='notice'>You insert [L] into [src].</span>")
AddShards(1, user)
qdel(L)
return
if(istype(I, /obj/item/storage))
var/obj/item/storage/S = I
var/found_lightbulbs = FALSE
var/replaced_something = TRUE
for(var/obj/item/IT in S.contents)
if(istype(IT, /obj/item/light))
var/obj/item/light/L = IT
found_lightbulbs = TRUE
if(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, user)
qdel(L)
if(!found_lightbulbs)
to_chat(user, "<span class='warning'>[S] contains no bulbs.</span>")
return
if(!replaced_something && uses == max_uses)
to_chat(user, "<span class='warning'>[src] is full!</span>")
return
to_chat(user, "<span class='notice'>You fill [src] with lights from [S]. " + status_string() + "</span>")
return
return ..()
/obj/item/lightreplacer/emag_act(user as mob)
if(!emagged)
Emag()
/obj/item/lightreplacer/attack_self(mob/user)
for(var/obj/machinery/light/target in user.loc)
ReplaceLight(target, user)
to_chat(user, status_string())
/obj/item/lightreplacer/update_icon()
icon_state = "lightreplacer[emagged]"
/obj/item/lightreplacer/proc/status_string()
return "It has [uses] light\s remaining (plus [bulb_shards] fragment\s)."
/obj/item/lightreplacer/proc/Use(mob/user)
playsound(loc, 'sound/machines/click.ogg', 50, TRUE)
AddUses(-1)
return 1
// Negative numbers will subtract
/obj/item/lightreplacer/proc/AddUses(amount = 1)
uses = Clamp(uses + amount, 0, max_uses)
/obj/item/lightreplacer/proc/AddShards(amount = 1, user)
bulb_shards += amount
var/new_bulbs = round(bulb_shards / shards_required)
if(new_bulbs > 0)
AddUses(new_bulbs)
bulb_shards = bulb_shards % shards_required
if(new_bulbs != 0)
to_chat(user, "<span class='notice'>[src] has fabricated a new bulb from the broken glass it has stored. It now has [uses] uses.</span>")
playsound(loc, 'sound/machines/ding.ogg', 50, TRUE)
return new_bulbs
/obj/item/lightreplacer/proc/Charge(var/mob/user)
charge += 1
if(charge > 3)
AddUses(1)
charge = 1
/obj/item/lightreplacer/proc/ReplaceLight(obj/machinery/light/target, mob/living/U)
if(target.status != LIGHT_OK)
if(CanUse(U))
if(!Use(U))
return
to_chat(U, "<span class='notice'>You replace [target.fitting] with [src].</span>")
if(target.status != LIGHT_EMPTY)
AddShards(1, U)
target.status = LIGHT_EMPTY
target.update()
var/obj/item/light/L2 = new target.light_type()
target.status = L2.status
target.switchcount = L2.switchcount
target.rigged = emagged
target.brightness_range = L2.brightness_range
target.brightness_power = L2.brightness_power
target.brightness_color = L2.brightness_color
target.on = target.has_power()
target.update()
qdel(L2)
if(target.on && target.rigged)
target.explode()
return
else
to_chat(U, "[src]'s refill light blinks red.")
return
else
to_chat(U, "<span class='warning'>There is a working [target.fitting] already inserted!</span>")
return
/obj/item/lightreplacer/proc/Emag()
emagged = !emagged
playsound(loc, "sparks", 100, TRUE)
if(emagged)
name = "shortcircuited [initial(name)]"
else
name = initial(name)
update_icon()
/obj/item/lightreplacer/proc/CanUse(mob/living/user)
add_fingerprint(user)
if(uses > 0)
return 1
else
return 0
/obj/item/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)
to_chat(U, "[src]'s refill light blinks red.")
/obj/item/lightreplacer/proc/janicart_insert(mob/user, obj/structure/janitorialcart/J)
J.put_in_cart(src, user)
J.myreplacer = src
J.update_icon()
/obj/item/lightreplacer/cyborg/janicart_insert(mob/user, obj/structure/janitorialcart/J)
return
#undef LIGHT_OK
#undef LIGHT_EMPTY
#undef LIGHT_BROKEN
#undef LIGHT_BURNED
@@ -1,111 +0,0 @@
#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/multitool
name = "multitool"
desc = "Used for pulsing wires to test which to cut. Not recommended by doctors."
icon = 'icons/obj/device.dmi'
icon_state = "multitool"
flags = CONDUCT
force = 5.0
w_class = WEIGHT_CLASS_SMALL
throwforce = 0
throw_range = 7
throw_speed = 3
materials = list(MAT_METAL=50, MAT_GLASS=20)
origin_tech = "magnets=1;engineering=2"
toolspeed = 1
hitsound = 'sound/weapons/tap.ogg'
var/shows_wire_information = FALSE // shows what a wire does if set to TRUE
var/obj/machinery/buffer // simple machine buffer for device linkage
/obj/item/multitool/proc/IsBufferA(var/typepath)
if(!buffer)
return 0
return istype(buffer,typepath)
// Syndicate device disguised as a multitool; it will turn red when an AI camera is nearby.
/obj/item/multitool/Destroy()
buffer = null
return ..()
/obj/item/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/multitool/ai_detect/New()
..()
START_PROCESSING(SSobj, src)
/obj/item/multitool/ai_detect/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/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/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/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
shows_wire_information = TRUE
/obj/item/multitool/ai_detect/admin/multitool_detect()
var/turf/our_turf = get_turf(src)
for(var/mob/J in urange(rangewarning,our_turf))
if(check_rights(R_ADMIN, 0, J))
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/multitool/cyborg
name = "multitool"
desc = "Optimised and stripped-down version of a regular multitool."
toolspeed = 0.5
/obj/item/multitool/abductor
name = "alien multitool"
desc = "An omni-technological interface."
icon = 'icons/obj/abductor.dmi'
icon_state = "multitool"
toolspeed = 0.1
origin_tech = "magnets=5;engineering=5;abductor=3"
shows_wire_information = TRUE
+340 -340
View File
@@ -1,340 +1,340 @@
/obj/item/paicard
name = "personal AI device"
icon = 'icons/obj/aicards.dmi'
icon_state = "pai"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
origin_tech = "programming=2"
var/request_cooldown = 5 // five seconds
var/last_request
var/obj/item/radio/radio
var/looking_for_personality = 0
var/mob/living/silicon/pai/pai
var/list/faction = list("neutral") // The factions the pAI will inherit from the card
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
/obj/item/paicard/syndicate
name = "syndicate personal AI device"
faction = list("syndicate")
/obj/item/paicard/relaymove(var/mob/user, var/direction)
if(user.stat || user.stunned)
return
var/obj/item/rig/rig = get_rig()
if(istype(rig))
rig.forced_move(direction, user)
/obj/item/paicard/New()
..()
overlays += "pai-off"
/obj/item/paicard/Destroy()
if(pai)
pai.ghostize()
QDEL_NULL(pai)
QDEL_NULL(radio)
return ..()
/obj/item/paicard/attack_self(mob/user)
if(!in_range(src, user))
return
user.set_machine(src)
var/dat = {"
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style>
body {
margin-top:5px;
font-family:Verdana;
color:white;
font-size:13px;
background-image:url('uiBackground.png');
background-repeat:repeat-x;
background-color:#272727;
background-position:center top;
}
table {
font-size:13px;
margin-left:-2px;
}
table.request {
border-collapse:collapse;
}
table.desc {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
table.download {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
tr.d0 td, tr.d0 th {
background-color: #506070;
color: white;
}
tr.d1 td, tr.d1 th {
background-color: #708090;
color: white;
}
tr.d2 td {
background-color: #00FF00;
color: white;
text-align:center;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
td.button_red {
border: 1px solid #161616;
background-color: #B04040;
text-align: center;
}
td.download {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
th {
text-align:left;
width:125px;
}
td.request {
width:140px;
vertical-align:top;
}
td.radio {
width:90px;
vertical-align:top;
}
td.request {
vertical-align:top;
}
a {
color:#4477E0;
}
a.button {
color:white;
text-decoration: none;
}
h2 {
font-size:15px;
}
</style>
</head>
<body>
"}
if(pai)
dat += {"
<b><font size='3px'>Personal AI Device</font></b><br><br>
<table class="request">
<tr>
<td class="request">Installed Personality:</td>
<td>[pai.name]</td>
</tr>
<tr>
<td class="request">Prime directive:</td>
<td>[pai.pai_law0]</td>
</tr>
<tr>
<td class="request">Additional directives:</td>
<td>[pai.pai_laws]</td>
</tr>
</table>
<br>
"}
dat += {"
<table>
<td class="button">
<a href='byond://?src=[UID()];setlaws=1' class='button'>Configure Directives</a>
</td>
</table>
"}
if(pai && (!pai.master_dna || !pai.master))
dat += {"
<table>
<td class="button">
<a href='byond://?src=[UID()];setdna=1' class='button'>Imprint Master DNA</a>
</td>
</table>
"}
dat += "<br>"
if(radio)
dat += "<b>Radio Uplink</b>"
dat += {"
<table class="request">
<tr>
<td class="radio">Transmit:</td>
<td><a href='byond://?src=[UID()];wires=4'>[radio.broadcasting ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
</td>
</tr>
<tr>
<td class="radio">Receive:</td>
<td><a href='byond://?src=[UID()];wires=2'>[radio.listening ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
</td>
</tr>
</table>
<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 += {"
<table>
<td class="button_red"><a href='byond://?src=[UID()];wipe=1' class='button'>Wipe current pAI personality</a>
</td>
</table>
"}
else
if(looking_for_personality)
dat += {"
<b><font size='3px'>pAI Request Module</font></b><br><br>
<p>Requesting AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.</p>
Searching for personalities, please wait...<br><br>
<table>
<tr>
<td class="button">
<a href='byond://?src=[UID()];request=1' class="button">Refresh available personalities</a>
</td>
</tr>
</table><br>
"}
else
dat += {"
<b><font size='3px'>pAI Request Module</font></b><br><br>
<p>No personality is installed.</p>
<table>
<tr>
<td class="button"><a href='byond://?src=[UID()];request=1' class="button">Request personality</a>
</td>
</tr>
</table>
<br>
<p>Each time this button is pressed, a request will be sent out to any available personalities. Check back often give plenty of time for personalities to respond. This process could take anywhere from 15 seconds to several minutes, depending on the available personalities' timeliness.</p>
"}
user << browse(dat, "window=paicard")
onclose(user, "paicard")
return
/obj/item/paicard/Topic(href, href_list)
var/mob/U = usr
if(!usr || usr.stat)
return
if(pai)
if(!in_range(src, U))
U << browse(null, "window=paicard")
usr.unset_machine()
return
if(href_list["setdna"])
if(pai.master_dna)
return
var/mob/M = usr
if(!istype(M, /mob/living/carbon))
to_chat(usr, "<font color=blue>You don't have any DNA, or your DNA is incompatible with this device.</font>")
else
var/datum/dna/dna = usr.dna
pai.master = M.real_name
pai.master_dna = dna.unique_enzymes
to_chat(pai, "<font color = red><h3>You have been bound to a new master.</h3></font>")
if(href_list["request"])
var/delta = (world.time / 10) - last_request
if(request_cooldown > delta)
var/cooldown_time = round(request_cooldown - ((world.time / 10) - last_request), 1)
to_chat(usr, "<span class='warning'>The request system is currently offline. Please wait another [cooldown_time] seconds.</span>")
return
last_request = world.time / 10
looking_for_personality = 1
paiController.findPAI(src, usr)
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")
for(var/mob/M in src)
to_chat(M, "<font color = #ff0000><h2>You feel yourself slipping away from reality.</h2></font>")
to_chat(M, "<font color = #ff4d4d><h3>Byte by byte you lose your sense of self.</h3></font>")
to_chat(M, "<font color = #ff8787><h4>Your mental faculties leave you.</h4></font>")
to_chat(M, "<font color = #ffc4c4><h5>oblivion... </h5></font>")
var/mob/living/silicon/pai/P = M
if(istype(P))
if(P.resting || P.canmove)
P.close_up()
M.death(0, 1)
removePersonality()
if(href_list["wires"])
var/t1 = text2num(href_list["wires"])
switch(t1)
if(4)
radio.ToggleBroadcast()
if(2)
radio.ToggleReception()
if(href_list["setlaws"])
var/newlaws = sanitize(copytext(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.pai_laws) as message,1,MAX_MESSAGE_LEN))
if(newlaws)
pai.pai_laws = newlaws
to_chat(pai, "Your supplemental directives have been updated. Your new directives are:")
to_chat(pai, "Prime Directive: <br>[pai.pai_law0]")
to_chat(pai, "Supplemental Directives: <br>[pai.pai_laws]")
attack_self(usr)
// WIRE_SIGNAL = 1
// WIRE_RECEIVE = 2
// WIRE_TRANSMIT = 4
/obj/item/paicard/proc/setPersonality(mob/living/silicon/pai/personality)
pai = personality
overlays += "pai-happy"
/obj/item/paicard/proc/removePersonality()
pai = null
overlays.Cut()
overlays += "pai-off"
/obj/item/paicard
var/current_emotion = 1
/obj/item/paicard/proc/setEmotion(var/emotion)
if(pai)
overlays.Cut()
switch(emotion)
if(1) overlays += "pai-happy"
if(2) overlays += "pai-cat"
if(3) overlays += "pai-extremely-happy"
if(4) overlays += "pai-face"
if(5) overlays += "pai-laugh"
if(6) overlays += "pai-off"
if(7) overlays += "pai-sad"
if(8) overlays += "pai-angry"
if(9) overlays += "pai-what"
current_emotion = emotion
/obj/item/paicard/proc/alertUpdate()
var/turf/T = get_turf_or_move(loc)
for(var/mob/M in viewers(T))
M.show_message("<span class='notice'>[src] flashes a message across its screen, \"Additional personalities available for download.\"</span>", 3, "<span class='notice'>[src] bleeps electronically.</span>", 2)
/obj/item/paicard/emp_act(severity)
for(var/mob/M in src)
M.emp_act(severity)
..()
/obj/item/paicard/extinguish_light()
pai.extinguish_light()
set_light(0)
/obj/item/paicard
name = "personal AI device"
icon = 'icons/obj/aicards.dmi'
icon_state = "pai"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
origin_tech = "programming=2"
var/request_cooldown = 5 // five seconds
var/last_request
var/obj/item/radio/radio
var/looking_for_personality = 0
var/mob/living/silicon/pai/pai
var/list/faction = list("neutral") // The factions the pAI will inherit from the card
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
/obj/item/paicard/syndicate
name = "syndicate personal AI device"
faction = list("syndicate")
/obj/item/paicard/relaymove(var/mob/user, var/direction)
if(user.stat || user.stunned)
return
var/obj/item/rig/rig = get_rig()
if(istype(rig))
rig.forced_move(direction, user)
/obj/item/paicard/New()
..()
overlays += "pai-off"
/obj/item/paicard/Destroy()
if(pai)
pai.ghostize()
QDEL_NULL(pai)
QDEL_NULL(radio)
return ..()
/obj/item/paicard/attack_self(mob/user)
if(!in_range(src, user))
return
user.set_machine(src)
var/dat = {"
<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style>
body {
margin-top:5px;
font-family:Verdana;
color:white;
font-size:13px;
background-image:url('uiBackground.png');
background-repeat:repeat-x;
background-color:#272727;
background-position:center top;
}
table {
font-size:13px;
margin-left:-2px;
}
table.request {
border-collapse:collapse;
}
table.desc {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
table.download {
border-collapse:collapse;
font-size:13px;
border: 1px solid #161616;
width:100%;
}
tr.d0 td, tr.d0 th {
background-color: #506070;
color: white;
}
tr.d1 td, tr.d1 th {
background-color: #708090;
color: white;
}
tr.d2 td {
background-color: #00FF00;
color: white;
text-align:center;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
}
td.button {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
td.button_red {
border: 1px solid #161616;
background-color: #B04040;
text-align: center;
}
td.download {
border: 1px solid #161616;
background-color: #40628a;
text-align: center;
}
th {
text-align:left;
width:125px;
}
td.request {
width:140px;
vertical-align:top;
}
td.radio {
width:90px;
vertical-align:top;
}
td.request {
vertical-align:top;
}
a {
color:#4477E0;
}
a.button {
color:white;
text-decoration: none;
}
h2 {
font-size:15px;
}
</style>
</head>
<body>
"}
if(pai)
dat += {"
<b><font size='3px'>Personal AI Device</font></b><br><br>
<table class="request">
<tr>
<td class="request">Installed Personality:</td>
<td>[pai.name]</td>
</tr>
<tr>
<td class="request">Prime directive:</td>
<td>[pai.pai_law0]</td>
</tr>
<tr>
<td class="request">Additional directives:</td>
<td>[pai.pai_laws]</td>
</tr>
</table>
<br>
"}
dat += {"
<table>
<td class="button">
<a href='byond://?src=[UID()];setlaws=1' class='button'>Configure Directives</a>
</td>
</table>
"}
if(pai && (!pai.master_dna || !pai.master))
dat += {"
<table>
<td class="button">
<a href='byond://?src=[UID()];setdna=1' class='button'>Imprint Master DNA</a>
</td>
</table>
"}
dat += "<br>"
if(radio)
dat += "<b>Radio Uplink</b>"
dat += {"
<table class="request">
<tr>
<td class="radio">Transmit:</td>
<td><a href='byond://?src=[UID()];wires=4'>[radio.broadcasting ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
</td>
</tr>
<tr>
<td class="radio">Receive:</td>
<td><a href='byond://?src=[UID()];wires=2'>[radio.listening ? "<font color=#55FF55>En" : "<font color=#FF5555>Dis" ]abled</font></a>
</td>
</tr>
</table>
<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 += {"
<table>
<td class="button_red"><a href='byond://?src=[UID()];wipe=1' class='button'>Wipe current pAI personality</a>
</td>
</table>
"}
else
if(looking_for_personality)
dat += {"
<b><font size='3px'>pAI Request Module</font></b><br><br>
<p>Requesting AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.</p>
Searching for personalities, please wait...<br><br>
<table>
<tr>
<td class="button">
<a href='byond://?src=[UID()];request=1' class="button">Refresh available personalities</a>
</td>
</tr>
</table><br>
"}
else
dat += {"
<b><font size='3px'>pAI Request Module</font></b><br><br>
<p>No personality is installed.</p>
<table>
<tr>
<td class="button"><a href='byond://?src=[UID()];request=1' class="button">Request personality</a>
</td>
</tr>
</table>
<br>
<p>Each time this button is pressed, a request will be sent out to any available personalities. Check back often give plenty of time for personalities to respond. This process could take anywhere from 15 seconds to several minutes, depending on the available personalities' timeliness.</p>
"}
user << browse(dat, "window=paicard")
onclose(user, "paicard")
return
/obj/item/paicard/Topic(href, href_list)
var/mob/U = usr
if(!usr || usr.stat)
return
if(pai)
if(!in_range(src, U))
U << browse(null, "window=paicard")
usr.unset_machine()
return
if(href_list["setdna"])
if(pai.master_dna)
return
var/mob/M = usr
if(!istype(M, /mob/living/carbon))
to_chat(usr, "<font color=blue>You don't have any DNA, or your DNA is incompatible with this device.</font>")
else
var/datum/dna/dna = usr.dna
pai.master = M.real_name
pai.master_dna = dna.unique_enzymes
to_chat(pai, "<font color = red><h3>You have been bound to a new master.</h3></font>")
if(href_list["request"])
var/delta = (world.time / 10) - last_request
if(request_cooldown > delta)
var/cooldown_time = round(request_cooldown - ((world.time / 10) - last_request), 1)
to_chat(usr, "<span class='warning'>The request system is currently offline. Please wait another [cooldown_time] seconds.</span>")
return
last_request = world.time / 10
looking_for_personality = 1
paiController.findPAI(src, usr)
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")
for(var/mob/M in src)
to_chat(M, "<font color = #ff0000><h2>You feel yourself slipping away from reality.</h2></font>")
to_chat(M, "<font color = #ff4d4d><h3>Byte by byte you lose your sense of self.</h3></font>")
to_chat(M, "<font color = #ff8787><h4>Your mental faculties leave you.</h4></font>")
to_chat(M, "<font color = #ffc4c4><h5>oblivion... </h5></font>")
var/mob/living/silicon/pai/P = M
if(istype(P))
if(P.resting || P.canmove)
P.close_up()
M.death(0, 1)
removePersonality()
if(href_list["wires"])
var/t1 = text2num(href_list["wires"])
switch(t1)
if(4)
radio.ToggleBroadcast()
if(2)
radio.ToggleReception()
if(href_list["setlaws"])
var/newlaws = sanitize(copytext(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.pai_laws) as message,1,MAX_MESSAGE_LEN))
if(newlaws)
pai.pai_laws = newlaws
to_chat(pai, "Your supplemental directives have been updated. Your new directives are:")
to_chat(pai, "Prime Directive: <br>[pai.pai_law0]")
to_chat(pai, "Supplemental Directives: <br>[pai.pai_laws]")
attack_self(usr)
// WIRE_SIGNAL = 1
// WIRE_RECEIVE = 2
// WIRE_TRANSMIT = 4
/obj/item/paicard/proc/setPersonality(mob/living/silicon/pai/personality)
pai = personality
overlays += "pai-happy"
/obj/item/paicard/proc/removePersonality()
pai = null
overlays.Cut()
overlays += "pai-off"
/obj/item/paicard
var/current_emotion = 1
/obj/item/paicard/proc/setEmotion(var/emotion)
if(pai)
overlays.Cut()
switch(emotion)
if(1) overlays += "pai-happy"
if(2) overlays += "pai-cat"
if(3) overlays += "pai-extremely-happy"
if(4) overlays += "pai-face"
if(5) overlays += "pai-laugh"
if(6) overlays += "pai-off"
if(7) overlays += "pai-sad"
if(8) overlays += "pai-angry"
if(9) overlays += "pai-what"
current_emotion = emotion
/obj/item/paicard/proc/alertUpdate()
var/turf/T = get_turf_or_move(loc)
for(var/mob/M in viewers(T))
M.show_message("<span class='notice'>[src] flashes a message across its screen, \"Additional personalities available for download.\"</span>", 3, "<span class='notice'>[src] bleeps electronically.</span>", 2)
/obj/item/paicard/emp_act(severity)
for(var/mob/M in src)
M.emp_act(severity)
..()
/obj/item/paicard/extinguish_light()
pai.extinguish_light()
set_light(0)
@@ -102,4 +102,4 @@
/obj/item/pizza_bomb/autoarm
timer_set = 1
timer = 30 // 3 seconds
timer = 30 // 3 seconds
+153 -153
View File
@@ -1,153 +1,153 @@
#define DISCONNECTED 0
#define CLAMPED_OFF 1
#define OPERATING 2
// Powersink - used to drain station power
/obj/item/powersink
name = "power sink"
desc = "A nulling power sink which drains energy from electrical systems."
icon = 'icons/obj/device.dmi'
icon_state = "powersink0"
item_state = "electronic"
w_class = WEIGHT_CLASS_BULKY
flags = CONDUCT
throwforce = 5
throw_speed = 1
throw_range = 2
materials = list(MAT_METAL=750)
origin_tech = "powerstorage=5;syndicate=5"
var/drain_rate = 2000000 // amount of power to drain per tick
var/power_drained = 0 // has drained this much power
var/max_power = 6e8 // maximum power that can be drained before exploding
var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
var/admins_warned = FALSE // stop spam, only warn the admins once that we are about to boom
var/obj/structure/cable/attached // the attached cable
/obj/item/powersink/Destroy()
STOP_PROCESSING(SSobj, src)
attached = null
return ..()
/obj/item/powersink/update_icon()
icon_state = "powersink[mode == OPERATING]"
/obj/item/powersink/proc/set_mode(value)
if(value == mode)
return
switch(value)
if(DISCONNECTED)
attached = null
if(mode == OPERATING)
STOP_PROCESSING(SSobj, src)
anchored = FALSE
density = FALSE
if(CLAMPED_OFF)
if(!attached)
return
if(mode == OPERATING)
STOP_PROCESSING(SSobj, src)
anchored = TRUE
density = TRUE
if(OPERATING)
if(!attached)
return
START_PROCESSING(SSobj, src)
anchored = TRUE
density = TRUE
mode = value
update_icon()
set_light(0)
/obj/item/powersink/attackby(obj/item/I, mob/user)
if(isscrewdriver(I))
if(mode == DISCONNECTED)
var/turf/T = loc
if(isturf(T) && !T.intact)
attached = locate() in T
if(!attached)
to_chat(user, "No exposed cable here to attach to.")
return
else
set_mode(CLAMPED_OFF)
visible_message("<span class='notice'>[user] attaches [src] to the cable!</span>")
message_admins("Power sink activated by [key_name_admin(user)] 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])")
else
to_chat(user, "Device must be placed over an exposed cable to attach to it.")
else
set_mode(DISCONNECTED)
src.visible_message("<span class='notice'>[user] detaches [src] from the cable!</span>")
else
return ..()
/obj/item/powersink/attack_ai()
return
/obj/item/powersink/attack_hand(var/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 [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(src)]")
log_game("Power sink activated by [key_name(user)] at [AREACOORD(src)]")
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/powersink/process()
if(!attached)
set_mode(DISCONNECTED)
return
var/datum/powernet/PN = attached.powernet
if(PN)
set_light(5)
// found a powernet, so drain up to max power from it
var/drained = min (drain_rate, attached.newavail())
attached.add_delayedload(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(drained >= drain_rate)
break
if(power_drained > max_power * 0.98)
if (!admins_warned)
admins_warned = TRUE
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)
#undef DISCONNECTED
#undef CLAMPED_OFF
#undef OPERATING
#define DISCONNECTED 0
#define CLAMPED_OFF 1
#define OPERATING 2
// Powersink - used to drain station power
/obj/item/powersink
name = "power sink"
desc = "A nulling power sink which drains energy from electrical systems."
icon = 'icons/obj/device.dmi'
icon_state = "powersink0"
item_state = "electronic"
w_class = WEIGHT_CLASS_BULKY
flags = CONDUCT
throwforce = 5
throw_speed = 1
throw_range = 2
materials = list(MAT_METAL=750)
origin_tech = "powerstorage=5;syndicate=5"
var/drain_rate = 2000000 // amount of power to drain per tick
var/power_drained = 0 // has drained this much power
var/max_power = 6e8 // maximum power that can be drained before exploding
var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
var/admins_warned = FALSE // stop spam, only warn the admins once that we are about to boom
var/obj/structure/cable/attached // the attached cable
/obj/item/powersink/Destroy()
STOP_PROCESSING(SSobj, src)
attached = null
return ..()
/obj/item/powersink/update_icon()
icon_state = "powersink[mode == OPERATING]"
/obj/item/powersink/proc/set_mode(value)
if(value == mode)
return
switch(value)
if(DISCONNECTED)
attached = null
if(mode == OPERATING)
STOP_PROCESSING(SSobj, src)
anchored = FALSE
density = FALSE
if(CLAMPED_OFF)
if(!attached)
return
if(mode == OPERATING)
STOP_PROCESSING(SSobj, src)
anchored = TRUE
density = TRUE
if(OPERATING)
if(!attached)
return
START_PROCESSING(SSobj, src)
anchored = TRUE
density = TRUE
mode = value
update_icon()
set_light(0)
/obj/item/powersink/screwdriver_act(mob/user, obj/item/I)
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
if(mode == DISCONNECTED)
var/turf/T = loc
if(isturf(T) && !T.intact)
attached = locate() in T
if(!attached)
to_chat(user, "No exposed cable here to attach to.")
return
else
set_mode(CLAMPED_OFF)
visible_message("<span class='notice'>[user] attaches [src] to the cable!</span>")
message_admins("Power sink activated by [key_name_admin(user)] 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])")
else
to_chat(user, "Device must be placed over an exposed cable to attach to it.")
else
set_mode(DISCONNECTED)
src.visible_message("<span class='notice'>[user] detaches [src] from the cable!</span>")
/obj/item/powersink/attack_ai()
return
/obj/item/powersink/attack_hand(var/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 [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(src)]")
log_game("Power sink activated by [key_name(user)] at [AREACOORD(src)]")
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/powersink/process()
if(!attached)
set_mode(DISCONNECTED)
return
var/datum/powernet/PN = attached.powernet
if(PN)
set_light(5)
// found a powernet, so drain up to max power from it
var/drained = min (drain_rate, attached.newavail())
attached.add_delayedload(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(drained >= drain_rate)
break
if(power_drained > max_power * 0.98)
if (!admins_warned)
admins_warned = TRUE
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)
#undef DISCONNECTED
#undef CLAMPED_OFF
#undef OPERATING
+106 -106
View File
@@ -1,106 +1,106 @@
/obj/item/radio/beacon
name = "Tracking Beacon"
desc = "A beacon used by a teleporter."
icon_state = "beacon"
item_state = "signaler"
var/code = "Beacon"
origin_tech = "bluespace=1"
var/emagged = 0
var/syndicate = 0
var/area_bypass = FALSE
var/cc_beacon = FALSE //set if allowed to teleport to even if on zlevel2
/obj/item/radio/beacon/New()
..()
code = "[code] ([GLOB.beacons.len + 1])"
GLOB.beacons += src
/obj/item/radio/beacon/Destroy()
GLOB.beacons -= src
return ..()
/obj/item/radio/beacon/emag_act(user as mob)
if(!emagged)
emagged = 1
syndicate = 1
to_chat(user, "<span class='notice'>The This beacon now only be locked on to by emagged teleporters!</span>")
/obj/item/radio/beacon/hear_talk()
return
/obj/item/radio/beacon/send_hear()
return null
/obj/item/radio/beacon/verb/alter_signal(t as text)
set name = "Alter Beacon's Signal"
set category = "Object"
set src in usr
if(usr.stat || usr.restrained())
return
code = t
if(isnull(code))
code = initial(code)
src.add_fingerprint(usr)
return
/obj/item/radio/beacon/bacon //Probably a better way of doing this, I'm lazy.
/obj/item/radio/beacon/bacon/proc/digest_delay()
QDEL_IN(src, 600)
// SINGULO BEACON SPAWNER
/obj/item/radio/beacon/syndicate
name = "suspicious beacon"
desc = "A label on it reads: <i>Activate to have a singularity beacon teleported to your location</i>."
origin_tech = "bluespace=6;syndicate=5"
syndicate = TRUE
var/obj/machinery/computer/syndicate_depot/teleporter/mycomputer
/obj/item/radio/beacon/syndicate/Destroy()
if(mycomputer)
mycomputer.mybeacon = null
return ..()
/obj/item/radio/beacon/syndicate/attack_self(mob/user)
if(user)
to_chat(user, "<span class='notice'>Locked In</span>")
new /obj/machinery/power/singularity_beacon/syndicate( user.loc )
playsound(src, 'sound/effects/pop.ogg', 100, 1, 1)
qdel(src)
return
/obj/item/radio/beacon/syndicate/bomb
name = "suspicious beacon"
desc = "A label on it reads: <i>Warning: Activating this device will send a high-ordinance explosive to your location</i>."
origin_tech = "bluespace=5;syndicate=5"
/obj/item/radio/beacon/syndicate/bomb/attack_self(mob/user)
if(user)
to_chat(user, "<span class='notice'>Locked In</span>")
new /obj/machinery/syndicatebomb( user.loc )
playsound(src, 'sound/effects/pop.ogg', 100, 1, 1)
qdel(src)
return
/obj/item/radio/beacon/engine
desc = "A label on it reads: <i>Warning: This device is used for transportation of high-density objects used for high-yield power generation. Stay away!</i>."
anchored = 1 //Let's not move these around. Some folk might get the idea to use these for assassinations
var/list/enginetype = list()
/obj/item/radio/beacon/engine/Initialize()
LAZYADD(GLOB.engine_beacon_list, src)
/obj/item/radio/beacon/engine/tesling
name = "Engine Beacon for Tesla and Singularity"
enginetype = list(ENGTYPE_TESLA, ENGTYPE_SING)
/obj/item/radio/beacon/engine/tesla
name = "Engine Beacon for Tesla"
enginetype = list(ENGTYPE_TESLA)
/obj/item/radio/beacon/engine/sing
name = "Engine Beacon for Singularity"
enginetype = list(ENGTYPE_SING)
/obj/item/radio/beacon
name = "Tracking Beacon"
desc = "A beacon used by a teleporter."
icon_state = "beacon"
item_state = "signaler"
var/code = "Beacon"
origin_tech = "bluespace=1"
var/emagged = 0
var/syndicate = 0
var/area_bypass = FALSE
var/cc_beacon = FALSE //set if allowed to teleport to even if on zlevel2
/obj/item/radio/beacon/New()
..()
code = "[code] ([GLOB.beacons.len + 1])"
GLOB.beacons += src
/obj/item/radio/beacon/Destroy()
GLOB.beacons -= src
return ..()
/obj/item/radio/beacon/emag_act(user as mob)
if(!emagged)
emagged = 1
syndicate = 1
to_chat(user, "<span class='notice'>The This beacon now only be locked on to by emagged teleporters!</span>")
/obj/item/radio/beacon/hear_talk()
return
/obj/item/radio/beacon/send_hear()
return null
/obj/item/radio/beacon/verb/alter_signal(t as text)
set name = "Alter Beacon's Signal"
set category = "Object"
set src in usr
if(usr.stat || usr.restrained())
return
code = t
if(isnull(code))
code = initial(code)
src.add_fingerprint(usr)
return
/obj/item/radio/beacon/bacon //Probably a better way of doing this, I'm lazy.
/obj/item/radio/beacon/bacon/proc/digest_delay()
QDEL_IN(src, 600)
// SINGULO BEACON SPAWNER
/obj/item/radio/beacon/syndicate
name = "suspicious beacon"
desc = "A label on it reads: <i>Activate to have a singularity beacon teleported to your location</i>."
origin_tech = "bluespace=6;syndicate=5"
syndicate = TRUE
var/obj/machinery/computer/syndicate_depot/teleporter/mycomputer
/obj/item/radio/beacon/syndicate/Destroy()
if(mycomputer)
mycomputer.mybeacon = null
return ..()
/obj/item/radio/beacon/syndicate/attack_self(mob/user)
if(user)
to_chat(user, "<span class='notice'>Locked In</span>")
new /obj/machinery/power/singularity_beacon/syndicate( user.loc )
playsound(src, 'sound/effects/pop.ogg', 100, 1, 1)
qdel(src)
return
/obj/item/radio/beacon/syndicate/bomb
name = "suspicious beacon"
desc = "A label on it reads: <i>Warning: Activating this device will send a high-ordinance explosive to your location</i>."
origin_tech = "bluespace=5;syndicate=5"
/obj/item/radio/beacon/syndicate/bomb/attack_self(mob/user)
if(user)
to_chat(user, "<span class='notice'>Locked In</span>")
new /obj/machinery/syndicatebomb( user.loc )
playsound(src, 'sound/effects/pop.ogg', 100, 1, 1)
qdel(src)
return
/obj/item/radio/beacon/engine
desc = "A label on it reads: <i>Warning: This device is used for transportation of high-density objects used for high-yield power generation. Stay away!</i>."
anchored = 1 //Let's not move these around. Some folk might get the idea to use these for assassinations
var/list/enginetype = list()
/obj/item/radio/beacon/engine/Initialize()
LAZYADD(GLOB.engine_beacon_list, src)
/obj/item/radio/beacon/engine/tesling
name = "Engine Beacon for Tesla and Singularity"
enginetype = list(ENGTYPE_TESLA, ENGTYPE_SING)
/obj/item/radio/beacon/engine/tesla
name = "Engine Beacon for Tesla"
enginetype = list(ENGTYPE_TESLA)
/obj/item/radio/beacon/engine/sing
name = "Engine Beacon for Singularity"
enginetype = list(ENGTYPE_SING)
@@ -1,113 +1,113 @@
/obj/item/radio/electropack
name = "electropack"
desc = "Dance my monkeys! DANCE!!!"
icon_state = "electropack0"
item_state = "electropack"
frequency = AIRLOCK_FREQ
flags = CONDUCT
slot_flags = SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
materials = list(MAT_METAL=10000, MAT_GLASS=2500)
var/code = 2
is_special = 1
/obj/item/radio/electropack/attack_hand(mob/user as mob)
if(src == user.back)
to_chat(user, "<span class='notice'>You need help taking this off!</span>")
return 0
. = ..()
/obj/item/radio/electropack/Destroy()
if(istype(src.loc, /obj/item/assembly/shock_kit))
var/obj/item/assembly/shock_kit/S = src.loc
if(S.part1 == src)
S.part1 = null
else if(S.part2 == src)
S.part2 = null
master = null
return ..()
/obj/item/radio/electropack/attackby(obj/item/W as obj, mob/user as mob, params)
..()
if(istype(W, /obj/item/clothing/head/helmet))
if(!b_stat)
to_chat(user, "<span class='notice'>[src] is not ready to be attached!</span>")
return
var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit( user )
A.icon = 'icons/obj/assemblies.dmi'
if(!user.unEquip(W))
to_chat(user, "<span class='notice'>\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
/obj/item/radio/electropack/Topic(href, href_list)
if(..())
return 1
if(href_list["freq"])
var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"]))
set_frequency(new_frequency)
else if(href_list["code"])
code += text2num(href_list["code"])
code = round(code)
code = Clamp(code, 1, 100)
else if(href_list["power"])
on = !on
add_fingerprint(usr)
/obj/item/radio/electropack/receive_signal(datum/signal/signal)
if(!signal || signal.encryption != code)
return
if(ismob(loc) && on)
var/mob/M = loc
var/turf/T = M.loc
if(istype(T, /turf))
if(!M.moved_recently && M.last_move)
M.moved_recently = 1
step(M, M.last_move)
sleep(50)
if(M)
M.moved_recently = 0
to_chat(M, "<span class='danger'>You feel a sharp shock!</span>")
do_sparks(3, 1, M)
M.Weaken(5)
if(master)
master.receive_signal()
return
/obj/item/radio/electropack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "radio_electro.tmpl", "[name]", 400, 500)
ui.open()
ui.set_auto_update(1)
/obj/item/radio/electropack/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
var/data[0]
data["power"] = on
data["freq"] = format_frequency(frequency)
data["code"] = code
return data
/obj/item/radio/electropack
name = "electropack"
desc = "Dance my monkeys! DANCE!!!"
icon_state = "electropack0"
item_state = "electropack"
frequency = AIRLOCK_FREQ
flags = CONDUCT
slot_flags = SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
materials = list(MAT_METAL=10000, MAT_GLASS=2500)
var/code = 2
is_special = 1
/obj/item/radio/electropack/attack_hand(mob/user as mob)
if(src == user.back)
to_chat(user, "<span class='notice'>You need help taking this off!</span>")
return 0
. = ..()
/obj/item/radio/electropack/Destroy()
if(istype(src.loc, /obj/item/assembly/shock_kit))
var/obj/item/assembly/shock_kit/S = src.loc
if(S.part1 == src)
S.part1 = null
else if(S.part2 == src)
S.part2 = null
master = null
return ..()
/obj/item/radio/electropack/attackby(obj/item/W as obj, mob/user as mob, params)
..()
if(istype(W, /obj/item/clothing/head/helmet))
if(!b_stat)
to_chat(user, "<span class='notice'>[src] is not ready to be attached!</span>")
return
var/obj/item/assembly/shock_kit/A = new /obj/item/assembly/shock_kit( user )
A.icon = 'icons/obj/assemblies.dmi'
if(!user.unEquip(W))
to_chat(user, "<span class='notice'>\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
/obj/item/radio/electropack/Topic(href, href_list)
if(..())
return 1
if(href_list["freq"])
var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"]))
set_frequency(new_frequency)
else if(href_list["code"])
code += text2num(href_list["code"])
code = round(code)
code = Clamp(code, 1, 100)
else if(href_list["power"])
on = !on
add_fingerprint(usr)
/obj/item/radio/electropack/receive_signal(datum/signal/signal)
if(!signal || signal.encryption != code)
return
if(ismob(loc) && on)
var/mob/M = loc
var/turf/T = M.loc
if(istype(T, /turf))
if(!M.moved_recently && M.last_move)
M.moved_recently = 1
step(M, M.last_move)
sleep(50)
if(M)
M.moved_recently = 0
to_chat(M, "<span class='danger'>You feel a sharp shock!</span>")
do_sparks(3, 1, M)
M.Weaken(5)
if(master)
master.receive_signal()
return
/obj/item/radio/electropack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "radio_electro.tmpl", "[name]", 400, 500)
ui.open()
ui.set_auto_update(1)
/obj/item/radio/electropack/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
var/data[0]
data["power"] = on
data["freq"] = format_frequency(frequency)
data["code"] = code
return data
+426 -425
View File
@@ -1,425 +1,426 @@
/obj/item/radio/headset
name = "radio headset"
desc = "An updated, modular intercom that fits over the head. Takes encryption keys."
var/radio_desc = ""
icon_state = "headset"
item_state = "headset"
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/ears.dmi',
"Vox Armalis" = 'icons/mob/species/armalis/ears.dmi'
) //We read you loud and skree-er.
materials = list(MAT_METAL=75)
subspace_transmission = TRUE
canhear_range = 0 // can't hear headsets from very far away
slot_flags = SLOT_EARS
var/translate_binary = FALSE
var/translate_hive = FALSE
var/obj/item/encryptionkey/keyslot1 = null
var/obj/item/encryptionkey/keyslot2 = null
var/ks1type = null
var/ks2type = null
dog_fashion = null
/obj/item/radio/headset/New()
..()
internal_channels.Cut()
/obj/item/radio/headset/Initialize()
..()
if(ks1type)
keyslot1 = new ks1type(src)
if(keyslot1.syndie)
syndiekey = keyslot1
if(ks2type)
keyslot2 = new ks2type(src)
if(keyslot2.syndie)
syndiekey = keyslot2
recalculateChannels(TRUE)
/obj/item/radio/headset/Destroy()
QDEL_NULL(keyslot1)
QDEL_NULL(keyslot2)
return ..()
/obj/item/radio/headset/list_channels(var/mob/user)
return list_secure_channels()
/obj/item/radio/headset/examine(mob/user)
. = ..()
if(in_range(src, user) && radio_desc)
. += "The following channels are available:"
. += radio_desc
/obj/item/radio/headset/handle_message_mode(mob/living/M as mob, list/message_pieces, channel)
if(channel == "special")
if(translate_binary)
var/datum/language/binary = GLOB.all_languages["Robot Talk"]
binary.broadcast(M, strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
if(translate_hive)
var/datum/language/hivemind = GLOB.all_languages["Hivemind"]
hivemind.broadcast(M, strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
return RADIO_CONNECTION_FAIL
return ..()
/obj/item/radio/headset/is_listening()
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(H.l_ear == src || H.r_ear == src)
return ..()
else if(isanimal(loc) || isAI(loc))
return ..()
return FALSE
/obj/item/radio/headset/alt
name = "bowman headset"
desc = "An updated, modular intercom that fits over the head. Takes encryption keys. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/syndicate
origin_tech = "syndicate=3"
ks1type = /obj/item/encryptionkey/syndicate/nukeops
/obj/item/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."
flags = EARBANGPROTECT
origin_tech = "syndicate=3"
icon_state = "syndie_headset"
item_state = "syndie_headset"
/obj/item/radio/headset/syndicate/syndteam
ks1type = /obj/item/encryptionkey/syndteam
/obj/item/radio/headset/syndicate/alt/syndteam
ks1type = /obj/item/encryptionkey/syndteam
/obj/item/radio/headset/binary
origin_tech = "syndicate=3"
ks1type = /obj/item/encryptionkey/binary
/obj/item/radio/headset/headset_sec
name = "security radio headset"
desc = "This is used by your elite security force."
icon_state = "sec_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_sec
/obj/item/radio/headset/headset_sec/alt
name = "security bowman headset"
desc = "This is used by your elite security force. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "sec_headset_alt"
item_state = "sec_headset_alt"
/obj/item/radio/headset/headset_eng
name = "engineering radio headset"
desc = "When the engineers wish to chat like girls."
icon_state = "eng_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_eng
/obj/item/radio/headset/headset_rob
name = "robotics radio headset"
desc = "Made specifically for the roboticists who cannot decide between departments."
icon_state = "rob_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_rob
/obj/item/radio/headset/headset_med
name = "medical radio headset"
desc = "A headset for the trained staff of the medbay."
icon_state = "med_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_med
/obj/item/radio/headset/headset_sci
name = "science radio headset"
desc = "A sciency headset. Like usual."
icon_state = "sci_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_sci
/obj/item/radio/headset/headset_medsci
name = "medical research radio headset"
desc = "A headset that is a result of the mating between medical and science."
icon_state = "medsci_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_medsci
/obj/item/radio/headset/headset_com
name = "command radio headset"
desc = "A headset with a commanding channel."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_com
/obj/item/radio/headset/heads/captain
name = "captain's headset"
desc = "The headset of the boss."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/captain
/obj/item/radio/headset/heads/captain/alt
name = "\proper the captain's bowman headset"
desc = "The headset of the boss. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/heads/rd
name = "Research Director's headset"
desc = "Headset of the researching God."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/rd
/obj/item/radio/headset/heads/hos
name = "head of security's headset"
desc = "The headset of the man who protects your worthless lives."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/hos
/obj/item/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."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/heads/ce
name = "chief engineer's headset"
desc = "The headset of the guy who is in charge of morons."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/ce
/obj/item/radio/headset/heads/cmo
name = "chief medical officer's headset"
desc = "The headset of the highly trained medical chief."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/cmo
/obj/item/radio/headset/heads/hop
name = "head of personnel's headset"
desc = "The headset of the guy who will one day be captain."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/hop
/obj/item/radio/headset/headset_cargo
name = "supply radio headset"
desc = "A headset used by the cargo department."
icon_state = "cargo_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_cargo
/obj/item/radio/headset/headset_cargo/mining
name = "mining radio headset"
desc = "Headset used by shaft miners."
icon_state = "mine_headset"
/obj/item/radio/headset/headset_service
name = "service radio headset"
desc = "Headset used by the service staff, tasked with keeping the station full, happy and clean."
icon_state = "srv_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_service
/obj/item/radio/headset/heads/ntrep
name = "nanotrasen representative's headset"
desc = "The headset of the Nanotrasen Representative."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/ntrep
/obj/item/radio/headset/heads/magistrate
name = "magistrate's headset"
desc = "The headset of the Magistrate."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/magistrate
/obj/item/radio/headset/heads/magistrate/alt
name = "\proper magistrate's bowman headset"
desc = "The headset of the Magistrate. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/heads/blueshield
name = "blueshield's headset"
desc = "The headset of the Blueshield."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/blueshield
/obj/item/radio/headset/heads/blueshield/alt
name = "\proper blueshield's bowman headset"
desc = "The headset of the Blueshield. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/ert
name = "emergency response team headset"
desc = "The headset of the boss's boss."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/ert
/obj/item/radio/headset/ert/alt
name = "\proper emergency response team's bowman headset"
desc = "The headset of the boss. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/centcom
name = "\proper centcom officer's bowman headset"
desc = "The headset of final authority. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
ks2type = /obj/item/encryptionkey/centcom
/obj/item/radio/headset/heads/ai_integrated //No need to care about icons, it should be hidden inside the AI anyway.
name = "\improper AI subspace transceiver"
desc = "Integrated AI radio transceiver."
icon = 'icons/obj/robot_component.dmi'
icon_state = "radio"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/ai_integrated
var/myAi = null // Atlantis: Reference back to the AI which has this radio.
var/disabledAi = 0 // Atlantis: Used to manually disable AI's integrated radio via intellicard menu.
/obj/item/radio/headset/heads/ai_integrated/is_listening()
if(disabledAi)
return FALSE
return ..()
/obj/item/radio/headset/attackby(obj/item/W as obj, mob/user as mob)
user.set_machine(src)
if(!( istype(W, /obj/item/screwdriver) || (istype(W, /obj/item/encryptionkey/ ))))
return ..()
if(istype(W, /obj/item/screwdriver))
if(keyslot1 || keyslot2)
for(var/ch_name in channels)
SSradio.remove_object(src, SSradio.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
if(keyslot1)
var/turf/T = get_turf(user)
if(T)
keyslot1.loc = T
keyslot1 = null
if(keyslot2)
var/turf/T = get_turf(user)
if(T)
keyslot2.loc = T
keyslot2 = null
recalculateChannels()
to_chat(user, "You pop out the encryption keys in the headset!")
else
to_chat(user, "This headset doesn't have any encryption keys! How useless...")
if(istype(W, /obj/item/encryptionkey/))
if(keyslot1 && keyslot2)
to_chat(user, "The headset can't hold another key!")
return
if(!keyslot1)
user.drop_item()
W.loc = src
keyslot1 = W
else
user.drop_item()
W.loc = src
keyslot2 = W
recalculateChannels()
return
/obj/item/radio/headset/proc/recalculateChannels(var/setDescription = FALSE)
channels = list()
translate_binary = FALSE
translate_hive = FALSE
syndiekey = null
if(keyslot1)
for(var/ch_name in keyslot1.channels)
if(ch_name in channels)
continue
channels += ch_name
channels[ch_name] = keyslot1.channels[ch_name]
if(keyslot1.translate_binary)
translate_binary = TRUE
if(keyslot1.translate_hive)
translate_hive = TRUE
if(keyslot1.syndie)
syndiekey = keyslot1
if(keyslot2)
for(var/ch_name in keyslot2.channels)
if(ch_name in channels)
continue
channels += ch_name
channels[ch_name] = keyslot2.channels[ch_name]
if(keyslot2.translate_binary)
translate_binary = TRUE
if(keyslot2.translate_hive)
translate_hive = TRUE
if(keyslot2.syndie)
syndiekey = keyslot2
for(var/ch_name in channels)
if(!SSradio)
name = "broken radio headset"
return
secure_radio_connections[ch_name] = SSradio.add_object(src, SSradio.radiochannels[ch_name], RADIO_CHAT)
if(setDescription)
setupRadioDescription()
return
/obj/item/radio/headset/proc/setupRadioDescription()
var/radio_text = ""
for(var/i = 1 to channels.len)
var/channel = channels[i]
var/key = get_radio_key_from_channel(channel)
radio_text += "[key] - [channel]"
if(i != channels.len)
radio_text += ", "
radio_desc = radio_text
/obj/item/radio/headset/proc/make_syndie() // Turns normal radios into Syndicate radios!
qdel(keyslot1)
keyslot1 = new /obj/item/encryptionkey/syndicate
syndiekey = keyslot1
recalculateChannels()
/obj/item/radio/headset
name = "radio headset"
desc = "An updated, modular intercom that fits over the head. Takes encryption keys."
var/radio_desc = ""
icon_state = "headset"
item_state = "headset"
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/ears.dmi',
"Vox Armalis" = 'icons/mob/species/armalis/ears.dmi'
) //We read you loud and skree-er.
materials = list(MAT_METAL=75)
subspace_transmission = TRUE
canhear_range = 0 // can't hear headsets from very far away
slot_flags = SLOT_EARS
var/translate_binary = FALSE
var/translate_hive = FALSE
var/obj/item/encryptionkey/keyslot1 = null
var/obj/item/encryptionkey/keyslot2 = null
var/ks1type = null
var/ks2type = null
dog_fashion = null
/obj/item/radio/headset/New()
..()
internal_channels.Cut()
/obj/item/radio/headset/Initialize()
..()
if(ks1type)
keyslot1 = new ks1type(src)
if(keyslot1.syndie)
syndiekey = keyslot1
if(ks2type)
keyslot2 = new ks2type(src)
if(keyslot2.syndie)
syndiekey = keyslot2
recalculateChannels(TRUE)
/obj/item/radio/headset/Destroy()
QDEL_NULL(keyslot1)
QDEL_NULL(keyslot2)
return ..()
/obj/item/radio/headset/list_channels(var/mob/user)
return list_secure_channels()
/obj/item/radio/headset/examine(mob/user)
. = ..()
if(in_range(src, user) && radio_desc)
. += "The following channels are available:"
. += radio_desc
/obj/item/radio/headset/handle_message_mode(mob/living/M as mob, list/message_pieces, channel)
if(channel == "special")
if(translate_binary)
var/datum/language/binary = GLOB.all_languages["Robot Talk"]
binary.broadcast(M, strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
if(translate_hive)
var/datum/language/hivemind = GLOB.all_languages["Hivemind"]
hivemind.broadcast(M, strip_prefixes(multilingual_to_message(message_pieces)))
return RADIO_CONNECTION_NON_SUBSPACE
return RADIO_CONNECTION_FAIL
return ..()
/obj/item/radio/headset/is_listening()
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
if(H.l_ear == src || H.r_ear == src)
return ..()
else if(isanimal(loc) || isAI(loc))
return ..()
return FALSE
/obj/item/radio/headset/alt
name = "bowman headset"
desc = "An updated, modular intercom that fits over the head. Takes encryption keys. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/syndicate
origin_tech = "syndicate=3"
ks1type = /obj/item/encryptionkey/syndicate/nukeops
/obj/item/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."
flags = EARBANGPROTECT
origin_tech = "syndicate=3"
icon_state = "syndie_headset"
item_state = "syndie_headset"
/obj/item/radio/headset/syndicate/syndteam
ks1type = /obj/item/encryptionkey/syndteam
/obj/item/radio/headset/syndicate/alt/syndteam
ks1type = /obj/item/encryptionkey/syndteam
/obj/item/radio/headset/binary
origin_tech = "syndicate=3"
ks1type = /obj/item/encryptionkey/binary
/obj/item/radio/headset/headset_sec
name = "security radio headset"
desc = "This is used by your elite security force."
icon_state = "sec_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_sec
/obj/item/radio/headset/headset_sec/alt
name = "security bowman headset"
desc = "This is used by your elite security force. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "sec_headset_alt"
item_state = "sec_headset_alt"
/obj/item/radio/headset/headset_eng
name = "engineering radio headset"
desc = "When the engineers wish to chat like girls."
icon_state = "eng_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_eng
/obj/item/radio/headset/headset_rob
name = "robotics radio headset"
desc = "Made specifically for the roboticists who cannot decide between departments."
icon_state = "rob_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_rob
/obj/item/radio/headset/headset_med
name = "medical radio headset"
desc = "A headset for the trained staff of the medbay."
icon_state = "med_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_med
/obj/item/radio/headset/headset_sci
name = "science radio headset"
desc = "A sciency headset. Like usual."
icon_state = "sci_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_sci
/obj/item/radio/headset/headset_medsci
name = "medical research radio headset"
desc = "A headset that is a result of the mating between medical and science."
icon_state = "medsci_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_medsci
/obj/item/radio/headset/headset_com
name = "command radio headset"
desc = "A headset with a commanding channel."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_com
/obj/item/radio/headset/heads/captain
name = "captain's headset"
desc = "The headset of the boss."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/captain
/obj/item/radio/headset/heads/captain/alt
name = "\proper the captain's bowman headset"
desc = "The headset of the boss. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/heads/rd
name = "Research Director's headset"
desc = "Headset of the researching God."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/rd
/obj/item/radio/headset/heads/hos
name = "head of security's headset"
desc = "The headset of the man who protects your worthless lives."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/hos
/obj/item/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."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/heads/ce
name = "chief engineer's headset"
desc = "The headset of the guy who is in charge of morons."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/ce
/obj/item/radio/headset/heads/cmo
name = "chief medical officer's headset"
desc = "The headset of the highly trained medical chief."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/cmo
/obj/item/radio/headset/heads/hop
name = "head of personnel's headset"
desc = "The headset of the guy who will one day be captain."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/hop
/obj/item/radio/headset/headset_cargo
name = "supply radio headset"
desc = "A headset used by the cargo department."
icon_state = "cargo_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_cargo
/obj/item/radio/headset/headset_cargo/mining
name = "mining radio headset"
desc = "Headset used by shaft miners."
icon_state = "mine_headset"
/obj/item/radio/headset/headset_service
name = "service radio headset"
desc = "Headset used by the service staff, tasked with keeping the station full, happy and clean."
icon_state = "srv_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/headset_service
/obj/item/radio/headset/heads/ntrep
name = "nanotrasen representative's headset"
desc = "The headset of the Nanotrasen Representative."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/ntrep
/obj/item/radio/headset/heads/magistrate
name = "magistrate's headset"
desc = "The headset of the Magistrate."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/magistrate
/obj/item/radio/headset/heads/magistrate/alt
name = "\proper magistrate's bowman headset"
desc = "The headset of the Magistrate. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/heads/blueshield
name = "blueshield's headset"
desc = "The headset of the Blueshield."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/blueshield
/obj/item/radio/headset/heads/blueshield/alt
name = "\proper blueshield's bowman headset"
desc = "The headset of the Blueshield. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/ert
name = "emergency response team headset"
desc = "The headset of the boss's boss."
icon_state = "com_headset"
item_state = "headset"
ks2type = /obj/item/encryptionkey/ert
/obj/item/radio/headset/ert/alt
name = "\proper emergency response team's bowman headset"
desc = "The headset of the boss. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
/obj/item/radio/headset/centcom
name = "\proper centcom officer's bowman headset"
desc = "The headset of final authority. Protects ears from flashbangs."
flags = EARBANGPROTECT
icon_state = "com_headset_alt"
item_state = "com_headset_alt"
ks2type = /obj/item/encryptionkey/centcom
/obj/item/radio/headset/heads/ai_integrated //No need to care about icons, it should be hidden inside the AI anyway.
name = "\improper AI subspace transceiver"
desc = "Integrated AI radio transceiver."
icon = 'icons/obj/robot_component.dmi'
icon_state = "radio"
item_state = "headset"
ks2type = /obj/item/encryptionkey/heads/ai_integrated
var/myAi = null // Atlantis: Reference back to the AI which has this radio.
var/disabledAi = 0 // Atlantis: Used to manually disable AI's integrated radio via intellicard menu.
/obj/item/radio/headset/heads/ai_integrated/is_listening()
if(disabledAi)
return FALSE
return ..()
/obj/item/radio/headset/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/encryptionkey/))
user.set_machine(src)
if(keyslot1 && keyslot2)
to_chat(user, "The headset can't hold another key!")
return
if(!keyslot1)
user.drop_item()
W.loc = src
keyslot1 = W
else
user.drop_item()
W.loc = src
keyslot2 = W
recalculateChannels()
else
return ..()
/obj/item/radio/headset/screwdriver_act(mob/user, obj/item/I)
. = TRUE
if(!I.use_tool(src, user, 0, volume = 0))
return
user.set_machine(src)
if(keyslot1 || keyslot2)
for(var/ch_name in channels)
SSradio.remove_object(src, SSradio.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
if(keyslot1)
var/turf/T = get_turf(user)
if(T)
keyslot1.loc = T
keyslot1 = null
if(keyslot2)
var/turf/T = get_turf(user)
if(T)
keyslot2.loc = T
keyslot2 = null
recalculateChannels()
to_chat(user, "You pop out the encryption keys in the headset!")
I.play_tool_sound(user, I.tool_volume)
else
to_chat(user, "This headset doesn't have any encryption keys! How useless...")
/obj/item/radio/headset/proc/recalculateChannels(var/setDescription = FALSE)
channels = list()
translate_binary = FALSE
translate_hive = FALSE
syndiekey = null
if(keyslot1)
for(var/ch_name in keyslot1.channels)
if(ch_name in channels)
continue
channels += ch_name
channels[ch_name] = keyslot1.channels[ch_name]
if(keyslot1.translate_binary)
translate_binary = TRUE
if(keyslot1.translate_hive)
translate_hive = TRUE
if(keyslot1.syndie)
syndiekey = keyslot1
if(keyslot2)
for(var/ch_name in keyslot2.channels)
if(ch_name in channels)
continue
channels += ch_name
channels[ch_name] = keyslot2.channels[ch_name]
if(keyslot2.translate_binary)
translate_binary = TRUE
if(keyslot2.translate_hive)
translate_hive = TRUE
if(keyslot2.syndie)
syndiekey = keyslot2
for(var/ch_name in channels)
if(!SSradio)
name = "broken radio headset"
return
secure_radio_connections[ch_name] = SSradio.add_object(src, SSradio.radiochannels[ch_name], RADIO_CHAT)
if(setDescription)
setupRadioDescription()
return
/obj/item/radio/headset/proc/setupRadioDescription()
var/radio_text = ""
for(var/i = 1 to channels.len)
var/channel = channels[i]
var/key = get_radio_key_from_channel(channel)
radio_text += "[key] - [channel]"
if(i != channels.len)
radio_text += ", "
radio_desc = radio_text
/obj/item/radio/headset/proc/make_syndie() // Turns normal radios into Syndicate radios!
qdel(keyslot1)
keyslot1 = new /obj/item/encryptionkey/syndicate
syndiekey = keyslot1
recalculateChannels()
+274 -268
View File
@@ -1,268 +1,274 @@
/obj/item/radio/intercom
name = "station intercom (General)"
desc = "Talk through this."
icon_state = "intercom"
anchored = 1
w_class = WEIGHT_CLASS_BULKY
canhear_range = 2
flags = CONDUCT
var/number = 0
var/circuitry_installed = 1
var/last_tick //used to delay the powercheck
var/buildstage = 0
dog_fashion = null
/obj/item/radio/intercom/custom
name = "station intercom (Custom)"
broadcasting = 0
listening = 0
/obj/item/radio/intercom/interrogation
name = "station intercom (Interrogation)"
frequency = AIRLOCK_FREQ
/obj/item/radio/intercom/private
name = "station intercom (Private)"
frequency = AI_FREQ
/obj/item/radio/intercom/command
name = "station intercom (Command)"
frequency = COMM_FREQ
/obj/item/radio/intercom/specops
name = "\improper Special Operations intercom"
frequency = ERT_FREQ
/obj/item/radio/intercom/department
canhear_range = 5
broadcasting = 0
listening = 1
/obj/item/radio/intercom/department/medbay
name = "station intercom (Medbay)"
frequency = MED_I_FREQ
/obj/item/radio/intercom/department/security
name = "station intercom (Security)"
frequency = SEC_I_FREQ
/obj/item/radio/intercom/New(turf/loc, ndir, building = 3)
..()
buildstage = building
if(buildstage)
START_PROCESSING(SSobj, src)
else
if(ndir)
pixel_x = (ndir & EAST|WEST) ? (ndir == EAST ? 28 : -28) : 0
pixel_y = (ndir & NORTH|SOUTH) ? (ndir == NORTH ? 28 : -28) : 0
dir=ndir
b_stat=1
on = 0
GLOB.global_intercoms.Add(src)
update_icon()
/obj/item/radio/intercom/department/medbay/New()
..()
internal_channels = default_medbay_channels.Copy()
/obj/item/radio/intercom/department/security/New()
..()
internal_channels = list(
num2text(PUB_FREQ) = list(),
num2text(SEC_I_FREQ) = list(access_security)
)
/obj/item/radio/intercom/syndicate
name = "illicit intercom"
desc = "Talk through this. Evilly"
frequency = SYND_FREQ
subspace_transmission = TRUE
syndiekey = new /obj/item/encryptionkey/syndicate/nukeops
/obj/item/radio/intercom/syndicate/New()
..()
internal_channels[num2text(SYND_FREQ)] = list(access_syndicate)
/obj/item/radio/intercom/pirate
name = "pirate radio intercom"
desc = "You wouldn't steal a space shuttle. Piracy. It's a crime!"
subspace_transmission = 1
/obj/item/radio/intercom/pirate/New()
..()
internal_channels.Cut()
internal_channels = list(
num2text(PUB_FREQ) = list(),
num2text(AI_FREQ) = list(),
num2text(COMM_FREQ)= list(),
num2text(ENG_FREQ) = list(),
num2text(MED_FREQ) = list(),
num2text(MED_I_FREQ)=list(),
num2text(SEC_FREQ) = list(),
num2text(SEC_I_FREQ)=list(),
num2text(SCI_FREQ) = list(),
num2text(SUP_FREQ) = list(),
num2text(SRV_FREQ) = list()
)
/obj/item/radio/intercom/Destroy()
STOP_PROCESSING(SSobj, src)
GLOB.global_intercoms.Remove(src)
return ..()
/obj/item/radio/intercom/attack_ai(mob/user as mob)
add_hiddenprint(user)
add_fingerprint(user)
spawn(0)
attack_self(user)
/obj/item/radio/intercom/attack_hand(mob/user as mob)
add_fingerprint(user)
spawn(0)
attack_self(user)
/obj/item/radio/intercom/receive_range(freq, level)
if(!is_listening())
return -1
if(!(0 in level))
var/turf/position = get_turf(src)
// TODO: Integrate radio with the space manager
if(isnull(position) || !(position.z in level))
return -1
if(freq in SSradio.ANTAG_FREQS)
if(!(syndiekey))
return -1//Prevents broadcast of messages over devices lacking the encryption
return canhear_range
/obj/item/radio/intercom/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/stack/tape_roll)) //eww
return
switch(buildstage)
if(3)
if(iswirecutter(W) && b_stat && wires.IsAllCut())
to_chat(user, "<span class='notice'>You cut out the intercoms wiring and disconnect its electronics.</span>")
playsound(get_turf(src), W.usesound, 50, 1)
if(do_after(user, 10 * W.toolspeed, target = src))
if(buildstage != 3)
return
new /obj/item/stack/cable_coil(get_turf(src),5)
on = 0
b_stat = 1
buildstage = 1
update_icon()
STOP_PROCESSING(SSobj, src)
return 1
else return ..()
if(2)
if(isscrewdriver(W))
playsound(get_turf(src), W.usesound, 50, 1)
if(do_after(user, 10 * W.toolspeed, target = src))
update_icon()
on = 1
b_stat = 0
buildstage = 3
to_chat(user, "<span class='notice'>You secure the electronics!</span>")
update_icon()
START_PROCESSING(SSobj, src)
for(var/i, i<= 5, i++)
wires.UpdateCut(i,1)
return 1
if(1)
if(iscoil(W))
var/obj/item/stack/cable_coil/coil = W
if(coil.amount < 5)
to_chat(user, "<span class='warning'>You need more cable for this!</span>")
return
if(do_after(user, 10 * coil.toolspeed, target = src))
coil.use(5)
to_chat(user, "<span class='notice'>You wire \the [src]!</span>")
buildstage = 2
return 1
if(iscrowbar(W))
to_chat(user, "<span class='notice'>You begin removing the electronics...</span>")
playsound(get_turf(src), W.usesound, 50, 1)
if(do_after(user, 10 * W.toolspeed, target = src))
if(buildstage != 1)
return
new /obj/item/intercom_electronics(get_turf(src))
to_chat(user, "<span class='notice'>The circuitboard pops out!</span>")
buildstage = 0
return 1
if(0)
if(istype(W,/obj/item/intercom_electronics))
playsound(get_turf(src), W.usesound, 50, 1)
if(do_after(user, 10 * W.toolspeed, target = src))
qdel(W)
to_chat(user, "<span class='notice'>You insert \the [W] into \the [src]!</span>")
buildstage = 1
return 1
if(iswelder(W))
var/obj/item/weldingtool/WT=W
playsound(get_turf(src), WT.usesound, 50, 1)
if(!WT.remove_fuel(3, user))
to_chat(user, "<span class='warning'>You're out of welding fuel.</span>")
return 1
if(do_after(user, 10 * WT.toolspeed, target = src))
to_chat(user, "<span class='notice'>You cut the intercom frame from the wall!</span>")
new /obj/item/mounted/frame/intercom(get_turf(src))
qdel(src)
return 1
/obj/item/radio/intercom/update_icon()
if(!circuitry_installed)
icon_state="intercom-frame"
return
icon_state = "intercom[!on?"-p":""][b_stat ? "-open":""]"
/obj/item/radio/intercom/process()
if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0))
last_tick = world.timeofday
if(!src.loc)
on = 0
else
var/area/A = get_area(src)
if(!A)
on = 0
else
on = A.powered(EQUIP) // set "on" to the power status
update_icon()
/obj/item/intercom_electronics
name = "intercom electronics"
icon = 'icons/obj/doors/door_assembly.dmi'
icon_state = "door_electronics"
desc = "Looks like a circuit. Probably is."
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=50, MAT_GLASS=50)
origin_tech = "engineering=2;programming=1"
toolspeed = 1
usesound = 'sound/items/deconstruct.ogg'
/obj/item/radio/intercom/locked
var/locked_frequency
/obj/item/radio/intercom/locked/set_frequency(var/frequency)
if(frequency == locked_frequency)
..(locked_frequency)
/obj/item/radio/intercom/locked/list_channels()
return ""
/obj/item/radio/intercom/locked/ai_private
name = "\improper AI intercom"
frequency = AI_FREQ
/obj/item/radio/intercom/locked/confessional
name = "confessional intercom"
frequency = 1480
/obj/item/radio/intercom/locked/prison
name = "\improper prison intercom"
desc = "Talk through this. It looks like it has been modified to not broadcast."
/obj/item/radio/intercom/locked/prison/New()
..()
wires.CutWireIndex(WIRE_TRANSMIT)
/obj/item/radio/intercom
name = "station intercom (General)"
desc = "Talk through this."
icon_state = "intercom"
anchored = 1
w_class = WEIGHT_CLASS_BULKY
canhear_range = 2
flags = CONDUCT
var/number = 0
var/circuitry_installed = 1
var/last_tick //used to delay the powercheck
var/buildstage = 0
dog_fashion = null
/obj/item/radio/intercom/custom
name = "station intercom (Custom)"
broadcasting = 0
listening = 0
/obj/item/radio/intercom/interrogation
name = "station intercom (Interrogation)"
frequency = AIRLOCK_FREQ
/obj/item/radio/intercom/private
name = "station intercom (Private)"
frequency = AI_FREQ
/obj/item/radio/intercom/command
name = "station intercom (Command)"
frequency = COMM_FREQ
/obj/item/radio/intercom/specops
name = "\improper Special Operations intercom"
frequency = ERT_FREQ
/obj/item/radio/intercom/department
canhear_range = 5
broadcasting = 0
listening = 1
/obj/item/radio/intercom/department/medbay
name = "station intercom (Medbay)"
frequency = MED_I_FREQ
/obj/item/radio/intercom/department/security
name = "station intercom (Security)"
frequency = SEC_I_FREQ
/obj/item/radio/intercom/New(turf/loc, ndir, building = 3)
..()
buildstage = building
if(buildstage)
START_PROCESSING(SSobj, src)
else
if(ndir)
pixel_x = (ndir & EAST|WEST) ? (ndir == EAST ? 28 : -28) : 0
pixel_y = (ndir & NORTH|SOUTH) ? (ndir == NORTH ? 28 : -28) : 0
dir=ndir
b_stat=1
on = 0
GLOB.global_intercoms.Add(src)
update_icon()
/obj/item/radio/intercom/department/medbay/New()
..()
internal_channels = default_medbay_channels.Copy()
/obj/item/radio/intercom/department/security/New()
..()
internal_channels = list(
num2text(PUB_FREQ) = list(),
num2text(SEC_I_FREQ) = list(ACCESS_SECURITY)
)
/obj/item/radio/intercom/syndicate
name = "illicit intercom"
desc = "Talk through this. Evilly"
frequency = SYND_FREQ
subspace_transmission = TRUE
syndiekey = new /obj/item/encryptionkey/syndicate/nukeops
/obj/item/radio/intercom/syndicate/New()
..()
internal_channels[num2text(SYND_FREQ)] = list(ACCESS_SYNDICATE)
/obj/item/radio/intercom/pirate
name = "pirate radio intercom"
desc = "You wouldn't steal a space shuttle. Piracy. It's a crime!"
subspace_transmission = 1
/obj/item/radio/intercom/pirate/New()
..()
internal_channels.Cut()
internal_channels = list(
num2text(PUB_FREQ) = list(),
num2text(AI_FREQ) = list(),
num2text(COMM_FREQ)= list(),
num2text(ENG_FREQ) = list(),
num2text(MED_FREQ) = list(),
num2text(MED_I_FREQ)=list(),
num2text(SEC_FREQ) = list(),
num2text(SEC_I_FREQ)=list(),
num2text(SCI_FREQ) = list(),
num2text(SUP_FREQ) = list(),
num2text(SRV_FREQ) = list()
)
/obj/item/radio/intercom/Destroy()
STOP_PROCESSING(SSobj, src)
GLOB.global_intercoms.Remove(src)
return ..()
/obj/item/radio/intercom/attack_ai(mob/user as mob)
add_hiddenprint(user)
add_fingerprint(user)
spawn(0)
attack_self(user)
/obj/item/radio/intercom/attack_hand(mob/user as mob)
add_fingerprint(user)
spawn(0)
attack_self(user)
/obj/item/radio/intercom/receive_range(freq, level)
if(!is_listening())
return -1
if(!(0 in level))
var/turf/position = get_turf(src)
// TODO: Integrate radio with the space manager
if(isnull(position) || !(position.z in level))
return -1
if(freq in SSradio.ANTAG_FREQS)
if(!(syndiekey))
return -1//Prevents broadcast of messages over devices lacking the encryption
return canhear_range
/obj/item/radio/intercom/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/stack/tape_roll)) //eww
return
else if(iscoil(W) && buildstage == 1)
var/obj/item/stack/cable_coil/coil = W
if(coil.amount < 5)
to_chat(user, "<span class='warning'>You need more cable for this!</span>")
return
if(do_after(user, 10 * coil.toolspeed, target = src) && buildstage == 1)
coil.use(5)
to_chat(user, "<span class='notice'>You wire \the [src]!</span>")
buildstage = 2
return 1
else if(istype(W,/obj/item/intercom_electronics) && buildstage == 0)
playsound(get_turf(src), W.usesound, 50, 1)
if(do_after(user, 10 * W.toolspeed, target = src) && buildstage == 0)
qdel(W)
to_chat(user, "<span class='notice'>You insert \the [W] into \the [src]!</span>")
buildstage = 1
return 1
else
return ..()
/obj/item/radio/intercom/crowbar_act(mob/user, obj/item/I)
if(buildstage != 1)
return
. = TRUE
if(!I.tool_use_check(user, 0))
return
to_chat(user, "<span class='notice'>You begin removing the electronics...</span>")
if(!I.use_tool(src, user, 10, volume = I.tool_volume) || buildstage != 1)
return
new /obj/item/intercom_electronics(get_turf(src))
to_chat(user, "<span class='notice'>The circuit board pops out!</span>")
buildstage = 0
/obj/item/radio/intercom/screwdriver_act(mob/user, obj/item/I)
if(buildstage != 2)
return ..()
. = TRUE
if(!I.tool_use_check(user, 0))
return
if(!I.use_tool(src, user, 10, volume = I.tool_volume) || buildstage != 2)
return
update_icon()
on = 1
b_stat = 0
buildstage = 3
to_chat(user, "<span class='notice'>You secure the electronics!</span>")
update_icon()
START_PROCESSING(SSobj, src)
for(var/i, i<= 5, i++)
wires.UpdateCut(i,1)
/obj/item/radio/intercom/wirecutter_act(mob/user, obj/item/I)
if(!(buildstage == 3 && b_stat && wires.IsAllCut()))
return
. = TRUE
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
WIRECUTTER_SNIP_MESSAGE
new /obj/item/stack/cable_coil(get_turf(src),5)
on = 0
b_stat = 1
buildstage = 1
update_icon()
STOP_PROCESSING(SSobj, src)
/obj/item/radio/intercom/welder_act(mob/user, obj/item/I)
if(!buildstage)
return
. = TRUE
if(!I.tool_use_check(user, 3))
return
to_chat(user, "<span class='notice'>You start slicing [src] from the wall...</span>")
if(I.use_tool(src, user, 10, amount = 3, volume = I.tool_volume))
to_chat(user, "<span class='notice'>You cut [src] free from the wall!</span>")
new /obj/item/mounted/frame/intercom(get_turf(src))
qdel(src)
/obj/item/radio/intercom/update_icon()
if(!circuitry_installed)
icon_state="intercom-frame"
return
icon_state = "intercom[!on?"-p":""][b_stat ? "-open":""]"
/obj/item/radio/intercom/process()
if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0))
last_tick = world.timeofday
if(!src.loc)
on = 0
else
var/area/A = get_area(src)
if(!A)
on = 0
else
on = A.powered(EQUIP) // set "on" to the power status
update_icon()
/obj/item/intercom_electronics
name = "intercom electronics"
icon = 'icons/obj/doors/door_assembly.dmi'
icon_state = "door_electronics"
desc = "Looks like a circuit. Probably is."
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=50, MAT_GLASS=50)
origin_tech = "engineering=2;programming=1"
toolspeed = 1
usesound = 'sound/items/deconstruct.ogg'
/obj/item/radio/intercom/locked
var/locked_frequency
/obj/item/radio/intercom/locked/set_frequency(var/frequency)
if(frequency == locked_frequency)
..(locked_frequency)
/obj/item/radio/intercom/locked/list_channels()
return ""
/obj/item/radio/intercom/locked/ai_private
name = "\improper AI intercom"
frequency = AI_FREQ
/obj/item/radio/intercom/locked/confessional
name = "confessional intercom"
frequency = 1480
/obj/item/radio/intercom/locked/prison
name = "\improper prison intercom"
desc = "Talk through this. It looks like it has been modified to not broadcast."
/obj/item/radio/intercom/locked/prison/New()
..()
wires.CutWireIndex(RADIO_WIRE_TRANSMIT)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -9,6 +9,7 @@
var/datum/nano_module/crew_monitor/crew_monitor
/obj/item/sensor_device/New()
..()
crew_monitor = new(src)
/obj/item/sensor_device/Destroy()
+324 -320
View File
@@ -1,320 +1,324 @@
/obj/item/taperecorder
name = "universal recorder"
desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback."
icon = 'icons/obj/device.dmi'
icon_state = "taperecorder_empty"
item_state = "analyzer"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
materials = list(MAT_METAL=60, MAT_GLASS=30)
force = 2
throwforce = 0
var/recording = 0
var/playing = 0
var/playsleepseconds = 0
var/obj/item/tape/mytape
var/open_panel = 0
var/canprint = 1
/obj/item/taperecorder/New()
mytape = new /obj/item/tape/random(src)
update_icon()
/obj/item/taperecorder/Destroy()
QDEL_NULL(mytape)
return ..()
/obj/item/taperecorder/examine(mob/user)
. = ..()
if(in_range(user, src))
. += "The wire panel is [open_panel ? "opened" : "closed"]."
/obj/item/taperecorder/attackby(obj/item/I, mob/user)
if(!mytape && istype(I, /obj/item/tape))
user.drop_item()
I.loc = src
mytape = I
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
update_icon()
/obj/item/taperecorder/proc/eject(mob/user)
if(mytape)
to_chat(user, "<span class='notice'>You remove [mytape] from [src].</span>")
stop()
user.put_in_hands(mytape)
mytape = null
update_icon()
/obj/item/taperecorder/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
mytape.ruin() //Fires destroy the tape
return ..()
/obj/item/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/taperecorder/verb/ejectverb()
set name = "Eject Tape"
set category = "Object"
if(usr.stat)
return
if(!mytape)
return
eject(usr)
/obj/item/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/taperecorder/hear_talk(mob/living/M as mob, list/message_pieces)
var/msg = multilingual_to_message(message_pieces)
if(mytape && recording)
var/ending = copytext(msg, length(msg))
mytape.timestamp += mytape.used_capacity
if(M.stuttering)
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] stammers, \"[msg]\""
return
if(M.getBrainLoss() >= 60)
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] gibbers, \"[msg]\""
return
if(ending == "?")
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] asks, \"[msg]\""
return
else if(ending == "!")
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] exclaims, \"[msg]\""
return
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] says, \"[msg]\""
/obj/item/taperecorder/hear_message(mob/living/M as mob, msg)
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] [msg]"
/obj/item/taperecorder/verb/record()
set name = "Start Recording"
set category = "Object"
if(usr.stat)
return
if(!mytape || mytape.ruined)
return
if(recording)
return
if(playing)
return
if(mytape.used_capacity < mytape.max_capacity)
to_chat(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
to_chat(usr, "<span class='notice'>The tape is full.</span>")
/obj/item/taperecorder/verb/stop()
set name = "Stop"
set category = "Object"
if(usr.stat)
return
if(recording)
recording = 0
mytape.timestamp += mytape.used_capacity
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording stopped."
to_chat(usr, "<span class='notice'>Recording stopped.</span>")
return
else if(playing)
playing = 0
atom_say("Playback stopped.")
update_icon()
/obj/item/taperecorder/verb/play()
set name = "Play Tape"
set category = "Object"
if(usr.stat)
return
if(!mytape || mytape.ruined)
return
if(recording)
return
if(playing)
return
playing = 1
update_icon()
to_chat(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
atom_say("[mytape.storedinfo[i]]")
if(mytape.storedinfo.len < i + 1)
playsleepseconds = 1
sleep(10)
T = get_turf(src)
atom_say("End of recording.")
else
playsleepseconds = mytape.timestamp[i + 1] - mytape.timestamp[i]
if(playsleepseconds > 14)
sleep(10)
T = get_turf(src)
atom_say("Skipping [playsleepseconds] seconds of silence.")
playsleepseconds = 1
i++
playing = 0
update_icon()
/obj/item/taperecorder/attack_self(mob/user)
if(!mytape || mytape.ruined)
return
if(recording)
stop()
else
record()
/obj/item/taperecorder/verb/print_transcript()
set name = "Print Transcript"
set category = "Object"
if(usr.stat)
return
if(!mytape)
return
if(!canprint)
to_chat(usr, "<span class='notice'>The recorder can't print that fast!</span>")
return
if(recording || playing)
return
to_chat(usr, "<span class='notice'>Transcript printed.</span>")
playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1)
var/obj/item/paper/P = new /obj/item/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/taperecorder/empty/New()
return
/obj/item/tape
name = "tape"
desc = "A magnetic tape that can hold up to ten minutes of content."
icon = 'icons/obj/device.dmi'
icon_state = "tape_white"
item_state = "analyzer"
w_class = WEIGHT_CLASS_TINY
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/tape/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
ruin()
/obj/item/tape/attack_self(mob/user)
if(!ruined)
to_chat(user, "<span class='notice'>You pull out all the tape!</span>")
ruin()
/obj/item/tape/verb/wipe()
set name = "Wipe Tape"
set category = "Object"
if(usr.stat)
return
if(ruined)
return
to_chat(usr, "You erase the data from the [src]")
clear()
/obj/item/tape/proc/clear()
used_capacity = 0
storedinfo.Cut()
timestamp.Cut()
/obj/item/tape/proc/ruin()
if(!ruined)
overlays += "ribbonoverlay"
ruined = 1
/obj/item/tape/proc/fix()
overlays -= "ribbonoverlay"
ruined = 0
/obj/item/tape/attackby(obj/item/I, mob/user)
if(ruined && istype(I, /obj/item/screwdriver))
to_chat(user, "<span class='notice'>You start winding the tape back in.</span>")
if(do_after(user, 120 * I.toolspeed, target = src))
to_chat(user, "<span class='notice'>You wound the tape back in!</span>")
fix()
else if(istype(I, /obj/item/pen))
var/title = stripped_input(usr,"What do you want to name the tape?", "Tape Renaming", name, MAX_NAME_LEN)
if(!title || !length(title))
name = initial(name)
return
name = "tape - [title]"
//Random colour tapes
/obj/item/tape/random/New()
icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
/obj/item/taperecorder
name = "universal recorder"
desc = "A device that can record to cassette tapes, and play them. It automatically translates the content in playback."
icon = 'icons/obj/device.dmi'
icon_state = "taperecorder_empty"
item_state = "analyzer"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
materials = list(MAT_METAL=60, MAT_GLASS=30)
force = 2
throwforce = 0
var/recording = 0
var/playing = 0
var/playsleepseconds = 0
var/obj/item/tape/mytape
var/open_panel = 0
var/canprint = 1
var/starts_with_tape = TRUE
/obj/item/taperecorder/New()
..()
if(starts_with_tape)
mytape = new /obj/item/tape/random(src)
update_icon()
/obj/item/taperecorder/Destroy()
QDEL_NULL(mytape)
return ..()
/obj/item/taperecorder/examine(mob/user)
. = ..()
if(in_range(user, src))
. += "The wire panel is [open_panel ? "opened" : "closed"]."
/obj/item/taperecorder/attackby(obj/item/I, mob/user)
if(!mytape && istype(I, /obj/item/tape))
user.drop_item()
I.loc = src
mytape = I
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
update_icon()
/obj/item/taperecorder/proc/eject(mob/user)
if(mytape)
to_chat(user, "<span class='notice'>You remove [mytape] from [src].</span>")
stop()
user.put_in_hands(mytape)
mytape = null
update_icon()
/obj/item/taperecorder/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
mytape.ruin() //Fires destroy the tape
return ..()
/obj/item/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/taperecorder/verb/ejectverb()
set name = "Eject Tape"
set category = "Object"
if(usr.stat)
return
if(!mytape)
return
eject(usr)
/obj/item/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/taperecorder/hear_talk(mob/living/M as mob, list/message_pieces)
var/msg = multilingual_to_message(message_pieces)
if(mytape && recording)
var/ending = copytext(msg, length(msg))
mytape.timestamp += mytape.used_capacity
if(M.stuttering)
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] stammers, \"[msg]\""
return
if(M.getBrainLoss() >= 60)
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] gibbers, \"[msg]\""
return
if(ending == "?")
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] asks, \"[msg]\""
return
else if(ending == "!")
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] exclaims, \"[msg]\""
return
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] says, \"[msg]\""
/obj/item/taperecorder/hear_message(mob/living/M as mob, msg)
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] [M.name] [msg]"
/obj/item/taperecorder/verb/record()
set name = "Start Recording"
set category = "Object"
if(usr.stat)
return
if(!mytape || mytape.ruined)
return
if(recording)
return
if(playing)
return
if(mytape.used_capacity < mytape.max_capacity)
to_chat(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
to_chat(usr, "<span class='notice'>The tape is full.</span>")
/obj/item/taperecorder/verb/stop()
set name = "Stop"
set category = "Object"
if(usr.stat)
return
if(recording)
recording = 0
mytape.timestamp += mytape.used_capacity
mytape.storedinfo += "\[[time2text(mytape.used_capacity * 10,"mm:ss")]\] Recording stopped."
to_chat(usr, "<span class='notice'>Recording stopped.</span>")
return
else if(playing)
playing = 0
atom_say("Playback stopped.")
update_icon()
/obj/item/taperecorder/verb/play()
set name = "Play Tape"
set category = "Object"
if(usr.stat)
return
if(!mytape || mytape.ruined)
return
if(recording)
return
if(playing)
return
playing = 1
update_icon()
to_chat(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
atom_say("[mytape.storedinfo[i]]")
if(mytape.storedinfo.len < i + 1)
playsleepseconds = 1
sleep(10)
T = get_turf(src)
atom_say("End of recording.")
else
playsleepseconds = mytape.timestamp[i + 1] - mytape.timestamp[i]
if(playsleepseconds > 14)
sleep(10)
T = get_turf(src)
atom_say("Skipping [playsleepseconds] seconds of silence.")
playsleepseconds = 1
i++
playing = 0
update_icon()
/obj/item/taperecorder/attack_self(mob/user)
if(!mytape || mytape.ruined)
return
if(recording)
stop()
else
record()
/obj/item/taperecorder/verb/print_transcript()
set name = "Print Transcript"
set category = "Object"
if(usr.stat)
return
if(!mytape)
return
if(!canprint)
to_chat(usr, "<span class='notice'>The recorder can't print that fast!</span>")
return
if(recording || playing)
return
to_chat(usr, "<span class='notice'>Transcript printed.</span>")
playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1)
var/obj/item/paper/P = new /obj/item/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/taperecorder/empty
starts_with_tape = FALSE
/obj/item/tape
name = "tape"
desc = "A magnetic tape that can hold up to ten minutes of content."
icon = 'icons/obj/device.dmi'
icon_state = "tape_white"
item_state = "analyzer"
w_class = WEIGHT_CLASS_TINY
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/tape/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
ruin()
/obj/item/tape/attack_self(mob/user)
if(!ruined)
to_chat(user, "<span class='notice'>You pull out all the tape!</span>")
ruin()
/obj/item/tape/verb/wipe()
set name = "Wipe Tape"
set category = "Object"
if(usr.stat)
return
if(ruined)
return
to_chat(usr, "You erase the data from the [src]")
clear()
/obj/item/tape/proc/clear()
used_capacity = 0
storedinfo.Cut()
timestamp.Cut()
/obj/item/tape/proc/ruin()
if(!ruined)
overlays += "ribbonoverlay"
ruined = 1
/obj/item/tape/proc/fix()
overlays -= "ribbonoverlay"
ruined = 0
/obj/item/tape/attackby(obj/item/I, mob/user)
if(ruined && istype(I, /obj/item/screwdriver))
to_chat(user, "<span class='notice'>You start winding the tape back in.</span>")
if(do_after(user, 120 * I.toolspeed, target = src))
to_chat(user, "<span class='notice'>You wound the tape back in!</span>")
fix()
else if(istype(I, /obj/item/pen))
var/title = stripped_input(usr,"What do you want to name the tape?", "Tape Renaming", name, MAX_NAME_LEN)
if(!title || !length(title))
name = initial(name)
return
name = "tape - [title]"
//Random colour tapes
/obj/item/tape/random/New()
..()
icon_state = "tape_[pick("white", "blue", "red", "yellow", "purple")]"
@@ -10,6 +10,7 @@
var/datum/effect_system/spark_spread/spark_system
/obj/item/thermal_drill/New()
..()
soundloop = new(list(src), FALSE)
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(1, 0, src)
@@ -24,4 +25,4 @@
name = "diamond tipped thermal safe drill"
desc = "A diamond tipped thermal drill with magnetic clamps for the purpose of quickly drilling hardened objects. Guaranteed 100% jam proof."
icon_state = "diamond_drill"
time_multiplier = 0.5
time_multiplier = 0.5
@@ -167,4 +167,4 @@ effective or pretty fucking useless.
if(active)
GLOB.active_jammers |= src
else
GLOB.active_jammers -= src
GLOB.active_jammers -= src
+220 -220
View File
@@ -1,220 +1,220 @@
/obj/item/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/tank/tank_one = null
var/obj/item/tank/tank_two = null
var/obj/item/assembly/attached_device = null
var/mob/living/attacher = null
var/valve_open = 0
var/toggle = 1
origin_tech = "materials=1;engineering=1"
/obj/item/transfer_valve/Destroy()
QDEL_NULL(tank_one)
QDEL_NULL(tank_two)
QDEL_NULL(attached_device)
attacher = null
return ..()
/obj/item/transfer_valve/IsAssemblyHolder()
return 1
/obj/item/transfer_valve/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/tank))
if(tank_one && tank_two)
to_chat(user, "<span class='warning'>There are already two tanks attached, remove one first.</span>")
return
if(!tank_one)
if(!user.unEquip(I))
return
tank_one = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You attach the tank to the transfer valve.</span>")
if(I.w_class > w_class)
w_class = I.w_class
else if(!tank_two)
if(!user.unEquip(I))
return
tank_two = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You attach the tank to the transfer valve.</span>")
if(I.w_class > w_class)
w_class = I.w_class
update_icon()
SSnanoui.update_uis(src) // update all UIs attached to src
//TODO: Have this take an assemblyholder
else if(isassembly(I))
var/obj/item/assembly/A = I
if(A.secured)
to_chat(user, "<span class='notice'>The device is secured.</span>")
return
if(attached_device)
to_chat(user, "<span class='warning'>There is already a device attached to the valve, remove it first.</span>")
return
user.remove_from_mob(A)
attached_device = A
A.forceMove(src)
to_chat(user, "<span class='notice'>You attach the [A] 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).
investigate_log("[key_name(user)] attached a [A] to a transfer valve.", INVESTIGATE_BOMB)
msg_admin_attack("[key_name_admin(user)]attached [A] to a transfer valve.", ATKLOG_FEW)
log_game("[key_name_admin(user)] attached [A] to a transfer valve.")
attacher = user
SSnanoui.update_uis(src) // update all UIs attached to src
/obj/item/transfer_valve/HasProximity(atom/movable/AM)
if(!attached_device)
return
attached_device.HasProximity(AM)
/obj/item/transfer_valve/hear_talk(mob/living/M, list/message_pieces)
..()
for(var/obj/O in contents)
O.hear_talk(M, message_pieces)
/obj/item/transfer_valve/hear_message(mob/living/M, msg)
..()
for(var/obj/O in contents)
O.hear_message(M, msg)
/obj/item/transfer_valve/attack_self(mob/user)
ui_interact(user)
/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280)
// open the new ui window
ui.open()
// auto update every Master Controller tick
//ui.set_auto_update(1)
/obj/item/transfer_valve/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
var/data[0]
data["attachmentOne"] = tank_one ? tank_one.name : null
data["attachmentTwo"] = tank_two ? tank_two.name : null
data["valveAttachment"] = attached_device ? attached_device.name : null
data["valveOpen"] = valve_open ? 1 : 0
return data
/obj/item/transfer_valve/Topic(href, href_list)
..()
if(usr.incapacitated())
return 0
if(loc != usr)
return 0
if(tank_one && href_list["tankone"])
split_gases()
valve_open = 0
tank_one.forceMove(get_turf(src))
tank_one = null
update_icon()
if((!tank_two || tank_two.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
else if(tank_two && href_list["tanktwo"])
split_gases()
valve_open = 0
tank_two.forceMove(get_turf(src))
tank_two = null
update_icon()
if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
else if(href_list["open"])
toggle_valve()
else if(attached_device)
if(href_list["rem_device"])
attached_device.forceMove(get_turf(src))
attached_device.holder = null
attached_device = null
update_icon()
if(href_list["device"])
attached_device.attack_self(usr)
add_fingerprint(usr)
return 1 // Returning 1 sends an update to attached UIs
/obj/item/transfer_valve/proc/process_activation(obj/item/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/transfer_valve/update_icon()
overlays.Cut()
underlays = null
if(!tank_one && !tank_two && !attached_device)
icon_state = "valve_1"
return
icon_state = "valve"
if(tank_one)
overlays += "[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)
overlays += "device"
/obj/item/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/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/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/attacher_name = ""
if(!attacher)
attacher_name = "Unknown"
else
attacher_name = "[key_name_admin(attacher)]"
var/mob/mob = get_mob_by_key(src.fingerprintslast)
investigate_log("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]", INVESTIGATE_BOMB)
message_admins("Bomb valve opened at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name_admin(mob)]")
log_game("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]")
merge_gases()
spawn(20) // In case one tank bursts
for(var/i in 1 to 5)
update_icon()
sleep(10)
update_icon()
else if(valve_open && tank_one && tank_two)
split_gases()
valve_open = 0
update_icon()
/obj/item/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/tank/tank_one = null
var/obj/item/tank/tank_two = null
var/obj/item/assembly/attached_device = null
var/mob/living/attacher = null
var/valve_open = 0
var/toggle = 1
origin_tech = "materials=1;engineering=1"
/obj/item/transfer_valve/Destroy()
QDEL_NULL(tank_one)
QDEL_NULL(tank_two)
QDEL_NULL(attached_device)
attacher = null
return ..()
/obj/item/transfer_valve/IsAssemblyHolder()
return 1
/obj/item/transfer_valve/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/tank))
if(tank_one && tank_two)
to_chat(user, "<span class='warning'>There are already two tanks attached, remove one first.</span>")
return
if(!tank_one)
if(!user.unEquip(I))
return
tank_one = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You attach the tank to the transfer valve.</span>")
if(I.w_class > w_class)
w_class = I.w_class
else if(!tank_two)
if(!user.unEquip(I))
return
tank_two = I
I.forceMove(src)
to_chat(user, "<span class='notice'>You attach the tank to the transfer valve.</span>")
if(I.w_class > w_class)
w_class = I.w_class
update_icon()
SSnanoui.update_uis(src) // update all UIs attached to src
//TODO: Have this take an assemblyholder
else if(isassembly(I))
var/obj/item/assembly/A = I
if(A.secured)
to_chat(user, "<span class='notice'>The device is secured.</span>")
return
if(attached_device)
to_chat(user, "<span class='warning'>There is already a device attached to the valve, remove it first.</span>")
return
user.remove_from_mob(A)
attached_device = A
A.forceMove(src)
to_chat(user, "<span class='notice'>You attach the [A] 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).
investigate_log("[key_name(user)] attached a [A] to a transfer valve.", INVESTIGATE_BOMB)
msg_admin_attack("[key_name_admin(user)]attached [A] to a transfer valve.", ATKLOG_FEW)
log_game("[key_name_admin(user)] attached [A] to a transfer valve.")
attacher = user
SSnanoui.update_uis(src) // update all UIs attached to src
/obj/item/transfer_valve/HasProximity(atom/movable/AM)
if(!attached_device)
return
attached_device.HasProximity(AM)
/obj/item/transfer_valve/hear_talk(mob/living/M, list/message_pieces)
..()
for(var/obj/O in contents)
O.hear_talk(M, message_pieces)
/obj/item/transfer_valve/hear_message(mob/living/M, msg)
..()
for(var/obj/O in contents)
O.hear_message(M, msg)
/obj/item/transfer_valve/attack_self(mob/user)
ui_interact(user)
/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280)
// open the new ui window
ui.open()
// auto update every Master Controller tick
//ui.set_auto_update(1)
/obj/item/transfer_valve/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state)
var/data[0]
data["attachmentOne"] = tank_one ? tank_one.name : null
data["attachmentTwo"] = tank_two ? tank_two.name : null
data["valveAttachment"] = attached_device ? attached_device.name : null
data["valveOpen"] = valve_open ? 1 : 0
return data
/obj/item/transfer_valve/Topic(href, href_list)
..()
if(usr.incapacitated())
return 0
if(loc != usr)
return 0
if(tank_one && href_list["tankone"])
split_gases()
valve_open = 0
tank_one.forceMove(get_turf(src))
tank_one = null
update_icon()
if((!tank_two || tank_two.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
else if(tank_two && href_list["tanktwo"])
split_gases()
valve_open = 0
tank_two.forceMove(get_turf(src))
tank_two = null
update_icon()
if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL))
w_class = WEIGHT_CLASS_NORMAL
else if(href_list["open"])
toggle_valve()
else if(attached_device)
if(href_list["rem_device"])
attached_device.forceMove(get_turf(src))
attached_device.holder = null
attached_device = null
update_icon()
if(href_list["device"])
attached_device.attack_self(usr)
add_fingerprint(usr)
return 1 // Returning 1 sends an update to attached UIs
/obj/item/transfer_valve/proc/process_activation(obj/item/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/transfer_valve/update_icon()
overlays.Cut()
underlays = null
if(!tank_one && !tank_two && !attached_device)
icon_state = "valve_1"
return
icon_state = "valve"
if(tank_one)
overlays += "[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)
overlays += "device"
/obj/item/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/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/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/attacher_name = ""
if(!attacher)
attacher_name = "Unknown"
else
attacher_name = "[key_name_admin(attacher)]"
var/mob/mob = get_mob_by_key(src.fingerprintslast)
investigate_log("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]", INVESTIGATE_BOMB)
message_admins("Bomb valve opened at <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[bombturf.x];Y=[bombturf.y];Z=[bombturf.z]'>[A.name] (JMP)</a> with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name_admin(mob)]")
log_game("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]")
merge_gases()
spawn(20) // In case one tank bursts
for(var/i in 1 to 5)
update_icon()
sleep(10)
update_icon()
else if(valve_open && tank_one && tank_two)
split_gases()
valve_open = 0
update_icon()
+3 -1
View File
@@ -316,6 +316,7 @@ var/list/world_uplinks = list()
// implant uplink (not the implant tool) and a preset headset uplink.
/obj/item/radio/uplink/New()
..()
hidden_uplink = new(src)
icon_state = "radio"
@@ -339,6 +340,7 @@ var/list/world_uplinks = list()
hidden_uplink.uplink_type = "sst"
/obj/item/multitool/uplink/New()
..()
hidden_uplink = new(src)
/obj/item/multitool/uplink/attack_self(mob/user as mob)
@@ -351,4 +353,4 @@ var/list/world_uplinks = list()
/obj/item/radio/headset/uplink/New()
..()
hidden_uplink = new(src)
hidden_uplink.uses = 20
hidden_uplink.uses = 20
+1 -1
View File
@@ -41,4 +41,4 @@
return
voice = sanitize(copytext(chosen_voice, 1, MAX_MESSAGE_LEN))
to_chat(user, "<span class='notice'>You are now mimicking <b>[voice]</b>.</span>")
to_chat(user, "<span class='notice'>You are now mimicking <b>[voice]</b>.</span>")