This commit is contained in:
Ghommie
2020-06-23 03:12:49 +02:00
736 changed files with 240884 additions and 242590 deletions
+15 -1
View File
@@ -93,6 +93,13 @@
/area/shuttle/abandoned/pod
name = "Abandoned Ship Pod"
////////////////////////////Bounty Hunter Shuttles////////////////////////////
/area/shuttle/hunter
name = "Hunter Shuttle"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
blob_allowed = FALSE
canSmoothWithAreas = /area/shuttle/hunter
////////////////////////////Single-area shuttles////////////////////////////
/area/shuttle/transit
@@ -103,6 +110,10 @@
/area/shuttle/custom
name = "Custom player shuttle"
/area/shuttle/custom/powered
name = "Custom Powered player shuttle"
requires_power = FALSE
/area/shuttle/arrival
name = "Arrival Shuttle"
unique = TRUE // SSjob refers to this area for latejoiners
@@ -200,4 +211,7 @@
name = "Tiny Freighter"
/area/shuttle/caravan/freighter3
name = "Tiny Freighter"
name = "Tiny Freighter"
/area/shuttle/snowtaxi
name = "Snow Taxi"
+38 -1
View File
@@ -8,6 +8,13 @@
var/interaction_flags_atom = NONE
var/datum/reagents/reagents = null
var/flags_ricochet = NONE
///When a projectile tries to ricochet off this atom, the projectile ricochet chance is multiplied by this
var/ricochet_chance_mod = 1
///When a projectile ricochets off this atom, it deals the normal damage * this modifier to this atom
var/ricochet_damage_mod = 0.33
//This atom's HUD (med/sec, etc) images. Associative list.
var/list/image/hud_list = null
//HUD images that this atom can provide.
@@ -141,8 +148,27 @@
return ..()
/**
* Checks if a projectile should ricochet off of us. Projectiles get final say.
* [__DEFINES/projectiles.dm] for return values.
*/
/atom/proc/check_projectile_ricochet(obj/item/projectile/P)
return (flags_1 & DEFAULT_RICOCHET_1)? PROJECTILE_RICOCHET_YES : PROJECTILE_RICOCHET_NO
/atom/proc/handle_ricochet(obj/item/projectile/P)
return
var/turf/p_turf = get_turf(P)
var/face_direction = get_dir(src, p_turf)
var/face_angle = dir2angle(face_direction)
var/incidence_s = GET_ANGLE_OF_INCIDENCE(face_angle, (P.Angle + 180))
var/a_incidence_s = abs(incidence_s)
if(a_incidence_s > 90 && a_incidence_s < 270)
return FALSE
if((P.flag in list("bullet", "bomb")) && P.ricochet_incidence_leeway)
if((a_incidence_s < 90 && a_incidence_s < 90 - P.ricochet_incidence_leeway) || (a_incidence_s > 270 && a_incidence_s -270 > P.ricochet_incidence_leeway))
return
var/new_angle_s = SIMPLIFY_DEGREES(face_angle + incidence_s)
P.setAngle(new_angle_s)
return TRUE
/atom/proc/CanPass(atom/movable/mover, turf/target)
return !density
@@ -846,6 +872,17 @@
/atom/proc/GenerateTag()
return
/**
* Called after a shuttle is loaded **from map template initially**.
*
* @params
* * port - Mobile port/shuttle
* * dock - Stationary dock the shuttle's at
* * idnum - ID number of the shuttle
*/
/atom/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
return
// Generic logging helper
/atom/proc/log_message(message, message_type, color=null, log_globally=TRUE)
if(!log_globally)
@@ -202,7 +202,7 @@
icon_state = "moustacheg"
clumsy_check = GRENADE_NONCLUMSY_FUMBLE
/obj/item/grenade/chem_grenade/teargas/moustache/prime()
/obj/item/grenade/chem_grenade/teargas/moustache/prime(mob/living/lanced_by)
var/list/check_later = list()
for(var/mob/living/carbon/C in get_turf(src))
check_later += C
+3 -3
View File
@@ -145,9 +145,9 @@
new /obj/item/stack/sheet/plasteel(src.loc)
qdel(src)
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user)
/obj/machinery/dominator/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
add_fingerprint(user)
..()
return ..()
/obj/machinery/dominator/attack_hand(mob/user)
if(operating || (stat & BROKEN))
@@ -240,4 +240,4 @@
#undef DOM_BLOCKED_SPAM_CAP
#undef DOM_REQUIRED_TURFS
#undef DOM_HULK_HITS_REQUIRED
#undef DOM_HULK_HITS_REQUIRED
+1 -1
View File
@@ -288,7 +288,7 @@ datum/gang_item/clothing/shades //Addition: Why not have cool shades on a gang m
name = "Fragmentation Grenade"
id = "frag nade"
cost = 5
item_path = /obj/item/grenade/syndieminibomb/concussion/frag
item_path = /obj/item/grenade/frag
/datum/gang_item/equipment/implant_breaker
name = "Implant Breaker"
+1
View File
@@ -36,6 +36,7 @@
targetitem = /obj/item/gun/energy/e_gun/hos
difficulty = 10
excludefromjob = list("Head Of Security")
altitems = list(/obj/item/gun/ballistic/revolver/mws, /obj/item/choice_beacon/hosgun) //We now look for eather the alt verson of the hos gun or the beacon picker.
/datum/objective_item/steal/handtele
name = "a hand teleporter."
+2
View File
@@ -92,6 +92,8 @@ Class Procs:
pressure_resistance = 15
max_integrity = 200
layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it.
flags_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.3
anchored = TRUE
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
+9
View File
@@ -257,3 +257,12 @@
name = "AI upload monitor"
desc = "A telescreen that connects to the AI upload's camera network."
network = list("aiupload")
// Subtype that connects to shuttles.
/obj/machinery/computer/security/shuttle
circuit = /obj/item/circuitboard/computer/security/shuttle
/obj/machinery/computer/security/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in network)
network -= i
network += "[idnum][i]"
+2 -1
View File
@@ -169,7 +169,8 @@
to_chat(user, "[src] is now in [mode] mode.")
/obj/item/grenade/barrier/prime()
/obj/item/grenade/barrier/prime(mob/living/lanced_by)
. = ..()
new /obj/structure/barricade/security(get_turf(src.loc))
switch(mode)
if(VERTICAL)
+2 -2
View File
@@ -413,8 +413,8 @@
// shock user with probability prb (if all connections & power are working)
// returns TRUE if shocked, FALSE otherwise
// The preceding comment was borrowed from the grille's shock script
/obj/machinery/door/airlock/proc/shock(mob/user, prb)
if(!hasPower()) // unpowered, no shock
/obj/machinery/door/airlock/proc/shock(mob/living/user, prb)
if(!istype(user) || !hasPower()) // unpowered, no shock
return FALSE
if(shockCooldown > world.time)
return FALSE //Already shocked someone recently?
@@ -1,7 +1,7 @@
/obj/item/electronics/airlock
name = "airlock electronics"
req_access = list(ACCESS_MAINT_TUNNELS)
custom_price = 50
custom_price = PRICE_CHEAP
var/list/accesses = list()
var/one_access = 0
+1
View File
@@ -12,6 +12,7 @@
armor = list("melee" = 30, "bullet" = 30, "laser" = 20, "energy" = 20, "bomb" = 10, "bio" = 100, "rad" = 100, "fire" = 80, "acid" = 70)
CanAtmosPass = ATMOS_PASS_DENSITY
flags_1 = PREVENT_CLICK_UNDER_1
ricochet_chance_mod = 0.8
interaction_flags_atom = INTERACT_ATOM_UI_INTERACT
+1 -1
View File
@@ -260,7 +260,7 @@
/obj/item/electronics/firelock
name = "firelock circuitry"
custom_price = 50
custom_price = PRICE_CHEAP
desc = "A circuit board used in construction of firelocks."
icon_state = "mainboard"
+1 -1
View File
@@ -2,7 +2,7 @@
/obj/item/electronics/firealarm
name = "fire alarm electronics"
custom_price = 50
custom_price = PRICE_CHEAP
desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
/obj/item/wallframe/firealarm
+2 -1
View File
@@ -13,7 +13,8 @@
var/obj/item/reagent_containers/beaker
var/static/list/drip_containers = typecacheof(list(/obj/item/reagent_containers/blood,
/obj/item/reagent_containers/food,
/obj/item/reagent_containers/glass))
/obj/item/reagent_containers/glass,
/obj/item/reagent_containers/chem_pack))
/obj/machinery/iv_drip/Initialize(mapload)
. = ..()
@@ -70,8 +70,8 @@
else
return ..()
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user)
parent_turret.attacked_by(I, user)
/obj/machinery/porta_turret_cover/attacked_by(obj/item/I, mob/user, attackchain_flags = NONE, damage_multiplier = 1)
return parent_turret.attacked_by(I, user)
/obj/machinery/porta_turret_cover/attack_alien(mob/living/carbon/alien/humanoid/user)
parent_turret.attack_alien(user)
Executable → Regular
+25
View File
@@ -17,6 +17,8 @@
/obj/item/melee/baton,
/obj/item/ammo_box/magazine/recharge,
/obj/item/modular_computer,
/obj/item/ammo_casing/mws_batt,
/obj/item/ammo_box/magazine/mws_mag,
/obj/item/twohanded/electrostaff,
/obj/item/gun/ballistic/automatic/magrifle))
@@ -143,6 +145,29 @@
using_power = TRUE
update_icon()
return
if(istype(charging, /obj/item/ammo_casing/mws_batt))
var/obj/item/ammo_casing/mws_batt/R = charging
if(R.cell.charge < R.cell.maxcharge)
R.cell.give(R.cell.chargerate * recharge_coeff)
use_power(250 * recharge_coeff)
using_power = 1
if(R.BB == null)
R.chargeshot()
update_icon(using_power)
if(istype(charging, /obj/item/ammo_box/magazine/mws_mag))
var/obj/item/ammo_box/magazine/mws_mag/R = charging
for(var/B in R.stored_ammo)
var/obj/item/ammo_casing/mws_batt/batt = B
if(batt.cell.charge < batt.cell.maxcharge)
batt.cell.give(batt.cell.chargerate * recharge_coeff)
use_power(250 * recharge_coeff)
using_power = 1
if(batt.BB == null)
batt.chargeshot()
update_icon(using_power)
else
return PROCESS_KILL
+30 -12
View File
@@ -100,44 +100,61 @@
eat(AM)
. = ..()
/obj/machinery/recycler/proc/eat(atom/AM0, sound=TRUE)
/obj/machinery/recycler/proc/eat(atom/AM0)
if(stat & (BROKEN|NOPOWER) || safety_mode)
return
var/list/to_eat
to_eat = AM0.GetAllContentsIgnoring(GLOB.typecache_mob)
to_eat = list(AM0)
var/items_recycled = 0
var/buzz = FALSE
for(var/i in to_eat)
var/atom/movable/AM = i
if(QDELETED(AM))
continue
var/obj/item/bodypart/head/as_head = AM
var/obj/item/mmi/as_mmi = AM
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || isbrain(AM) || istype(AM, /obj/item/dullahan_relay)
var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay)
if(brain_holder)
emergency_stop(AM)
else if(isliving(AM))
if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM))))
crush_living(AM)
if(obj_flags & EMAGGED)
continue
else
emergency_stop(AM)
return
else if(isliving(AM))
if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM))))
to_eat += crush_living(AM)
else
emergency_stop(AM)
return
else if(isitem(AM))
var/obj/O = AM
if(O.resistance_flags & INDESTRUCTIBLE)
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
buzz = TRUE
O.forceMove(loc)
else
recycle_item(AM)
to_eat += recycle_item(AM)
items_recycled++
else
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
buzz = TRUE
AM.forceMove(loc)
if(items_recycled && sound)
if(items_recycled)
playsound(src, item_recycle_sound, 50, 1)
if(buzz)
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
/obj/machinery/recycler/proc/recycle_item(obj/item/I)
. = list()
for(var/A in I)
var/atom/movable/AM = A
AM.forceMove(loc)
if(AM.loc == loc)
. += AM
I.forceMove(loc)
var/obj/item/grown/log/L = I
if(istype(L))
@@ -172,6 +189,7 @@
/obj/machinery/recycler/proc/crush_living(mob/living/L)
. = list()
L.forceMove(loc)
if(issilicon(L))
@@ -193,7 +211,7 @@
if(eat_victim_items)
for(var/obj/item/I in L.get_equipped_items(TRUE))
if(L.dropItemToGround(I))
eat(I, sound=FALSE)
. += I
// Instantly lie down, also go unconscious from the pain, before you die.
L.Unconscious(100)
+249 -227
View File
@@ -9,7 +9,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
#define NO_NEW_MESSAGE 0
#define NORMAL_MESSAGE_PRIORITY 1
#define HIGH_MESSAGE_PRIORITY 2
#define EXTREME_MESSAGE_PRIORITY 3 // not implemented, will probably require some hacking... everything needs to have a hidden feature in this game.
#define EXTREME_MESSAGE_PRIORITY 3 // is implimented, does require hacking. everything needs to have a hidden feature in this game.
/obj/machinery/requests_console
name = "requests console"
@@ -48,9 +48,9 @@ GLOBAL_LIST_EMPTY(allConsoles)
var/announceAuth = FALSE //Will be set to 1 when you authenticate yourself for announcements
var/msgVerified = "" //Will contain the name of the person who verified it
var/msgStamped = "" //If a message is stamped, this will contain the stamp name
var/message = "";
var/dpt = ""; //the department which will be receiving the message
var/priority = -1 ; //Priority of the message being sent
var/message = ""
var/dpt = "" //the department which will be receiving the message
var/priority = NORMAL_MESSAGE_PRIORITY //Priority of the message being sent. why is the default -1??
var/obj/item/radio/Radio
var/emergency //If an emergency has been called by this device. Acts as both a cooldown and lets the responder know where it the emergency was triggered from
var/receive_ore_updates = FALSE //If ore redemption machines will send an update when it receives new ores.
@@ -62,16 +62,17 @@ GLOBAL_LIST_EMPTY(allConsoles)
update_icon()
/obj/machinery/requests_console/update_icon_state()
if(stat & NOPOWER)
if(CHECK_BITFIELD(stat, NOPOWER))
set_light(0)
else
set_light(1.4,0.7,"#34D352")//green light
set_light(1.4, 0.7, "#34D352")//green light
if(open)
if(!hackState)
icon_state="req_comp_open"
else
icon_state="req_comp_rewired"
else if(stat & NOPOWER)
else if(CHECK_BITFIELD(stat, NOPOWER))
if(icon_state != "req_comp_off")
icon_state = "req_comp_off"
else
@@ -122,7 +123,7 @@ GLOBAL_LIST_EMPTY(allConsoles)
GLOB.req_console_information += department
Radio = new /obj/item/radio(src)
Radio.listening = 0
Radio.listening = FALSE
/obj/machinery/requests_console/Destroy()
QDEL_NULL(Radio)
@@ -131,164 +132,173 @@ GLOBAL_LIST_EMPTY(allConsoles)
/obj/machinery/requests_console/ui_interact(mob/user)
. = ..()
if(open) //no.
return
var/dat = ""
if(!open)
switch(screen)
if(1) //req. assistance
dat += "Which department do you need assistance from?<BR><BR>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_assistance)
if (dpt != department)
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
if(hackState)
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
switch(screen)
if(1) //req. assistance
dat += "Which department do you need assistance from?<br><br>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_assistance)
if(dpt == department)
continue
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
if(hackState)
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<br><A href='?src=[REF(src)];setScreen=0'><< Back</A><br>"
if(2) //req. supplies
dat += "Which department do you need supplies from?<BR><BR>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_supplies)
if (dpt != department)
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
if(hackState)
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
if(2) //req. supplies
dat += "Which department do you need supplies from?<br><br>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_supplies)
if(dpt == department)
continue
if(3) //relay information
dat += "Which department would you like to send information to?<BR><BR>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_information)
if (dpt != department)
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'><A href='?src=[REF(src)];write=[ckey(dpt)]'>Normal</A> <A href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</A>"
if(hackState)
dat += "<A href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</A>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
if(hackState)
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<br><A href='?src=[REF(src)];setScreen=0'><< Back</A><br>"
if(6) //sent successfully
dat += "<span class='good'>Message sent.</span><BR><BR>"
dat += "<A href='?src=[REF(src)];setScreen=0'>Continue</A><BR>"
if(3) //relay information
dat += "Which department would you like to send information to?<br><br>"
dat += "<table width='100%'>"
for(var/dpt in GLOB.req_console_information)
if(dpt == department)
continue
dat += "<tr>"
dat += "<td width='55%'>[dpt]</td>"
dat += "<td width='45%'>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=1'>Normal</a>"
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=2'>High</a>"
if(hackState)
dat += "<a href='?src=[REF(src)];write=[ckey(dpt)];priority=3'>EXTREME</a>"
dat += "</td>"
dat += "</tr>"
dat += "</table>"
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back</a><br>"
if(7) //unsuccessful; not sent
dat += "<span class='bad'>An error occurred.</span><BR><BR>"
dat += "<A href='?src=[REF(src)];setScreen=0'>Continue</A><BR>"
if(6) //sent successfully
dat += "<span class='good'>Message sent.</span><br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'>Continue</a><br>"
if(8) //view messages
for (var/obj/machinery/requests_console/Console in GLOB.allConsoles)
if (Console.department == department)
Console.newmessagepriority = NO_NEW_MESSAGE
Console.update_icon()
if(7) //unsuccessful; not sent
dat += "<span class='bad'>An error occurred.</span><br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'>Continue</a><br>"
newmessagepriority = NO_NEW_MESSAGE
update_icon()
var/messageComposite = ""
for(var/msg in messages) // This puts more recent messages at the *top*, where they belong.
messageComposite = "<div class='block'>[msg]</div>" + messageComposite
dat += messageComposite
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back to Main Menu</A><BR>"
if(8) //view messages
for(var/obj/machinery/requests_console/Console in GLOB.allConsoles)
if(Console.department == department)
Console.newmessagepriority = NO_NEW_MESSAGE
Console.update_icon()
if(9) //authentication before sending
dat += "<B>Message Authentication</B><BR><BR>"
dat += "<b>Message for [dpt]: </b>[message]<BR><BR>"
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div><BR>"
dat += "<b>Validated by:</b> [msgVerified ? msgVerified : "<i>Not Validated</i>"]<br>"
dat += "<b>Stamped by:</b> [msgStamped ? msgStamped : "<i>Not Stamped</i>"]<br><br>"
dat += "<A href='?src=[REF(src)];department=[dpt]'>Send Message</A><BR>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Discard Message</A><BR>"
newmessagepriority = NO_NEW_MESSAGE
update_icon()
var/messageComposite = ""
for(var/msg in messages) // This puts more recent messages at the *top*, where they belong.
messageComposite = "<div class='block'>[msg]</div>" + messageComposite
dat += messageComposite
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back to Main Menu</a><br>"
if(10) //send announcement
dat += "<h3>Station-wide Announcement</h3>"
if(announceAuth)
dat += "<div class='notice'>Authentication accepted</div><BR>"
else
dat += "<div class='notice'>Swipe your card to authenticate yourself</div><BR>"
dat += "<b>Message: </b>[message ? message : "<i>No Message</i>"]<BR>"
dat += "<A href='?src=[REF(src)];writeAnnouncement=1'>[message ? "Edit" : "Write"] Message</A><BR><BR>"
if ((announceAuth || IsAdminGhost(user)) && message)
dat += "<A href='?src=[REF(src)];sendAnnouncement=1'>Announce Message</A><BR>"
else
dat += "<span class='linkOff'>Announce Message</span><BR>"
dat += "<BR><A href='?src=[REF(src)];setScreen=0'><< Back</A><BR>"
if(9) //authentication before sending
dat += "<b>Message Authentication</b> <br><br>"
dat += "<b>Message for [dpt]:</b> [message] <br><br>"
dat += "<div class='notice'>You may authenticate your message now by scanning your ID or your stamp</div> <br>"
dat += "<b>Validated by:</b> [msgVerified ? "<span class='good'><b>[msgVerified]</b></span>" : "<i>Not Validated</i>"] <br>"
dat += "<b>Stamped by:</b> [msgStamped ? "<span class='boldnotice'>[msgStamped]</span>" : "<i>Not Stamped</i>"] <br><br>"
dat += "<a href='?src=[REF(src)];department=[dpt]'>Send Message</a> <br><br>"
dat += "<a href='?src=[REF(src)];setScreen=0'><< Discard Message</a> <br>"
else //main menu
screen = 0
announceAuth = FALSE
if (newmessagepriority == NORMAL_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new messages</div><BR>"
if (newmessagepriority == HIGH_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>PRIORITY</b> messages</div><BR>"
if (newmessagepriority == EXTREME_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>EXTREME PRIORITY</b> messages</div><BR>"
dat += "<A href='?src=[REF(src)];setScreen=8'>View Messages</A><BR><BR>"
if(10) //send announcement
dat += "<h3>Station-wide Announcement</h3>"
if(announceAuth)
dat += "<div class='notice'>Authentication accepted</div><br>"
else
dat += "<div class='notice'>Swipe your card to authenticate yourself</div> <br>"
dat += "<b>Message: </b>[message ? message : "<i>No Message</i>"] <br>"
dat += "<a href='?src=[REF(src)];writeAnnouncement=1'>[message ? "Edit" : "Write"] Message</a> <br><br>"
if((announceAuth || IsAdminGhost(user)) && message)
dat += "<a href='?src=[REF(src)];sendAnnouncement=1'>Announce Message</a> <br>"
else
dat += "<span class='linkOff'>Announce Message</span> <br>"
dat += "<br><a href='?src=[REF(src)];setScreen=0'><< Back</a> <br>"
dat += "<A href='?src=[REF(src)];setScreen=1'>Request Assistance</A><BR>"
dat += "<A href='?src=[REF(src)];setScreen=2'>Request Supplies</A><BR>"
dat += "<A href='?src=[REF(src)];setScreen=3'>Relay Anonymous Information</A><BR><BR>"
else //main menu
screen = 0
announceAuth = FALSE
if(newmessagepriority == NORMAL_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new messages</div><br>"
if(newmessagepriority == HIGH_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>PRIORITY</b> messages</div><br>"
if(newmessagepriority == EXTREME_MESSAGE_PRIORITY)
dat += "<div class='notice'>There are new <b>EXTREME PRIORITY</b> messages</div><br>"
if(!emergency)
dat += "<A href='?src=[REF(src)];emergency=1'>Emergency: Security</A><BR>"
dat += "<A href='?src=[REF(src)];emergency=2'>Emergency: Engineering</A><BR>"
dat += "<A href='?src=[REF(src)];emergency=3'>Emergency: Medical</A><BR><BR>"
else
dat += "<B><font color='red'>[emergency] has been dispatched to this location.</font></B><BR><BR>"
dat += "<a href='?src=[REF(src)];setScreen=8'>View Messages</a> <br><br>"
if(announcementConsole)
dat += "<A href='?src=[REF(src)];setScreen=10'>Send Station-wide Announcement</A><BR><BR>"
if (silent)
dat += "Speaker <A href='?src=[REF(src)];setSilent=0'>OFF</A>"
else
dat += "Speaker <A href='?src=[REF(src)];setSilent=1'>ON</A>"
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
dat += "<a href='?src=[REF(src)];setScreen=1'>Request Assistance</a> <br>"
dat += "<a href='?src=[REF(src)];setScreen=2'>Request Supplies</a> <br>"
dat += "<a href='?src=[REF(src)];setScreen=3'>Relay Anonymous Information</a> <br><br>"
if(!emergency)
dat += "<a href='?src=[REF(src)];emergency=1'>Emergency: Security</a> <br>"
dat += "<a href='?src=[REF(src)];emergency=2'>Emergency: Engineering</a> <br>"
dat += "<a href='?src=[REF(src)];emergency=3'>Emergency: Medical</a> <br><br>"
else
dat += "<b><div class='bad'>[emergency] has been dispatched to this location.</div></b> <br><br>"
if(announcementConsole)
dat += "<a href='?src=[REF(src)];setScreen=10'>Send Station-wide Announcement</a> <br><br>"
if(silent)
dat += "Speaker <a href='?src=[REF(src)];setSilent=0'>OFF</a>"
else
dat += "Speaker <a href='?src=[REF(src)];setSilent=1'>ON</a>"
var/datum/browser/popup = new(user, "req_console", "[department] Requests Console", 450, 440)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/requests_console/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
add_fingerprint(usr)
if(href_list["write"])
dpt = ckey(reject_bad_text(href_list["write"])) //write contains the string of the receiving department's name
var/new_message = stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN)
if(new_message)
message = new_message
screen = 9
if (text2num(href_list["priority"]) < 2)
priority = -1
else
priority = text2num(href_list["priority"])
priority = text2num(href_list["priority"])
else
dpt = "";
msgVerified = ""
msgStamped = ""
screen = 0
priority = -1
priority = NORMAL_MESSAGE_PRIORITY //:salt:
if(href_list["writeAnnouncement"])
var/new_message = reject_bad_text(stripped_input(usr, "Write your message:", "Awaiting Input", "", MAX_MESSAGE_LEN))
if(new_message)
message = new_message
if (text2num(href_list["priority"]) < 2)
priority = -1
else
priority = text2num(href_list["priority"])
priority = text2num(href_list["priority"])
else
message = ""
announceAuth = FALSE
@@ -296,106 +306,116 @@ GLOBAL_LIST_EMPTY(allConsoles)
if(href_list["sendAnnouncement"])
if(!announcementConsole)
updateUsrDialog()
return
if(isliving(usr))
var/mob/living/L = usr
message = L.treat_message(message)
minor_announce(message, "[department] Announcement:")
GLOB.news_network.SubmitArticle(message, department, "Station Announcements", null)
usr.log_talk(message, LOG_SAY, tag="station announcement from [src]")
usr.log_talk(message, LOG_SAY, tag = "station announcement from [src]")
message_admins("[ADMIN_LOOKUPFLW(usr)] has made a station announcement from [src] at [AREACOORD(usr)].")
announceAuth = FALSE
message = ""
screen = 0
if(href_list["emergency"])
if(!emergency)
var/radio_freq
switch(text2num(href_list["emergency"]))
if(1) //Security
radio_freq = FREQ_SECURITY
emergency = "Security"
if(2) //Engineering
radio_freq = FREQ_ENGINEERING
emergency = "Engineering"
if(3) //Medical
radio_freq = FREQ_MEDICAL
emergency = "Medical"
if(radio_freq)
Radio.set_frequency(radio_freq)
Radio.talk_into(src,"[emergency] emergency in [department]!!",radio_freq)
update_icon()
addtimer(CALLBACK(src, .proc/clear_emergency), 3000)
if(emergency) //already has an emergency? do not continue
updateUsrDialog()
return
if( href_list["department"] && message )
var/log_msg = message
var/radio_freq
switch(text2num(href_list["emergency"]))
if(1) //Security
radio_freq = FREQ_SECURITY
emergency = "Security"
if(2) //Engineering
radio_freq = FREQ_ENGINEERING
emergency = "Engineering"
if(3) //Medical
radio_freq = FREQ_MEDICAL
emergency = "Medical"
if(radio_freq)
Radio.set_frequency(radio_freq)
Radio.talk_into(src, "[emergency] emergency in [department]!!", radio_freq)
update_icon()
addtimer(CALLBACK(src, .proc/clear_emergency), 5 MINUTES)
if(href_list["department"] && message)
var/sending = message
sending += "<br>"
if (msgVerified)
sending += msgVerified
sending += "<br>"
if (msgStamped)
sending += msgStamped
sending += "<br>"
screen = 7 //if it's successful, this will get overrwritten (7 = unsufccessfull, 6 = successfull)
if (sending)
var/pass = FALSE
var/datum/data_rc_msg/log = new(href_list["department"], department, log_msg, msgStamped, msgVerified, priority)
for (var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
if (MS.toggled)
MS.rc_msgs += log
pass = TRUE
if(msgVerified)
sending += "<span class='good'><b>[msgVerified]</b></span> <br>"
if(msgStamped)
sending += "<span class='boldnotice'>[msgStamped]</span> <br>"
//so you're telling me is you cheated, by making fail happen, then quickly replacing it with 6
if(pass)
var/radio_freq = 0
switch(href_list["department"])
if("bridge")
radio_freq = FREQ_COMMAND
if("medbay")
radio_freq = FREQ_MEDICAL
if("science")
radio_freq = FREQ_SCIENCE
if("engineering")
radio_freq = FREQ_ENGINEERING
if("security")
radio_freq = FREQ_SECURITY
if("cargobay" || "mining")
radio_freq = FREQ_SUPPLY
Radio.set_frequency(radio_freq)
var/authentic
if(msgVerified || msgStamped)
authentic = " (Authenticated)"
var/workingServer = FALSE
var/datum/data_rc_msg/log = new(href_list["department"], department, message, msgStamped, msgVerified, priority)
for(var/obj/machinery/telecomms/message_server/MS in GLOB.telecomms_list)
if(MS.on) //on does the calculations. why would this server still work even though the apc is off??
LAZYADD(MS.rc_msgs, log)
workingServer = TRUE
var/alert = ""
for (var/obj/machinery/requests_console/Console in GLOB.allConsoles)
if (ckey(Console.department) == ckey(href_list["department"]))
switch(priority)
if(2) //High priority
alert = "PRIORITY Alert in [department][authentic]"
Console.createmessage(src, alert, sending, 2, 1)
if(3) // Extreme Priority
alert = "EXTREME PRIORITY Alert from [department][authentic]"
Console.createmessage(src, alert , sending, 3, 1)
else // Normal priority
alert = "Message from [department][authentic]"
Console.createmessage(src, alert , sending, 1, 1)
screen = 6
if(!workingServer)
screen = 7
say("NOTICE: No server detected! Please contact your local engineering team.")
updateUsrDialog()
return
if(radio_freq)
Radio.talk_into(src, "[alert]: <i>[message]</i>", radio_freq)
var/radio_freq = 0
switch(href_list["department"])
if("bridge")
radio_freq = FREQ_COMMAND
if("medbay")
radio_freq = FREQ_MEDICAL
if("science")
radio_freq = FREQ_SCIENCE
if("engineering")
radio_freq = FREQ_ENGINEERING
if("security")
radio_freq = FREQ_SECURITY
if("cargobay" || "mining")
radio_freq = FREQ_SUPPLY
Radio.set_frequency(radio_freq)
switch(priority)
if(2)
messages += "<span class='bad'>High Priority</span><BR><b>To:</b> [dpt]<BR>[sending]"
else
messages += "<b>To: [dpt]</b><BR>[sending]"
var/authentic = ""
if(msgVerified || msgStamped)
authentic = " (Authenticated)"
var/alert = ""
for(var/obj/machinery/requests_console/C in GLOB.allConsoles)
if(ckey(C.department) != ckey(href_list["department"]))
continue
switch(priority)
if(HIGH_MESSAGE_PRIORITY) //High priority
alert = "PRIORITY Alert from [department][authentic]"
C.createmessage(src, alert, sending, HIGH_MESSAGE_PRIORITY)
if(EXTREME_MESSAGE_PRIORITY) // Extreme Priority
alert = "EXTREME PRIORITY Alert from [department][authentic]"
C.createmessage(src, alert, sending, EXTREME_MESSAGE_PRIORITY)
else // Normal priority
alert = "Message from [department][authentic]"
C.createmessage(src, alert, sending, NORMAL_MESSAGE_PRIORITY)
screen = 6 //if it ever gets here that means (c.department == href_ls["dept"])
if(radio_freq)
Radio.talk_into(src, "[alert]: <i>[message]</i>", radio_freq)
//log to (this)
switch(priority)
if(HIGH_MESSAGE_PRIORITY)
messages += "<span class='bad'>High Priority</span><br><b>To:</b> [dpt]<br>[sending]"
if(EXTREME_MESSAGE_PRIORITY)
messages += "<span class='bad'>!!!Extreme Priority!!!</span><br><b>To:</b> [dpt]<br>[sending]"
else
say("NOTICE: No server detected!")
messages += "<b>To:</b> [dpt]<br>[sending]"
//Handle screen switching
switch(text2num(href_list["setScreen"]))
if(null) //skip
updateUsrDialog()
return
if(1) //req. assistance
screen = 1
if(2) //req. supplies
@@ -423,16 +443,14 @@ GLOBAL_LIST_EMPTY(allConsoles)
msgVerified = ""
msgStamped = ""
message = ""
priority = -1
priority = NORMAL_MESSAGE_PRIORITY // :salt:
screen = 0
//Handle silencing the console
switch( href_list["setSilent"] )
if(null) //skip
if("1")
silent = TRUE
else
silent = FALSE
if(href_list["setSilent"] == "1")
silent = TRUE
else
silent = FALSE
updateUsrDialog()
return
@@ -457,31 +475,32 @@ GLOBAL_LIST_EMPTY(allConsoles)
linkedsender = source
capitalize(title)
switch(priority)
if(2) //High priority
if(HIGH_MESSAGE_PRIORITY) //High priority
if(newmessagepriority < HIGH_MESSAGE_PRIORITY)
newmessagepriority = HIGH_MESSAGE_PRIORITY
update_icon()
if(!silent)
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<span class='bad'>High Priority</span><BR><b>From:</b> [linkedsender]<BR>[message]"
messages += "<span class='bad'>High Priority</span><br><b>From:</b> [linkedsender]<br>[message]" //the fuck is this not being sent
if(3) // Extreme Priority
if(EXTREME_MESSAGE_PRIORITY) // Extreme Priority
if(newmessagepriority < EXTREME_MESSAGE_PRIORITY)
newmessagepriority = EXTREME_MESSAGE_PRIORITY
update_icon()
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<span class='bad'>!!!Extreme Priority!!!</span><BR><b>From:</b> [linkedsender]<BR>[message]"
//we ignore the silent option because this is !!!IMPORTANT!!!
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<span class='bad'><b>!!!Extreme Priority!!!</span></b><br><b>From:</b> [linkedsender]<br>[message]"
else // Normal priority
if(newmessagepriority < NORMAL_MESSAGE_PRIORITY)
newmessagepriority = NORMAL_MESSAGE_PRIORITY
update_icon()
if(!src.silent)
if(!silent)
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
say(title)
messages += "<b>From:</b> [linkedsender]<BR>[message]"
messages += "<b>From:</b> [linkedsender]<br>[message]"
/obj/machinery/requests_console/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/crowbar))
@@ -505,23 +524,26 @@ GLOBAL_LIST_EMPTY(allConsoles)
to_chat(user, "<span class='warning'>You must open the maintenance panel first!</span>")
return
var/obj/item/card/id/ID = O.GetID()
if(ID)
if(istype(O, /obj/item/card/id))
var/obj/item/card/id/ID = O.GetID()
if(!ID)
return
if(screen == 9)
msgVerified = "<font color='green'><b>Verified by [ID.registered_name] ([ID.assignment])</b></font>"
msgVerified = "Verified by [ID.registered_name] ([ID.assignment])"
updateUsrDialog()
if(screen == 10)
if (ACCESS_RC_ANNOUNCE in ID.access)
if(ACCESS_RC_ANNOUNCE in ID.access)
announceAuth = TRUE
else
announceAuth = FALSE
to_chat(user, "<span class='warning'>You are not authorized to send announcements!</span>")
updateUsrDialog()
return
if (istype(O, /obj/item/stamp))
if(istype(O, /obj/item/stamp))
if(screen == 9)
var/obj/item/stamp/T = O
msgStamped = "<span class='boldnotice'>Stamped with the [T.name]</span>"
msgStamped = "Stamped with the [T.name]"
updateUsrDialog()
return
return ..()
@@ -0,0 +1,33 @@
/obj/machinery/shuttle
name = "shuttle component"
desc = "Something for shuttles."
density = TRUE
obj_integrity = 250
max_integrity = 250
icon = 'icons/turf/shuttle.dmi'
icon_state = "burst_plasma"
idle_power_usage = 150
circuit = /obj/item/circuitboard/machine/shuttle/engine
var/icon_state_closed = "burst_plasma"
var/icon_state_open = "burst_plasma_open"
var/icon_state_off = "burst_plasma_off"
/obj/machinery/shuttle/Initialize()
. = ..()
GLOB.custom_shuttle_machines += src
/obj/machinery/shuttle/Destroy()
. = ..()
GLOB.custom_shuttle_machines -= src
/obj/machinery/shuttle/attackby(obj/item/I, mob/living/user, params)
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
return
if(default_pry_open(I))
return
if(panel_open)
if(default_change_direction_wrench(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
@@ -0,0 +1,138 @@
//-----------------------------------------------
//-------------Engine Thrusters------------------
//-----------------------------------------------
#define ENGINE_HEAT_TARGET 600
#define ENGINE_HEATING_POWER 5000000
/obj/machinery/shuttle/engine
name = "shuttle thruster"
desc = "A thruster for shuttles."
density = TRUE
obj_integrity = 250
max_integrity = 250
icon = 'icons/turf/shuttle.dmi'
icon_state = "burst_plasma"
idle_power_usage = 150
circuit = /obj/item/circuitboard/machine/shuttle/engine
var/thrust = 0
var/fuel_use = 0
var/bluespace_capable = TRUE
var/cooldown = 0
var/thruster_active = FALSE
var/datum/weakref/attached_heater
/obj/machinery/shuttle/engine/plasma
name = "plasma thruster"
desc = "A thruster that burns plasma stored in an adjacent plasma thruster heater."
icon_state = "burst_plasma"
icon_state_off = "burst_plasma_off"
idle_power_usage = 0
circuit = /obj/item/circuitboard/machine/shuttle/engine/plasma
thrust = 25
fuel_use = 0.24
bluespace_capable = FALSE
cooldown = 45
/obj/machinery/shuttle/engine/void
name = "void thruster"
desc = "A thruster using technology to breach voidspace for propulsion."
icon_state = "burst_void"
icon_state_off = "burst_void"
icon_state_closed = "burst_void"
icon_state_open = "burst_void_open"
idle_power_usage = 0
circuit = /obj/item/circuitboard/machine/shuttle/engine/void
thrust = 400
fuel_use = 0
bluespace_capable = TRUE
cooldown = 90
/obj/machinery/shuttle/engine/Initialize()
. = ..()
check_setup()
/obj/machinery/shuttle/engine/on_construction()
. = ..()
check_setup()
/obj/machinery/shuttle/engine/Destroy()
attached_heater = FALSE
thruster_active = FALSE
return ..()
/obj/machinery/shuttle/engine/proc/check_setup()
if(!anchored)
attached_heater = null
update_engine()
return
var/heater_turf
switch(dir)
if(NORTH)
heater_turf = get_offset_target_turf(src, 0, 1)
if(SOUTH)
heater_turf = get_offset_target_turf(src, 0, -1)
if(EAST)
heater_turf = get_offset_target_turf(src, 1, 0)
if(WEST)
heater_turf = get_offset_target_turf(src, -1, 0)
if(!heater_turf)
attached_heater = null
update_engine()
return
attached_heater = null
for(var/obj/machinery/atmospherics/components/unary/shuttle/heater/as_heater in heater_turf)
if(as_heater.dir != dir)
continue
if(as_heater.panel_open)
continue
if(!as_heater.anchored)
continue
attached_heater = WEAKREF(as_heater)
break
update_engine()
return
/obj/machinery/shuttle/engine/proc/update_engine()
if(!attached_heater)
icon_state = icon_state_off
thruster_active = FALSE
return
var/obj/machinery/atmospherics/components/unary/shuttle/heater/resolved_heater = attached_heater.resolve()
if(panel_open)
thruster_active = FALSE
else if(resolved_heater?.hasFuel(1))
icon_state = icon_state_closed
thruster_active = TRUE
else
thruster_active = FALSE
icon_state = icon_state_off
return
/obj/machinery/shuttle/engine/void/update_engine()
if(panel_open)
thruster_active = FALSE
return
thruster_active = TRUE
icon_state = icon_state_closed
return
//Thanks to spaceheater.dm for inspiration :)
/obj/machinery/shuttle/engine/proc/fireEngine()
var/turf/heatTurf = loc
if(!heatTurf)
return
var/datum/gas_mixture/env = heatTurf.return_air()
var/heat_cap = env.heat_capacity()
var/req_power = abs(env.return_temperature() - ENGINE_HEAT_TARGET) * heat_cap
req_power = min(req_power, ENGINE_HEATING_POWER)
var/deltaTemperature = req_power / heat_cap
if(deltaTemperature < 0)
return
env.temperature += deltaTemperature
air_update_turf()
/obj/machinery/shuttle/engine/default_change_direction_wrench(mob/user, obj/item/I)
. = ..()
update_engine()
@@ -0,0 +1,132 @@
//-----------------------------------------------
//--------------Engine Heaters-------------------
//This uses atmospherics, much like a thermomachine,
//but instead of changing temp, it stores plasma and uses
//it for the engine.
//-----------------------------------------------
/obj/machinery/atmospherics/components/unary/shuttle
name = "shuttle atmospherics device"
desc = "This does something to do with shuttle atmospherics"
icon_state = "heater"
icon = 'icons/turf/shuttle.dmi'
/obj/machinery/atmospherics/components/unary/shuttle/heater
name = "engine heater"
desc = "Directs energy into compressed particles in order to power an attached thruster."
icon_state = "heater_pipe"
var/icon_state_closed = "heater_pipe"
var/icon_state_open = "heater_pipe_open"
var/icon_state_off = "heater_pipe"
idle_power_usage = 50
circuit = /obj/item/circuitboard/machine/shuttle/heater
density = TRUE
max_integrity = 400
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 30)
layer = OBJ_LAYER
showpipe = TRUE
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
var/gas_type = /datum/gas/plasma
var/efficiency_multiplier = 1
var/gas_capacity = 0
/obj/machinery/atmospherics/components/unary/shuttle/heater/New()
. = ..()
GLOB.custom_shuttle_machines += src
SetInitDirections()
update_adjacent_engines()
updateGasStats()
/obj/machinery/atmospherics/components/unary/shuttle/heater/Destroy()
. = ..()
update_adjacent_engines()
GLOB.custom_shuttle_machines -= src
/obj/machinery/atmospherics/components/unary/shuttle/heater/on_construction()
..(dir, dir)
SetInitDirections()
update_adjacent_engines()
/obj/machinery/atmospherics/components/unary/shuttle/heater/default_change_direction_wrench(mob/user, obj/item/I)
if(!..())
return FALSE
SetInitDirections()
var/obj/machinery/atmospherics/node = nodes[1]
if(node)
node.disconnect(src)
nodes[1] = null
if(!parents[1])
return
nullifyPipenet(parents[1])
atmosinit()
node = nodes[1]
if(node)
node.atmosinit()
node.addMember(src)
build_network()
return TRUE
/obj/machinery/atmospherics/components/unary/shuttle/heater/RefreshParts()
var/cap = 0
var/eff = 0
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
cap += M.rating
for(var/obj/item/stock_parts/micro_laser/L in component_parts)
eff += L.rating
gas_capacity = 5000 * ((cap - 1) ** 2) + 1000
efficiency_multiplier = round(((eff / 2) / 2.8) ** 2, 0.1)
updateGasStats()
/obj/machinery/atmospherics/components/unary/shuttle/heater/examine(mob/user)
. = ..()
var/datum/gas_mixture/air_contents = airs[1]
. += "The engine heater's gas dial reads [air_contents.return_volume()] liters in internal tank.<br>"
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/updateGasStats()
var/datum/gas_mixture/air_contents = airs[1]
if(!air_contents)
return
air_contents.volume = gas_capacity
air_contents.temperature = T20C
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/hasFuel(var/required)
var/datum/gas_mixture/air_contents = airs[1]
var/moles = air_contents.total_moles()
return moles >= required
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/consumeFuel(var/amount)
var/datum/gas_mixture/air_contents = airs[1]
air_contents.remove(amount)
return
/obj/machinery/atmospherics/components/unary/shuttle/heater/attackby(obj/item/I, mob/living/user, params)
update_adjacent_engines()
if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_closed, I))
return
if(default_pry_open(I))
return
if(panel_open)
if(default_change_direction_wrench(user, I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/update_adjacent_engines()
var/engine_turf
switch(dir)
if(NORTH)
engine_turf = get_offset_target_turf(src, 0, -1)
if(SOUTH)
engine_turf = get_offset_target_turf(src, 0, 1)
if(EAST)
engine_turf = get_offset_target_turf(src, -1, 0)
if(WEST)
engine_turf = get_offset_target_turf(src, 1, 0)
if(!engine_turf)
return
for(var/obj/machinery/shuttle/engine/E in engine_turf)
E.check_setup()
+1 -1
View File
@@ -290,7 +290,7 @@
if("shuttle_id")
update()
/obj/machinery/status_display/shuttle/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
/obj/machinery/status_display/shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
if (port && (shuttle_id == initial(shuttle_id) || override))
shuttle_id = port.id
update()
@@ -1,215 +1,164 @@
/*
The log console for viewing the entire telecomms
network log
*/
/obj/machinery/computer/telecomms/server
name = "telecommunications server monitoring console"
icon_screen = "comm_logs"
desc = "Has full access to all details and record of the telecommunications network it's monitoring."
circuit = /obj/item/circuitboard/computer/comm_server
req_access = list(ACCESS_TCOMSAT)
var/screen = 0 // the screen number:
var/list/servers = list() // the servers located by the computer
var/obj/machinery/telecomms/server/SelectedServer
var/list/machinelist = list() // the servers located by the computer
var/obj/machinery/telecomms/server/SelectedMachine = null
var/network = "NULL" // the network to probe
var/temp = "" // temporary feedback messages
var/notice = ""
var/universal_translate = FALSE // set to TRUE(1) if it can translate nonhuman speech
var/universal_translate = 0 // set to 1 if it can translate nonhuman speech
/obj/machinery/computer/telecomms/server/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "tcommsserver", "Telecomms Server Monitor", 575, 400, master_ui, state)
ui.open()
req_access = list(ACCESS_TCOMSAT)
circuit = /obj/item/circuitboard/computer/comm_server
/obj/machinery/computer/telecomms/server/ui_data(mob/user)
var/list/data_out = list()
data_out["network"] = network
data_out["notice"] = notice
/obj/machinery/computer/telecomms/server/ui_interact(mob/user)
. = ..()
var/dat = "<TITLE>Telecommunication Server Monitor</TITLE><center><b>Telecommunications Server Monitor</b></center>"
data_out["servers"] = list()
for(var/obj/machinery/telecomms/server/T in machinelist)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["servers"] += list(data)
data_out["servers"] = sortList(data_out["servers"]) //a-z sort
switch(screen)
if(!SelectedMachine) //null is bad.
data_out["selected"] = null //but in js, null is good.
return data_out
data_out["selected"] = list(
name = SelectedMachine.name,
id = SelectedMachine.id,
status = SelectedMachine.on,
traffic = SelectedMachine.totaltraffic, //note: total traffic, not traffic!
ref = REF(SelectedMachine)
)
data_out["selected_logs"] = list()
// --- Main Menu ---
if(!LAZYLEN(SelectedMachine.log_entries))
return data_out
for(var/datum/comm_log_entry/C in SelectedMachine.log_entries)
var/list/data = list()
data["name"] = C.name //name of the file
data["ref"] = REF(C)
data["input_type"] = C.input_type //type of input ("Speech File" | "Execution Error").
if(0)
dat += "<br>[temp]<br>"
dat += "<br>Current Network: <a href='?src=[REF(src)];network=1'>[network]</a><br>"
if(servers.len)
dat += "<br>Detected Telecommunication Servers:<ul>"
for(var/obj/machinery/telecomms/T in servers)
dat += "<li><a href='?src=[REF(src)];viewserver=[T.id]'>[REF(T)] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=[REF(src)];operation=release'>\[Flush Buffer\]</a>"
if(C.input_type == "Speech File") //there is a reason why this is not a switch.
data["source"] = list(
name = C.parameters["name"], //name of the mob | obj
job = C.parameters["job"] //job of the mob | obj
)
// -- Determine race of orator --
var/mobtype = C.parameters["mobtype"]
var/race // The actual race of the mob
if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
race = "Humanoid"
else if(ispath(mobtype, /mob/living/simple_animal/slime))
race = "Slime" // NT knows a lot about slimes, but not aliens. Can identify slimes
else if(ispath(mobtype, /mob/living/carbon/monkey))
race = "Monkey"
else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
race = "Artificial Life" // sometimes M gets deleted prematurely for AIs... just check the job
else if(isobj(mobtype))
race = "Machinery"
else if(ispath(mobtype, /mob/living/simple_animal))
race = "Domestic Animal"
else
dat += "<br>No servers detected. Scan for servers: <a href='?src=[REF(src)];operation=scan'>\[Scan\]</a>"
race = "Unidentifiable"
data["race"] = race
// based on [/atom/movable/proc/lang_treat]
var/message = C.parameters["message"]
var/language = C.parameters["language"]
// --- Viewing Server ---
if(universal_translate || user.has_language(language))
message = message
else if(!user.has_language(language))
var/datum/language/D = GLOB.language_datum_instances[language]
message = D.scramble(message)
else if(language)
message = "(unintelligible)"
if(1)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=[REF(src)];operation=mainmenu'>\[Main Menu\]</a> <a href='?src=[REF(src)];operation=refresh'>\[Refresh\]</a></center>"
dat += "<br>Current Network: [network]"
dat += "<br>Selected Server: [SelectedServer.id]"
data["message"] = message
if(SelectedServer.totaltraffic >= 1024)
dat += "<br>Total recorded traffic: [round(SelectedServer.totaltraffic / 1024)] Terrabytes<br><br>"
else
dat += "<br>Total recorded traffic: [SelectedServer.totaltraffic] Gigabytes<br><br>"
else if(C.input_type == "Execution Error")
data["message"] = C.parameters["message"]
else
data["message"] = "(unintelligible)"
data_out["selected_logs"] += list(data)
return data_out
dat += "Stored Logs: <ol>"
var/i = 0
for(var/datum/comm_log_entry/C in SelectedServer.log_entries)
i++
// If the log is a speech file
if(C.input_type == "Speech File")
dat += "<li><font color = #008F00>[C.name]</font> <font color = #FF0000><a href='?src=[REF(src)];delete=[i]'>\[X\]</a></font><br>"
// -- Determine race of orator --
var/mobtype = C.parameters["mobtype"]
var/race // The actual race of the mob
if(ispath(mobtype, /mob/living/carbon/human) || ispath(mobtype, /mob/living/brain))
race = "Humanoid"
// NT knows a lot about slimes, but not aliens. Can identify slimes
else if(ispath(mobtype, /mob/living/simple_animal/slime))
race = "Slime"
else if(ispath(mobtype, /mob/living/carbon/monkey))
race = "Monkey"
// sometimes M gets deleted prematurely for AIs... just check the job
else if(ispath(mobtype, /mob/living/silicon) || C.parameters["job"] == "AI")
race = "Artificial Life"
else if(isobj(mobtype))
race = "Machinery"
else if(ispath(mobtype, /mob/living/simple_animal))
race = "Domestic Animal"
else
race = "<i>Unidentifiable</i>"
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
dat += "<u><font color = #18743E>Source</font></u>: [C.parameters["name"]] (Job: [C.parameters["job"]])<br>"
dat += "<u><font color = #18743E>Class</font></u>: [race]<br>"
var/message = C.parameters["message"]
var/language = C.parameters["language"]
// based on [/atom/movable/proc/lang_treat]
if (universal_translate || user.has_language(language))
message = "\"[message]\""
else if (!user.has_language(language))
var/datum/language/D = GLOB.language_datum_instances[language]
message = "\"[D.scramble(message)]\""
else if (language)
message = "<i>(unintelligible)</i>"
dat += "<u><font color = #18743E>Contents</font></u>: [message]<br>"
dat += "</li><br>"
else if(C.input_type == "Execution Error")
dat += "<li><font color = #990000>[C.name]</font> <a href='?src=[REF(src)];delete=[i]'>\[X\]</a><br>"
dat += "<u><font color = #787700>Error</font></u>: \"[C.parameters["message"]]\"<br>"
dat += "</li><br>"
else
dat += "<li><font color = #000099>[C.name]</font> <a href='?src=[REF(src)];delete=[i]'>\[X\]</a><br>"
dat += "<u><font color = #18743E>Data type</font></u>: [C.input_type]<br>"
dat += "<u><font color = #18743E>Contents</font></u>: <i>(unintelligible)</i><br>"
dat += "</li><br>"
dat += "</ol>"
user << browse(dat, "window=comm_monitor;size=575x400")
onclose(user, "server_control")
temp = ""
return
/obj/machinery/computer/telecomms/server/Topic(href, href_list)
/obj/machinery/computer/telecomms/server/ui_act(action, params)
if(..())
return
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["viewserver"])
screen = 1
for(var/obj/machinery/telecomms/T in servers)
if(T.id == href_list["viewserver"])
SelectedServer = T
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
servers = list()
screen = 0
if("mainmenu")
screen = 0
if("scan")
if(servers.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
else
for(var/obj/machinery/telecomms/server/T in urange(25, src))
if(T.network == network)
servers.Add(T)
if(!servers.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE SERVERS IN \[[network]\] -</font color>"
else
temp = "<font color = #336699>- [servers.len] SERVERS PROBED & BUFFERED -</font color>"
screen = 0
if(href_list["delete"])
if(!src.allowed(usr) && !(obj_flags & EMAGGED))
to_chat(usr, "<span class='danger'>ACCESS DENIED.</span>")
switch(action)
if("mainmenu")
SelectedMachine = null
notice = ""
return
if("release")
machinelist = list()
notice = ""
return
if("network") //network change, flush the selected machine and buffer
var/newnet = sanitize(sanitize_text(params["value"], network))
if(length(newnet) > 15) //i'm looking at you, you href fuckers
notice = "FAILED: Network tag string too lengthy"
return
network = newnet
SelectedMachine = null
machinelist = list()
return
if("probe")
if(LAZYLEN(machinelist) > 0)
notice = "FAILED: Cannot probe when buffer full"
return
for(var/obj/machinery/telecomms/T in GLOB.telecomms_list) //telecomms just went global!
if(T.network == network)
LAZYADD(machinelist, T)
if(SelectedServer)
if(!LAZYLEN(machinelist))
notice = "FAILED: Unable to locate network entities in \[[network]\]"
return
if("viewmachine")
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == params["value"])
SelectedMachine = T
break
if("delete")
if(!src.allowed(usr) && !CHECK_BITFIELD(obj_flags, EMAGGED))
to_chat(usr, "<span class='danger'>ACCESS DENIED.</span>")
return
var/datum/comm_log_entry/D = SelectedServer.log_entries[text2num(href_list["delete"])]
temp = "<font color = #336699>- DELETED ENTRY: [D.name] -</font color>"
SelectedServer.log_entries.Remove(D)
if(!SelectedMachine)
notice = "ALERT: No server detected. Server may be nonresponsive."
return
var/datum/comm_log_entry/D = locate(params["value"])
if(!istype(D))
notice = "NOTICE: Object not found"
return
notice = "Deleted entry: [D.name]"
LAZYREMOVE(SelectedMachine.log_entries, D)
qdel(D)
else
temp = "<font color = #D70B00>- FAILED: NO SELECTED MACHINE -</font color>"
if(href_list["network"])
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
if(newnet && ((usr in range(1, src)) || hasSiliconAccessInArea(usr)))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font color>"
else
network = newnet
screen = 0
servers = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
updateUsrDialog()
return
/obj/machinery/computer/telecomms/server/attackby()
. = ..()
updateUsrDialog()
+315 -382
View File
@@ -3,241 +3,360 @@
Lets you read PDA and request console messages.
*/
#define LINKED_SERVER_NONRESPONSIVE (!linkedServer || (linkedServer.stat & (NOPOWER|BROKEN)))
// The monitor itself.
/obj/machinery/computer/message_monitor
name = "message monitor console"
desc = "Used to monitor the crew's PDA messages, as well as request console messages."
icon_screen = "comm_logs"
circuit = /obj/item/circuitboard/computer/message_monitor
//Server linked to.
//Servers, and server linked to.
var/network = "tcommsat" // the network to probe
var/list/machinelist = list() // the servers located by the computer
var/obj/machinery/telecomms/message_server/linkedServer = null
//Sparks effect - For emag
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
//Messages - Saves me time if I want to change something.
var/noserver = "<span class='alert'>ALERT: No server detected.</span>"
var/incorrectkey = "<span class='warning'>ALERT: Incorrect decryption key!</span>"
var/defaultmsg = "<span class='notice'>Welcome. Please select an option.</span>"
var/rebootmsg = "<span class='warning'>%$&(: Critical %$$@ Error // !RestArting! <lOadiNg backUp iNput ouTput> - ?pLeaSe wAit!</span>"
var/noserver = "ALERT: No server detected. Server may be nonresponsive."
var/incorrectkey = "ALERT: Incorrect decryption key!"
var/rebootmsg = "%$(:SYS&EM INTRN@L ACfES VIOLTIa█ DEtE₡TED! Ree3ARcinG A█ BAaKUP RdSTRE PbINT \[0xcff32ca/ - PLfASE aAIT"
//Computer properties
var/screen = 0 // 0 = Main menu, 1 = Message Logs, 2 = Hacked screen, 3 = Custom Message
var/hacking = FALSE // Is it being hacked into by the AI/Cyborg
var/message = "<span class='notice'>System bootup complete. Please select an option.</span>" // The message that shows on the main menu.
var/auth = FALSE // Are they authenticated?
var/optioncount = 7
var/message = "" // The message that shows on the main menu.
var/auth = FALSE // Are they authenticated?
// Custom Message Properties
var/customsender = "System Administrator"
var/obj/item/pda/customrecepient = null
var/customsender = "System Administrator"
var/customjob = "Admin"
var/custommessage = "This is a test, please ignore."
light_color = LIGHT_COLOR_GREEN
/obj/machinery/computer/message_monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "telepdalog", name, 727, 510, master_ui, state)
ui.open()
/obj/machinery/computer/message_monitor/ui_static_data(mob/user)
var/list/data_out = list()
if(!linkedServer || !auth) // no need building this if the usr isn't authenticated
return data_out
data_out["recon_logs"] = list()
var/i1 = 0
for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs)
i1++
if(i1 > 3000)
break
var/list/data = list(
sender = rc.send_dpt,
recipient = rc.rec_dpt,
message = rc.message,
stamp = rc.stamp,
auth = rc.id_auth,
priority = rc.priority,
ref = REF(rc)
)
data_out["recon_logs"] += list(data)
data_out["message_logs"] = list()
var/i2 = 0
for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs)
i2++
if(i2 > 3000)
break
var/list/data = list(
sender = pda.sender,
recipient = pda.recipient,
message = pda.message,
picture = pda.picture ? TRUE : FALSE,
ref = REF(pda)
)
data_out["message_logs"] += list(data)
return data_out
/obj/machinery/computer/message_monitor/ui_data(mob/user)
var/list/data_out = list()
data_out["notice"] = message
data_out["authenticated"] = auth
data_out["network"] = network
var/mob/living/silicon/S = user
if(istype(S) && S.hack_software)
data_out["canhack"] = TRUE
data_out["hacking"] = (hacking || CHECK_BITFIELD(obj_flags, EMAGGED))
if(hacking)
data_out["borg"] = ((isAI(user) || iscyborg(user)) && !CHECK_BITFIELD(obj_flags, EMAGGED)) //even borgs can't read emag
return data_out
data_out["servers"] = list()
for(var/obj/machinery/telecomms/message_server/T in machinelist)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["servers"] += list(data) // This /might/ cause an oom. Too bad!
data_out["servers"] = sortList(data_out["servers"]) //a-z sort
data_out["fake_message"] = list(
sender = customsender,
job = customjob,
message = custommessage,
recepient = (customrecepient ? "[customrecepient.owner] ([customrecepient.ownjob])" : null)
)
if(!linkedServer)
data_out["selected"] = null
return data_out
data_out["selected"] = list(
name = linkedServer.name,
id = linkedServer.id,
ref = REF(linkedServer),
status = (linkedServer.on && (linkedServer.toggled != FALSE)) // returns true if server is running
)
return data_out
/obj/machinery/computer/message_monitor/ui_act(action, params)
if(..())
return
switch(action)
if("mainmenu") //deselect
linkedServer = null
auth = FALSE
message = ""
return
if("release") //release server listing
machinelist = list()
message = ""
return
if("network") //network change, flush the selected machine and buffer, and de-auth them, if blank, return default
var/newnet = sanitize(sanitize_text(params["value"], network))
if(length(newnet) > 15) //i'm looking at you, you href fuckers
message = "FAILED: Network tag string too lengthy"
return
network = newnet
linkedServer = null
machinelist = list()
auth = FALSE
message = "NOTICE: Network change detected. Server disconnected, please re-authenticate."
return
if("probe") //probe network for the pda serbs
if(LAZYLEN(machinelist) > 0)
message = "FAILED: Cannot probe when buffer full"
return
for(var/obj/machinery/telecomms/message_server/T in GLOB.telecomms_list)
if(T.network == network)
LAZYADD(machinelist, T)
if(!LAZYLEN(machinelist))
message = "FAILED: Unable to locate network entities in \[[network]\]"
return
if("viewmachine") //selected but not authorized
for(var/obj/machinery/telecomms/message_server/T in machinelist)
if(T.id == params["value"])
linkedServer = T
break
if("auth")
if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
if(auth)
auth = FALSE
update_static_data(usr) //make sure it's cleared!
return
var/dkey = stripped_input(usr, "Please enter the decryption key.")
if(dkey && dkey == "")
return
if(linkedServer.decryptkey == dkey)
auth = TRUE
else
message = incorrectkey
update_static_data(usr)
if("change_auth")
if(!auth)
message = "WARNING: Auth failed! Please log in to change the password!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/dkey = stripped_input(usr, "Please enter the old decryption key.")
if(dkey && dkey != "")
if(linkedServer.decryptkey == dkey)
var/newkey = stripped_input(usr, "Please enter the new key (3 - 20 characters max):")
if(!ISINRANGE(length(newkey), 3, 20))
message = "NOTICE: Decryption key length too long/short!"
return
if(newkey && newkey != "")
linkedServer.decryptkey = newkey
message = "NOTICE: Decryption key set."
return
message = incorrectkey
if("hack")
if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/mob/living/silicon/S = usr
if(istype(S) && S.hack_software)
hacking = TRUE
//Time it takes to bruteforce is dependant on the password length.
addtimer(CALLBACK(src, .proc/BruteForce, usr), (10 SECONDS) * length(linkedServer.decryptkey))
if("del_log")
if(!auth)
message = "WARNING: Auth failed! Delete aborted!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/datum/data_ref = locate(params["ref"])
if(istype(data_ref, /datum/data_rc_msg))
LAZYREMOVE(linkedServer.rc_msgs, data_ref)
message = "NOTICE: Log Deleted!"
else if(istype(data_ref, /datum/data_pda_msg))
LAZYREMOVE(linkedServer.pda_msgs, data_ref)
message = "NOTICE: Log Deleted!"
else
message = "NOTICE: Log not found! It may have already been deleted"
update_static_data(usr)
if("clear_log")
if(!auth)
message = "WARNING: Auth failed! Delete aborted!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
var/what = params["value"]
if(what == "pda_logs")
linkedServer.pda_msgs = list()
if(what == "rc_msgs")
linkedServer.rc_msgs = list()
update_static_data(usr)
if("fake")
if(!auth)
message = "WARNING: Auth failed!"
return
else if(!(linkedServer.on && (linkedServer.toggled != FALSE)))
message = noserver
return
if("reset" in params)
ResetMessage()
return
if("send" in params)
if(isnull(customrecepient))
message = "NOTICE: No recepient selected!"
return
if(length(custommessage) <= 0 || custommessage == "")
message = "NOTICE: No message entered!"
return
if(length(customjob) <= 0 || customjob == "")
customjob = "Admin"
return
if(length(customsender) <= 0 || customsender == "")
customsender = "UNKNOWN"
//sanitize text!!!
var/datum/signal/subspace/pda/signal = new(src, list(
"name" = sanitize(customsender),
"job" = sanitize(customjob),
"message" = sanitize(custommessage),
"emojis" = TRUE,
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
))
// this will log the signal and transmit it to the target
linkedServer.receive_information(signal, null)
usr.log_message("(PDA: [name] | [usr.real_name]) sent \"[sanitize(custommessage)]\" to [signal.format_target()]", LOG_PDA)
message = ""
return
// Do not check if it's blank yet
// But do check if it's above our set limit (for people who manualy send hrefs at us!)
if("sender" in params)
var/S = params["sender"]
if(length(S) > MAX_NAME_LEN)
message = "FAILED: Job string too lengthy"
return
customsender = S
return
if("job" in params)
var/J = params["job"]
if(length(J) > 100)
message = "FAILED: Job string too lengthy"
return
customjob = J
return
if("message" in params)
var/M = params["message"]
if(length(M) > MAX_MESSAGE_LEN)
message = "FAILED: Message string too lengthy"
return
custommessage = M
return
if("recepient" in params)
// Get out list of viable PDAs
var/list/obj/item/pda/sendPDAs = get_viewable_pdas()
if(GLOB.PDAs && LAZYLEN(GLOB.PDAs) > 0)
customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
else
customrecepient = null
return
if("refresh")
update_static_data(usr)
/obj/machinery/computer/message_monitor/attackby(obj/item/O, mob/living/user, params)
if(istype(O, /obj/item/screwdriver) && (obj_flags & EMAGGED))
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
if(istype(O, /obj/item/screwdriver) && CHECK_BITFIELD(obj_flags, EMAGGED))
//Stops people from just unscrewing the monitor and putting it back to get the console working again.
//Why this though, you should make it emag to a board level. (i wont do it)
to_chat(user, "<span class='warning'>It is too hot to mess with!</span>")
else
return ..()
/obj/machinery/computer/message_monitor/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
if(CHECK_BITFIELD(obj_flags, EMAGGED))
return
if(isnull(linkedServer))
to_chat(user, "<span class='notice'>A no server error appears on the screen.</span>")
return
obj_flags |= EMAGGED
screen = 2
ENABLE_BITFIELD(obj_flags, EMAGGED)
spark_system.set_up(5, 0, src)
spark_system.start()
var/obj/item/paper/monitorkey/MK = new(loc, linkedServer)
// Will help make emagging the console not so easy to get away with.
MK.info += "<br><br><font color='red'>%@%(*$%&(&?*(%&/{}</font>"
var/time = 100 * length(linkedServer.decryptkey)
addtimer(CALLBACK(src, .proc/UnmagConsole), time)
message = rebootmsg
addtimer(CALLBACK(src, .proc/UnmagConsole), (10 SECONDS) * length(linkedServer.decryptkey))
//message = rebootmsg
return TRUE
/obj/machinery/computer/message_monitor/New()
. = ..()
GLOB.telecomms_list += src
/obj/machinery/computer/message_monitor/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/message_monitor/LateInitialize()
//Is the server isn't linked to a server, and there's a server available, default it to the first one in the list.
if(!linkedServer)
for(var/obj/machinery/telecomms/message_server/S in GLOB.telecomms_list)
linkedServer = S
break
/obj/machinery/computer/message_monitor/Destroy()
GLOB.telecomms_list -= src
. = ..()
/obj/machinery/computer/message_monitor/ui_interact(mob/living/user)
. = ..()
//If the computer is being hacked or is emagged, display the reboot message.
if(hacking || (obj_flags & EMAGGED))
message = rebootmsg
var/dat = "<center><font color='blue'[message]</font></center>"
if(auth)
dat += "<h4><dd><A href='?src=[REF(src)];auth=1'>&#09;<font color='green'>\[Authenticated\]</font></a>&#09;/"
dat += " Server Power: <A href='?src=[REF(src)];active=1'>[linkedServer && linkedServer.toggled ? "<font color='green'>\[On\]</font>":"<font color='red'>\[Off\]</font>"]</a></h4>"
else
dat += "<h4><dd><A href='?src=[REF(src)];auth=1'>&#09;<font color='red'>\[Unauthenticated\]</font></a>&#09;/"
dat += " Server Power: <u>[linkedServer && linkedServer.toggled ? "<font color='green'>\[On\]</font>":"<font color='red'>\[Off\]</font>"]</u></h4>"
if(hacking || (obj_flags & EMAGGED))
screen = 2
else if(!auth || LINKED_SERVER_NONRESPONSIVE)
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
screen = 0
switch(screen)
//Main menu
if(0)
//&#09; = TAB
var/i = 0
dat += "<dd><A href='?src=[REF(src)];find=1'>&#09;[++i]. Link To A Server</a></dd>"
if(auth)
if(LINKED_SERVER_NONRESPONSIVE)
dat += "<dd><A>&#09;ERROR: Server not found!</A><br></dd>"
else
dat += "<dd><A href='?src=[REF(src)];view_logs=1'>&#09;[++i]. View Message Logs </a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];view_requests=1'>&#09;[++i]. View Request Console Logs </a></br></dd>"
dat += "<dd><A href='?src=[REF(src)];clear_logs=1'>&#09;[++i]. Clear Message Logs</a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];clear_requests=1'>&#09;[++i]. Clear Request Console Logs</a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];pass=1'>&#09;[++i]. Set Custom Key</a><br></dd>"
dat += "<dd><A href='?src=[REF(src)];msg=1'>&#09;[++i]. Send Admin Message</a><br></dd>"
else
for(var/n = ++i; n <= optioncount; n++)
dat += "<dd><font color='blue'>&#09;[n]. ---------------</font><br></dd>"
var/mob/living/silicon/S = usr
if(istype(S) && S.hack_software)
//Malf/Traitor AIs can bruteforce into the system to gain the Key.
dat += "<dd><A href='?src=[REF(src)];hack=1'><i><font color='Red'>*&@#. Bruteforce Key</font></i></font></a><br></dd>"
else
dat += "<br>"
//Bottom message
if(!auth)
dat += "<br><hr><dd><span class='notice'>Please authenticate with the server in order to show additional options.</span>"
else
dat += "<br><hr><dd><span class='warning'>Reg, #514 forbids sending messages to a Head of Staff containing Erotic Rendering Properties.</span>"
//Message Logs
if(1)
var/index = 0
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];refresh=1'>Refresh</a></center><hr>"
dat += "<table border='1' width='100%'><tr><th width = '5%'>X</th><th width='15%'>Sender</th><th width='15%'>Recipient</th><th width='300px' word-wrap: break-word>Message</th></tr>"
for(var/datum/data_pda_msg/pda in linkedServer.pda_msgs)
index++
if(index > 3000)
break
// Del - Sender - Recepient - Message
// X - Al Green - Your Mom - WHAT UP!?
dat += "<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_logs=[REF(pda)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[pda.sender]</td><td width='15%'>[pda.recipient]</td><td width='300px'>[pda.message][pda.picture ? " <a href='byond://?src=[REF(pda)];photo=1'>(Photo)</a>":""]</td></tr>"
dat += "</table>"
//Hacking screen.
if(2)
if(isAI(user) || iscyborg(user))
dat += "Brute-forcing for server key.<br> It will take 20 seconds for every character that the password has."
dat += "In the meantime, this console can reveal your true intentions if you let someone access it. Make sure no humans enter the room during that time."
else
//It's the same message as the one above but in binary. Because robots understand binary and humans don't... well I thought it was clever.
dat += {"01000010011100100111010101110100011001010010110<br>
10110011001101111011100100110001101101001011011100110011<br>
10010000001100110011011110111001000100000011100110110010<br>
10111001001110110011001010111001000100000011010110110010<br>
10111100100101110001000000100100101110100001000000111011<br>
10110100101101100011011000010000001110100011000010110101<br>
10110010100100000001100100011000000100000011100110110010<br>
10110001101101111011011100110010001110011001000000110011<br>
00110111101110010001000000110010101110110011001010111001<br>
00111100100100000011000110110100001100001011100100110000<br>
10110001101110100011001010111001000100000011101000110100<br>
00110000101110100001000000111010001101000011001010010000<br>
00111000001100001011100110111001101110111011011110111001<br>
00110010000100000011010000110000101110011001011100010000<br>
00100100101101110001000000111010001101000011001010010000<br>
00110110101100101011000010110111001110100011010010110110<br>
10110010100101100001000000111010001101000011010010111001<br>
10010000001100011011011110110111001110011011011110110110<br>
00110010100100000011000110110000101101110001000000111001<br>
00110010101110110011001010110000101101100001000000111100<br>
10110111101110101011100100010000001110100011100100111010<br>
10110010100100000011010010110111001110100011001010110111<br>
00111010001101001011011110110111001110011001000000110100<br>
10110011000100000011110010110111101110101001000000110110<br>
00110010101110100001000000111001101101111011011010110010<br>
10110111101101110011001010010000001100001011000110110001<br>
10110010101110011011100110010000001101001011101000010111<br>
00010000001001101011000010110101101100101001000000111001<br>
10111010101110010011001010010000001101110011011110010000<br>
00110100001110101011011010110000101101110011100110010000<br>
00110010101101110011101000110010101110010001000000111010<br>
00110100001100101001000000111001001101111011011110110110<br>
10010000001100100011101010111001001101001011011100110011<br>
10010000001110100011010000110000101110100001000000111010<br>
001101001011011010110010100101110"}
//Fake messages
if(3)
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];Reset=1'>Reset</a></center><hr>"
dat += {"<table border='1' width='100%'>
<tr><td width='20%'><A href='?src=[REF(src)];select=Sender'>Sender</a></td>
<td width='20%'><A href='?src=[REF(src)];select=RecJob'>Sender's Job</a></td>
<td width='20%'><A href='?src=[REF(src)];select=Recepient'>Recipient</a></td>
<td width='300px' word-wrap: break-word><A href='?src=[REF(src)];select=Message'>Message</a></td></tr>"}
//Sender - Sender's Job - Recepient - Message
//Al Green- Your Dad - Your Mom - WHAT UP!?
dat += {"<tr><td width='20%'>[customsender]</td>
<td width='20%'>[customjob]</td>
<td width='20%'>[customrecepient ? customrecepient.owner : "NONE"]</td>
<td width='300px'>[custommessage]</td></tr>"}
dat += "</table><br><center><A href='?src=[REF(src)];select=Send'>Send</a>"
//Request Console Logs
if(4)
var/index = 0
/* data_rc_msg
X - 5%
var/rec_dpt = "Unspecified" //name of the person - 15%
var/send_dpt = "Unspecified" //name of the sender- 15%
var/message = "Blank" //transferred message - 300px
var/stamp = "Unstamped" - 15%
var/id_auth = "Unauthenticated" - 15%
var/priority = "Normal" - 10%
*/
dat += "<center><A href='?src=[REF(src)];back=1'>Back</a> - <A href='?src=[REF(src)];refresh=1'>Refresh</a></center><hr>"
dat += {"<table border='1' width='100%'><tr><th width = '5%'>X</th><th width='15%'>Sending Dep.</th><th width='15%'>Receiving Dep.</th>
<th width='300px' word-wrap: break-word>Message</th><th width='15%'>Stamp</th><th width='15%'>ID Auth.</th><th width='15%'>Priority.</th></tr>"}
for(var/datum/data_rc_msg/rc in linkedServer.rc_msgs)
index++
if(index > 3000)
break
// Del - Sender - Recepient - Message
// X - Al Green - Your Mom - WHAT UP!?
dat += {"<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_requests=[REF(rc)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[rc.send_dpt]</td>
<td width='15%'>[rc.rec_dpt]</td><td width='300px'>[rc.message]</td><td width='15%'>[rc.stamp]</td><td width='15%'>[rc.id_auth]</td><td width='15%'>[rc.priority]</td></tr>"}
dat += "</table>"
message = defaultmsg
var/datum/browser/popup = new(user, "hologram_console", name, 700, 700)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.open()
/obj/machinery/computer/message_monitor/proc/BruteForce(mob/user)
if(isnull(linkedServer))
to_chat(user, "<span class='warning'>Could not complete brute-force: Linked Server Disconnected!</span>")
@@ -245,10 +364,11 @@
var/currentKey = linkedServer.decryptkey
to_chat(user, "<span class='warning'>Brute-force completed! The key is '[currentKey]'.</span>")
hacking = FALSE
screen = 0 // Return the screen back to normal
message = ""
/obj/machinery/computer/message_monitor/proc/UnmagConsole()
obj_flags &= ~EMAGGED
DISABLE_BITFIELD(obj_flags, EMAGGED)
message = ""
/obj/machinery/computer/message_monitor/proc/ResetMessage()
customsender = "System Administrator"
@@ -256,199 +376,12 @@
custommessage = "This is a test, please ignore."
customjob = "Admin"
/obj/machinery/computer/message_monitor/Topic(href, href_list)
if(..())
return
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || hasSiliconAccessInArea(usr))
//Authenticate
if (href_list["auth"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
auth = FALSE
screen = 0
else
var/dkey = trim(input(usr, "Please enter the decryption key.") as text|null)
if(dkey && dkey != "")
if(linkedServer.decryptkey == dkey)
auth = TRUE
else
message = incorrectkey
//Turn the server on/off.
if (href_list["active"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
linkedServer.toggled = !linkedServer.toggled
//Find a server
if (href_list["find"])
var/list/message_servers = list()
for (var/obj/machinery/telecomms/message_server/M in GLOB.telecomms_list)
message_servers += M
if(message_servers.len > 1)
linkedServer = input(usr, "Please select a server.", "Select a server.", null) as null|anything in message_servers
message = "<span class='alert'>NOTICE: Server selected.</span>"
else if(message_servers.len > 0)
linkedServer = message_servers[1]
message = "<span class='notice'>NOTICE: Only Single Server Detected - Server selected.</span>"
else
message = noserver
//View the logs - KEY REQUIRED
if (href_list["view_logs"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
screen = 1
//Clears the logs - KEY REQUIRED
if (href_list["clear_logs"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
linkedServer.pda_msgs = list()
message = "<span class='notice'>NOTICE: Logs cleared.</span>"
//Clears the request console logs - KEY REQUIRED
if (href_list["clear_requests"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
linkedServer.rc_msgs = list()
message = "<span class='notice'>NOTICE: Logs cleared.</span>"
//Change the password - KEY REQUIRED
if (href_list["pass"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
var/dkey = stripped_input(usr, "Please enter the decryption key.")
if(dkey && dkey != "")
if(linkedServer.decryptkey == dkey)
var/newkey = trim(input(usr,"Please enter the new key (3 - 16 characters max):"))
if(length(newkey) <= 3)
message = "<span class='notice'>NOTICE: Decryption key too short!</span>"
else if(length(newkey) > 16)
message = "<span class='notice'>NOTICE: Decryption key too long!</span>"
else if(newkey && newkey != "")
linkedServer.decryptkey = newkey
message = "<span class='notice'>NOTICE: Decryption key set.</span>"
else
message = incorrectkey
//Hack the Console to get the password
if (href_list["hack"])
var/mob/living/silicon/S = usr
if(istype(S) && S.hack_software)
hacking = TRUE
screen = 2
//Time it takes to bruteforce is dependant on the password length.
spawn(100*length(linkedServer.decryptkey))
if(src && linkedServer && usr)
BruteForce(usr)
//Delete the log.
if (href_list["delete_logs"])
//Are they on the view logs screen?
if(screen == 1)
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else //if(istype(href_list["delete_logs"], /datum/data_pda_msg))
linkedServer.pda_msgs -= locate(href_list["delete_logs"])
message = "<span class='notice'>NOTICE: Log Deleted!</span>"
//Delete the request console log.
if (href_list["delete_requests"])
//Are they on the view logs screen?
if(screen == 4)
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else //if(istype(href_list["delete_logs"], /datum/data_pda_msg))
linkedServer.rc_msgs -= locate(href_list["delete_requests"])
message = "<span class='notice'>NOTICE: Log Deleted!</span>"
//Create a custom message
if (href_list["msg"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
screen = 3
//Fake messaging selection - KEY REQUIRED
if (href_list["select"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
screen = 0
else
switch(href_list["select"])
//Reset
if("Reset")
ResetMessage()
//Select Your Name
if("Sender")
customsender = stripped_input(usr, "Please enter the sender's name.") || customsender
//Select Receiver
if("Recepient")
//Get out list of viable PDAs
var/list/obj/item/pda/sendPDAs = get_viewable_pdas()
if(GLOB.PDAs && GLOB.PDAs.len > 0)
customrecepient = input(usr, "Select a PDA from the list.") as null|anything in sortNames(sendPDAs)
else
customrecepient = null
//Enter custom job
if("RecJob")
customjob = stripped_input(usr, "Please enter the sender's job.") || customjob
//Enter message
if("Message")
custommessage = stripped_input(usr, "Please enter your message.") || custommessage
//Send message
if("Send")
if(isnull(customsender) || customsender == "")
customsender = "UNKNOWN"
if(isnull(customrecepient))
message = "<span class='notice'>NOTICE: No recepient selected!</span>"
return attack_hand(usr)
if(isnull(custommessage) || custommessage == "")
message = "<span class='notice'>NOTICE: No message entered!</span>"
return attack_hand(usr)
var/datum/signal/subspace/pda/signal = new(src, list(
"name" = "[customsender]",
"job" = "[customjob]",
"message" = custommessage,
"emojis" = TRUE,
"targets" = list("[customrecepient.owner] ([customrecepient.ownjob])")
))
// this will log the signal and transmit it to the target
linkedServer.receive_information(signal, null)
usr.log_message("(PDA: [name] | [usr.real_name]) sent \"[custommessage]\" to [signal.format_target()]", LOG_PDA)
//Request Console Logs - KEY REQUIRED
if(href_list["view_requests"])
if(LINKED_SERVER_NONRESPONSIVE)
message = noserver
else if(auth)
screen = 4
if (href_list["back"])
screen = 0
return attack_hand(usr)
#undef LINKED_SERVER_NONRESPONSIVE
/obj/item/paper/monitorkey
name = "monitor decryption key"
/obj/item/paper/monitorkey/Initialize(mapload, obj/machinery/telecomms/message_server/server)
..()
if (server)
if(server)
print(server)
return INITIALIZE_HINT_NORMAL
else
@@ -460,7 +393,7 @@
add_overlay("paper_words")
/obj/item/paper/monitorkey/LateInitialize()
for (var/obj/machinery/telecomms/message_server/server in GLOB.telecomms_list)
if (server.decryptkey)
for(var/obj/machinery/telecomms/message_server/server in GLOB.telecomms_list)
if(server.decryptkey)
print(server)
break
@@ -1,4 +1,3 @@
/*
Telecomms monitor tracks the overall trafficing of a telecommunications network
and displays a heirarchy of linked machines.
@@ -10,117 +9,98 @@
icon_screen = "comm_monitor"
desc = "Monitors the details of the telecommunications network it's synced with."
var/screen = 0 // the screen number:
var/list/machinelist = list() // the machines located by the computer
var/obj/machinery/telecomms/SelectedMachine
var/obj/machinery/telecomms/SelectedMachine = null
var/network = "NULL" // the network to probe
var/notice = ""
var/temp = "" // temporary feedback messages
circuit = /obj/item/circuitboard/computer/comm_monitor
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user)
. = ..()
var/dat = "<TITLE>Telecommunications Monitor</TITLE><center><b>Telecommunications Monitor</b></center>"
/obj/machinery/computer/telecomms/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
switch(screen)
if(!ui)
ui = new(user, src, ui_key, "telemonitor", name, 575, 400, master_ui, state)
ui.open()
/obj/machinery/computer/telecomms/monitor/ui_data(mob/user)
var/list/data_out = list()
data_out["network"] = network
data_out["notice"] = notice
// --- Main Menu ---
data_out["servers"] = list()
for(var/obj/machinery/telecomms/T in machinelist)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["servers"] += list(data)
data_out["servers"] = sortList(data_out["servers"])
if(0)
dat += "<br>[temp]<br><br>"
dat += "<br>Current Network: <a href='?src=[REF(src)];network=1'>[network]</a><br>"
if(machinelist.len)
dat += "<br>Detected Network Entities:<ul>"
for(var/obj/machinery/telecomms/T in machinelist)
dat += "<li><a href='?src=[REF(src)];viewmachine=[T.id]'>[REF(T)] [T.name]</a> ([T.id])</li>"
dat += "</ul>"
dat += "<br><a href='?src=[REF(src)];operation=release'>\[Flush Buffer\]</a>"
else
dat += "<a href='?src=[REF(src)];operation=probe'>\[Probe Network\]</a>"
if(!SelectedMachine) //null is bad.
data_out["selected"] = null //but in js, null is good.
return data_out
data_out["selected"] = list(
name = SelectedMachine.name,
id = SelectedMachine.id,
status = SelectedMachine.on,
traffic = SelectedMachine.traffic,
netspeed = SelectedMachine.netspeed,
freq_listening = SelectedMachine.freq_listening,
long_range_link = SelectedMachine.long_range_link,
ref = REF(SelectedMachine)
)
data_out["selected_servers"] = list()
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
if(!T.hide)
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
data_out["selected_servers"] += list(data)
return data_out
// --- Viewing Machine ---
if(1)
dat += "<br>[temp]<br>"
dat += "<center><a href='?src=[REF(src)];operation=mainmenu'>\[Main Menu\]</a></center>"
dat += "<br>Current Network: [network]<br>"
dat += "Selected Network Entity: [SelectedMachine.name] ([SelectedMachine.id])<br>"
dat += "Linked Entities: <ol>"
for(var/obj/machinery/telecomms/T in SelectedMachine.links)
if(!T.hide)
dat += "<li><a href='?src=[REF(src)];viewmachine=[T.id]'>[REF(T.id)] [T.name]</a> ([T.id])</li>"
dat += "</ol>"
user << browse(dat, "window=comm_monitor;size=575x400")
onclose(user, "server_control")
temp = ""
return
/obj/machinery/computer/telecomms/monitor/Topic(href, href_list)
/obj/machinery/computer/telecomms/monitor/ui_act(action, params)
if(..())
return
switch(action)
if("mainmenu")
SelectedMachine = null
notice = ""
return
if("release")
machinelist = list()
notice = ""
return
if("network") //network change, flush the selected machine and buffer
var/newnet = sanitize(sanitize_text(params["value"], network))
if(length(newnet) > 15) //i'm looking at you, you href fuckers
notice = "FAILED: Network tag string too lengthy"
return
network = newnet
SelectedMachine = null
machinelist = list()
return
if("probe")
if(LAZYLEN(machinelist) > 0)
notice = "FAILED: Cannot probe when buffer full"
return
for(var/obj/machinery/telecomms/T in GLOB.telecomms_list)
if(T.network == network)
LAZYADD(machinelist, T)
add_fingerprint(usr)
usr.set_machine(src)
if(href_list["viewmachine"])
screen = 1
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == href_list["viewmachine"])
SelectedMachine = T
break
if(href_list["operation"])
switch(href_list["operation"])
if("release")
machinelist = list()
screen = 0
if("mainmenu")
screen = 0
if("probe")
if(machinelist.len > 0)
temp = "<font color = #D70B00>- FAILED: CANNOT PROBE WHEN BUFFER FULL -</font color>"
else
for(var/obj/machinery/telecomms/T in urange(25, src))
if(T.network == network)
machinelist.Add(T)
if(!machinelist.len)
temp = "<font color = #D70B00>- FAILED: UNABLE TO LOCATE NETWORK ENTITIES IN \[[network]\] -</font color>"
else
temp = "<font color = #336699>- [machinelist.len] ENTITIES LOCATED & BUFFERED -</font color>"
screen = 0
if(href_list["network"])
var/newnet = stripped_input(usr, "Which network do you want to view?", "Comm Monitor", network)
if(newnet && ((usr in range(1, src)) || hasSiliconAccessInArea(usr)))
if(length(newnet) > 15)
temp = "<font color = #D70B00>- FAILED: NETWORK TAG STRING TOO LENGHTLY -</font color>"
else
network = newnet
screen = 0
machinelist = list()
temp = "<font color = #336699>- NEW NETWORK TAG SET IN ADDRESS \[[network]\] -</font color>"
updateUsrDialog()
return
/obj/machinery/computer/telecomms/monitor/attackby()
. = ..()
updateUsrDialog()
if(!LAZYLEN(machinelist))
notice = "FAILED: Unable to locate network entities in \[[network]\]"
return
if("viewmachine")
for(var/obj/machinery/telecomms/T in machinelist)
if(T.id == params["value"])
SelectedMachine = T
break
@@ -9,9 +9,9 @@
var/temp = "" // output message
/obj/machinery/telecomms/attackby(obj/item/P, mob/user, params)
var/icon_closed = initial(icon_state)
var/icon_open = "[initial(icon_state)]_o"
if(!on)
icon_closed = "[initial(icon_state)]_off"
icon_open = "[initial(icon_state)]_o_off"
@@ -27,78 +27,240 @@
else
return ..()
/obj/machinery/telecomms/ui_interact(mob/user)
. = ..()
// You need a multitool to use this, or be silicon
if(!hasSiliconAccessInArea(user))
// istype returns false if the value is null
if(!istype(user.get_active_held_item(), /obj/item/multitool))
return
/obj/machinery/telecomms/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE,\
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
if(!canInteract(user))
if(ui)
ui.close() //haha no.
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "teleinteract", "[name] Access", 520, 500, master_ui, state)
ui.open()
/obj/machinery/telecomms/ui_data(mob/user)
. = list() //cpypaste from the vending bus
.["notice"] = temp
.["multitool"] = FALSE
var/obj/item/multitool/P = get_multitool(user)
var/dat
dat = "<font face = \"Courier\"><HEAD><TITLE>[name]</TITLE></HEAD><center><H3>[name] Access</H3></center>"
dat += "<br>[temp]<br>"
dat += "<br>Power Status: <a href='?src=[REF(src)];input=toggle'>[toggled ? "On" : "Off"]</a>"
if(on && toggled)
if(id != "" && id)
dat += "<br>Identification String: <a href='?src=[REF(src)];input=id'>[id]</a>"
else
dat += "<br>Identification String: <a href='?src=[REF(src)];input=id'>NULL</a>"
dat += "<br>Network: <a href='?src=[REF(src)];input=network'>[network]</a>"
dat += "<br>Prefabrication: [autolinkers.len ? "TRUE" : "FALSE"]"
if(hide)
dat += "<br>Shadow Link: ACTIVE</a>"
if(P)
.["multitool"] = TRUE
.["multitool_buf"] = null //to clean the list!
var/obj/machinery/telecomms/T = P.buffer
if(istype(T))
.["multitool_buf"] = list(
name = T.name,
id = T.id
)
//Show additional options for certain machines.
dat += Options_Menu()
.["machine"] = list()
.["machine"]["power"] = toggled
.["machine"]["id"] = id
.["machine"]["network"] = network
.["machine"]["prefab"] = LAZYLEN(autolinkers) ? TRUE : FALSE
.["machine"]["hidden"] = hide
dat += "<br>Linked Network Entities: <ol>"
.["links"] = list()
for(var/obj/machinery/telecomms/T in links)
if(T.hide && !hide)
continue
var/list/data = list(
name = T.name,
id = T.id,
ref = REF(T)
)
.["links"] += list(data)
var/i = 0
for(var/obj/machinery/telecomms/T in links)
i++
if(T.hide && !hide)
continue
dat += "<li>[REF(T)] [T.name] ([T.id]) <a href='?src=[REF(src)];unlink=[i]'>\[X\]</a></li>"
dat += "</ol>"
.["freq_listening"] = freq_listening
dat += "<br>Filtering Frequencies: "
/obj/machinery/telecomms/relay/ui_data(mob/user)
. = ..()
.["machine"]["isrelay"] = TRUE
.["machine"]["broadcast"] = broadcasting
.["machine"]["receiving"] = receiving
i = 0
if(length(freq_listening))
for(var/x in freq_listening)
i++
if(i < length(freq_listening))
dat += "[format_frequency(x)] GHz<a href='?src=[REF(src)];delete=[x]'>\[X\]</a>; "
else
dat += "[format_frequency(x)] GHz<a href='?src=[REF(src)];delete=[x]'>\[X\]</a>"
else
dat += "NONE"
/obj/machinery/telecomms/bus/ui_data(mob/user)
. = ..()
.["machine"]["isbus"] = TRUE
.["machine"]["chang_frequency"] = change_frequency
.["machine"]["chang_freq_value"] = change_freq_value
dat += "<br> <a href='?src=[REF(src)];input=freq'>\[Add Filter\]</a>"
dat += "<hr>"
if(P)
var/obj/machinery/telecomms/T = P.buffer
if(istype(T))
dat += "<br><br>MULTITOOL BUFFER: [T] ([T.id]) <a href='?src=[REF(src)];link=1'>\[Link\]</a> <a href='?src=[REF(src)];flush=1'>\[Flush\]"
else
dat += "<br><br>MULTITOOL BUFFER: <a href='?src=[REF(src)];buffer=1'>\[Add Machine\]</a>"
dat += "</font>"
/obj/machinery/telecomms/ui_act(action, params, datum/tgui/ui)
if(!canInteract(usr))
if(ui)
ui.close() //haha no.
return
temp = ""
user << browse(dat, "window=tcommachine;size=520x500;can_resize=0")
onclose(user, "tcommachine")
return TRUE
switch(action)
if("toggle")
toggled = !toggled
temp = "-% [src.name] has been [toggled ? "activated" : "deactivated"]. %-"
update_power()
return
if("machine")
if("id" in params)
if(!canAccess(usr))
return
//if the text is blank, return the id it was using
var/newid = sanitize_text(reject_bad_text(params["id"]), id) // reject_bad_text can return null!
if(length(newid) > 255)
temp = "-% Too many characters in new id tag. %-"
return
temp = "-% New ID assigned: \"[newid]\". %-"
id = newid
return
if("network" in params)
if(!canAccess(usr))
return
var/newnet = sanitize(sanitize_text(params["network"], network))
if(length(newnet) > 15)
temp = "-% Too many characters in new network tag. %-"
return
network = newnet
links = list()
temp = "-% New network tag assigned: \"[network]\" %-"
return
if("multitool")
var/obj/item/multitool/P = get_multitool(usr)
if("Link" in params)
if(!canAccess(usr))
return
if(!istype(P))
temp = "-% Unable to acquire buffer %-"
return
var/obj/machinery/telecomms/T = P.buffer
if(!istype(T) || T == src)
temp = "-% Unable to acquire buffer %-"
return
if(!(src in T.links))
LAZYADD(T.links, src)
if(!(T in links))
LAZYADD(links, T)
temp = "-% Successfully linked with [REF(T)] [T.name] %-"
if("Flush" in params)
if(!istype(P))
temp = "-% Unable to acquire multitool %-"
return
temp = "-% Buffer successfully flushed. %-"
P.buffer = null
if("Add" in params)
if(!canAccess(usr))
return
if(!istype(P))
temp = "-% Unable to acquire multitool %-"
return
P.buffer = src
temp = "% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-"
if("unlink")
var/obj/machinery/telecomms/T = locate(params["value"])
if(!canAccess(usr))
return
if(!istype(T))
temp = "-% Unable to locate machine to unlink from, try again. %-"
return
temp = "-% Removed [REF(T)] [T.name] from linked entities. %-"
if(T.links) //lazyrem makes blank list null, which is good but some might cause runtime ee's
T.links.Remove(src)
links.Remove(T)
if("freq")
if("add" in params)
var/newfreq = input("Specify a new frequency to filter (GHz). Decimals assigned automatically.", src.name, null) as null|num
if(!canAccess(usr) || !newfreq || isnull(newfreq))
return
if(findtext(num2text(newfreq), ".")) // did they not read the text?
newfreq *= 10 // shift the decimal one place
newfreq = sanitize_frequency(newfreq, TRUE) //sanitize
if(newfreq == FREQ_SYNDICATE)
temp = "-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-"
return
if(newfreq in freq_listening)
temp = "-% Error: Frequency already filtered %-"
return
LAZYADD(freq_listening, newfreq)
temp = "-% New frequency filter assigned: \"[newfreq] GHz\" %-"
if("remove" in params)
if(!canAccess(usr))
return
var/x = text2num(params["remove"])
temp = "-% Removed frequency filter [x] %-"
freq_listening.Remove(x)
/obj/machinery/telecomms/relay/ui_act(action, params)
..()
switch(action)
if("relay")
if("broadcast" in params)
if(!canAccess(usr))
return
broadcasting = !broadcasting
temp = "-% Broadcasting mode changed. %-"
return
if("receiving" in params)
if(!canAccess(usr))
return
receiving = !receiving
temp = "-% Receiving mode changed. %-"
/obj/machinery/telecomms/bus/ui_act(action, params)
..()
switch(action)
if("frequency")
if("toggle" in params)
if(!canAccess(usr))
return
change_frequency = !change_frequency
return
if("adjust" in params)
var/newfreq = text2num(params["adjust"])
if(!canAccess(usr) || !newfreq)
return
// this should return true, unless the href is handcrafted
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
newfreq = sanitize_frequency(newfreq, TRUE)
if(newfreq == FREQ_SYNDICATE)
temp = "-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-"
return
change_freq_value = newfreq
temp = "-% New frequency to change to assigned: \"[newfreq] GHz\" %-"
return
// Check if the user can use it.
/obj/machinery/telecomms/proc/canInteract(mob/user)
if(hasSiliconAccessInArea(user) || istype(user.get_active_held_item(), /obj/item/multitool))
return TRUE
return FALSE
// Check if the user is nearby and has a multitool.
/obj/machinery/telecomms/proc/canAccess(mob/user)
if((canInteract(user) && in_range(user, src)) || hasSiliconAccessInArea(user))
return TRUE
return FALSE
// Returns a multitool from a user depending on their mobtype.
/obj/machinery/telecomms/proc/get_multitool(mob/user)
var/obj/item/multitool/P = null
// Let's double check
if(!hasSiliconAccessInArea(user) && istype(user.get_active_held_item(), /obj/item/multitool))
P = user.get_active_held_item()
if(!canInteract(user))
return null
var/obj/item/multitool/P = user.get_active_held_item()
// Is the ref not a null? and is it the actual type?
if(istype(P))
return P
else if(isAI(user))
var/mob/living/silicon/ai/U = user
P = U.aiMulti
@@ -106,170 +268,3 @@
if(istype(user.get_active_held_item(), /obj/item/multitool))
P = user.get_active_held_item()
return P
// Additional Options for certain machines. Use this when you want to add an option to a specific machine.
// Example of how to use below.
/obj/machinery/telecomms/proc/Options_Menu()
return ""
// The topic for Additional Options. Use this for checking href links for your specific option.
// Example of how to use below.
/obj/machinery/telecomms/proc/Options_Topic(href, href_list)
return
// RELAY
/obj/machinery/telecomms/relay/Options_Menu()
var/dat = ""
dat += "<br>Broadcasting: <A href='?src=[REF(src)];broadcast=1'>[broadcasting ? "YES" : "NO"]</a>"
dat += "<br>Receiving: <A href='?src=[REF(src)];receive=1'>[receiving ? "YES" : "NO"]</a>"
return dat
/obj/machinery/telecomms/relay/Options_Topic(href, href_list)
if(href_list["receive"])
receiving = !receiving
temp = "<font color = #666633>-% Receiving mode changed. %-</font color>"
if(href_list["broadcast"])
broadcasting = !broadcasting
temp = "<font color = #666633>-% Broadcasting mode changed. %-</font color>"
// BUS
/obj/machinery/telecomms/bus/Options_Menu()
var/dat = "<br>Change Signal Frequency: <A href='?src=[REF(src)];change_freq=1'>[change_frequency ? "YES ([change_frequency])" : "NO"]</a>"
return dat
/obj/machinery/telecomms/bus/Options_Topic(href, href_list)
if(href_list["change_freq"])
var/newfreq = input(usr, "Specify a new frequency for new signals to change to. Enter null to turn off frequency changing. Decimals assigned automatically.", src, network) as null|num
if(canAccess(usr))
if(newfreq)
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if(newfreq < 10000)
change_frequency = newfreq
temp = "<font color = #666633>-% New frequency to change to assigned: \"[newfreq] GHz\" %-</font color>"
else
change_frequency = 0
temp = "<font color = #666633>-% Frequency changing deactivated %-</font color>"
/obj/machinery/telecomms/Topic(href, href_list)
if(..())
return
if(!hasSiliconAccessInArea(usr))
if(!istype(usr.get_active_held_item(), /obj/item/multitool))
return
var/obj/item/multitool/P = get_multitool(usr)
if(href_list["input"])
switch(href_list["input"])
if("toggle")
toggled = !toggled
temp = "<font color = #666633>-% [src] has been [toggled ? "activated" : "deactivated"].</font color>"
update_power()
if("id")
var/newid = reject_bad_text(stripped_input(usr, "Specify the new ID for this machine", src, id, MAX_MESSAGE_LEN))
if(newid && canAccess(usr))
id = newid
temp = "<font color = #666633>-% New ID assigned: \"[id]\" %-</font color>"
if("network")
var/newnet = stripped_input(usr, "Specify the new network for this machine. This will break all current links.", src, network)
if(newnet && canAccess(usr))
if(length(newnet) > 15)
temp = "<font color = #666633>-% Too many characters in new network tag %-</font color>"
else
for(var/obj/machinery/telecomms/T in links)
T.links.Remove(src)
network = newnet
links = list()
temp = "<font color = #666633>-% New network tag assigned: \"[network]\" %-</font color>"
if("freq")
var/newfreq = input(usr, "Specify a new frequency to filter (GHz). Decimals assigned automatically.", src, network) as null|num
if(newfreq && canAccess(usr))
if(findtext(num2text(newfreq), "."))
newfreq *= 10 // shift the decimal one place
if(newfreq == FREQ_SYNDICATE)
temp = "<font color = #FF0000>-% Error: Interference preventing filtering frequency: \"[newfreq] GHz\" %-</font color>"
else
if(!(newfreq in freq_listening) && newfreq < 10000)
freq_listening.Add(newfreq)
temp = "<font color = #666633>-% New frequency filter assigned: \"[newfreq] GHz\" %-</font color>"
if(href_list["delete"])
// changed the layout about to workaround a pesky runtime -- Doohl
var/x = text2num(href_list["delete"])
temp = "<font color = #666633>-% Removed frequency filter [x] %-</font color>"
freq_listening.Remove(x)
if(href_list["unlink"])
if(text2num(href_list["unlink"]) <= length(links))
var/obj/machinery/telecomms/T = links[text2num(href_list["unlink"])]
if(T)
temp = "<font color = #666633>-% Removed [REF(T)] [T.name] from linked entities. %-</font color>"
// Remove link entries from both T and src.
if(T.links)
T.links.Remove(src)
links.Remove(T)
else
temp = "<font color = #666633>-% Unable to locate machine to unlink from, try again. %-</font color>"
if(href_list["link"])
if(P)
var/obj/machinery/telecomms/T = P.buffer
if(istype(T) && T != src)
if(!(src in T.links))
T.links += src
if(!(T in links))
links += T
temp = "<font color = #666633>-% Successfully linked with [REF(T)] [T.name] %-</font color>"
else
temp = "<font color = #666633>-% Unable to acquire buffer %-</font color>"
if(href_list["buffer"])
P.buffer = src
temp = "<font color = #666633>-% Successfully stored [REF(P.buffer)] [P.buffer.name] in buffer %-</font color>"
if(href_list["flush"])
temp = "<font color = #666633>-% Buffer successfully flushed. %-</font color>"
P.buffer = null
Options_Topic(href, href_list)
usr.set_machine(src)
updateUsrDialog()
/obj/machinery/telecomms/proc/canAccess(mob/user)
if(hasSiliconAccessInArea(user) || in_range(user, src))
return TRUE
return FALSE
@@ -17,7 +17,8 @@
idle_power_usage = 50
netspeed = 40
circuit = /obj/item/circuitboard/machine/telecomms/bus
var/change_frequency = 0
var/change_frequency = FALSE
var/change_freq_value = 0
/obj/machinery/telecomms/bus/RefreshParts()
idle_power_usage = 50
@@ -28,8 +29,8 @@
if(!istype(signal) || !is_freq_listening(signal))
return
if(change_frequency && signal.frequency != FREQ_SYNDICATE)
signal.frequency = change_frequency
if(change_frequency && (change_freq_value && signal.frequency != FREQ_SYNDICATE))
signal.frequency = change_freq_value
if(!istype(machine_from, /obj/machinery/telecomms/processor) && machine_from != src) // Signal must be ready (stupid assuming machine), let's send it
// send to one linked processor unit
@@ -140,11 +140,16 @@
..()
if(href_list["photo"])
var/mob/M = usr
M << browse_rsc(picture.picture_image, "pda_photo.png")
M << browse("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>PDA Photo</title></head>" \
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
+ "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
+ "</body></html>", "window=pdaphoto;size=[picture.psize_x]x[picture.psize_y];can-close=true")
M << browse_rsc(picture.picture_image, "pda_photo.png")
var/dat = "<div style='overflow: hidden; margin :0; text-align: center'>"
dat += "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />"
dat += "</div>"
var/datum/browser/popup = new(M, "pdaphoto", "PDA Photo", picture.psize_x, picture.psize_y)
popup.set_content(dat)
popup.open()
onclose(M, "pdaphoto")
/datum/data_rc_msg
@@ -33,7 +33,7 @@
totaltraffic += traffic // add current traffic to total traffic
// Delete particularly old logs
if (log_entries.len >= 400)
if(LAZYLEN(log_entries) >= 400) //[list].len is not safe
log_entries.Cut(1, 2)
var/datum/comm_log_entry/log = new
@@ -117,9 +117,9 @@ GLOBAL_LIST_EMPTY(telecomms_list)
icon_state = "[initial(icon_state)]_off"
/obj/machinery/telecomms/proc/update_power()
if(toggled)
if(stat & (BROKEN|NOPOWER|EMPED)) // if powered, on. if not powered, off. if too damaged, off
// if powered, on. if not powered, off. if too damaged, off
if(CHECK_BITFIELD(stat, (BROKEN | NOPOWER | EMPED)))
on = FALSE
else
on = TRUE
@@ -137,11 +137,11 @@ GLOBAL_LIST_EMPTY(telecomms_list)
/obj/machinery/telecomms/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
if(CHECK_BITFIELD(., EMP_PROTECT_SELF))
return
if(prob(100/severity))
if(!(stat & EMPED))
stat |= EMPED
var/duration = (300 * 10)/severity
if(prob(100 / severity))
if(!CHECK_BITFIELD(stat, EMPED))
ENABLE_BITFIELD(stat, EMPED)
var/duration = (300 * 10) / severity
spawn(rand(duration - 20, duration + 20)) // Takes a long time for the machines to reboot.
stat &= ~EMPED
DISABLE_BITFIELD(stat, EMPED)
+17 -19
View File
@@ -5,44 +5,42 @@
var/base_icon
var/looky_helpy = TRUE
/datum/component/construction/mecha/examine(mob/user)
/datum/component/construction/mecha/examine(datum/source, mob/user, list/examine_list)
. = ..()
if(looky_helpy)
switch(steps[index]["key"])
if(TOOL_WRENCH)
. += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
examine_list += "<span class='notice'>The mech could be <b>wrenched</b> into place.</span>"
if(TOOL_SCREWDRIVER)
. += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
examine_list += "<span class='notice'>The mech could be <b>screwed</b> into place.</span>"
if(TOOL_WIRECUTTER)
. += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
examine_list += "<span class='notice'>The mech wires could be <b>trimmed</b> into place.</span>"
if(/obj/item/stack/cable_coil)
. += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
examine_list += "<span class='notice'>The mech could use some <b>wiring</b>.</span>"
if(/obj/item/circuitboard)
. += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
examine_list += "<span class='notice'>The mech could use a type of<b>circuitboard</b>.</span>"
if(/obj/item/stock_parts/scanning_module)
. += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
examine_list += "<span class='notice'>The mech could use a <b>scanning stock part</b>.</span>"
if(/obj/item/stock_parts/capacitor)
. += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
examine_list += "<span class='notice'>The mech could use a <b>power based stock part</b>.</span>"
if(/obj/item/stock_parts/cell)
. += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
examine_list += "<span class='notice'>The mech could use a <b>power source</b>.</span>"
if(/obj/item/stack/sheet/metal)
. += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
examine_list += "<span class='notice'>The mech could use some <b>sheets of metal</b>.</span>"
if(/obj/item/stack/sheet/plasteel)
. += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
examine_list += "<span class='notice'>The mech could use some <b>sheets of strong steel</b>.</span>"
if(/obj/item/bikehorn)
. += "<span class='notice'>HONK IT!.</span>"
examine_list += "<span class='notice'>HONK IT!.</span>"
if(/obj/item/clothing/mask/gas/clown_hat)
. += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
examine_list += "<span class='notice'>GIVE IT CLOWN MAKEUP HONK!.</span>"
if(/obj/item/clothing/shoes/clown_shoes)
. += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
examine_list += "<span class='notice'>GIVE IT GOOFY SHOES HONK HONK!.</span>"
if(/obj/item/mecha_parts/part)
. += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
examine_list += "<span class='notice'>The mech could use a mech <b>part</b>.</span>"
if(/obj/item/stack/ore/bluespace_crystal)
. += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
examine_list += "<span class='notice'>The mech could use a <b>crystal</b> of sorts.</span>"
if(/obj/item/assembly/signaler/anomaly)
. += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
else
return
examine_list += "<span class='notice'>The mech could use a <b>anomaly</b> of sorts.</span>"
/datum/component/construction/mecha/spawn_result()
if(!result)
+2 -2
View File
@@ -282,9 +282,9 @@
else
return ..()
/obj/mecha/attacked_by(obj/item/I, mob/living/user)
/obj/mecha/attacked_by(obj/item/I, mob/living/user, attackchain_flags = NONE, damage_multiplier = 1)
mecha_log_message("Attacked by [I]. Attacker - [user]")
..()
return ..()
/obj/mecha/proc/mech_toxin_damage(mob/living/target)
playsound(src, 'sound/effects/spray2.ogg', 50, 1)
+5
View File
@@ -428,6 +428,11 @@
desc = "A poster decipting a snake shaped into an ominous 'S'!"
icon_state = "poster47"
/obj/structure/sign/poster/contraband/bountyhunters
name = "Bounty Hunters"
desc = "A poster advertising bounty hunting services. \"I hear you got a problem.\""
icon_state = "poster48"
/obj/structure/sign/poster/official
poster_item_name = "motivational poster"
poster_item_desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface."
+1 -1
View File
@@ -46,4 +46,4 @@
var/turf/T = loc
if(!istype(T)) //you know this will happen somehow
CRASH("Turf decal initialized in an object/nullspace")
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)
T.AddElement(/datum/element/decal, icon, icon_state, turn(dir, -dir2angle(T.dir)), CLEAN_GOD, color, null, null, alpha)
+28 -10
View File
@@ -5,19 +5,21 @@
anchored = TRUE
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "uglymine"
var/triggered = 0
/// We manually check to see if we've been triggered in case multiple atoms cross us in the time between the mine being triggered and it actually deleting, to avoid a race condition with multiple detonations
var/triggered = FALSE
/obj/effect/mine/proc/mineEffect(mob/victim)
to_chat(victim, "<span class='danger'>*click*</span>")
/obj/effect/mine/Crossed(AM as mob|obj)
if(isturf(loc))
if(ismob(AM))
var/mob/MM = AM
if(!(MM.movement_type & FLYING))
triggermine(AM)
else
triggermine(AM)
/obj/effect/mine/Crossed(atom/movable/AM)
if(triggered || !isturf(loc))
return
. = ..()
if(AM.movement_type & FLYING)
return
triggermine(AM)
/obj/effect/mine/proc/triggermine(mob/victim)
if(triggered)
@@ -27,9 +29,13 @@
s.set_up(3, 1, src)
s.start()
mineEffect(victim)
SEND_SIGNAL(src, COMSIG_MINE_TRIGGERED)
triggered = 1
qdel(src)
/obj/effect/mine/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir)
. = ..()
triggermine()
/obj/effect/mine/explosive
name = "explosive mine"
@@ -50,6 +56,18 @@
if(isliving(victim))
victim.DefaultCombatKnockdown(stun_time)
/obj/effect/mine/shrapnel
name = "shrapnel mine"
var/shrapnel_type = /obj/item/projectile/bullet/shrapnel
var/shrapnel_magnitude = 3
/obj/effect/mine/shrapnel/mineEffect(mob/victim)
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_magnitude)
/obj/effect/mine/shrapnel/sting
name = "stinger mine"
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball
/obj/effect/mine/kickmine
name = "kick mine"
@@ -105,7 +123,7 @@
/obj/effect/mine/pickup/triggermine(mob/victim)
if(triggered)
return
triggered = 1
triggered = TRUE
invisibility = INVISIBILITY_ABSTRACT
mineEffect(victim)
qdel(src)
+90 -3
View File
@@ -491,7 +491,7 @@
/obj/item/kitchen/knife = 5,
/obj/item/screwdriver = 5,
/obj/item/crowbar/red = 1, //Dont you need a crowbar to open this?
/obj/item/stack/medical/bruise_pack = 3,
/obj/item/stack/medical/suture = 3,
/obj/item/reagent_containers/food/drinks/bottle/vodka = 2,
/obj/item/radio = 5,
/obj/item/flashlight = 4,
@@ -611,13 +611,13 @@
/obj/item/clothing/mask/breath = 5,
/obj/item/clothing/mask/breath/medical = 1
)
/obj/effect/spawner/lootdrop/welder_tools/no_turf
spawn_on_turf = FALSE
/obj/effect/spawner/lootdrop/low_tools/no_turf
spawn_on_turf = FALSE
/obj/effect/spawner/lootdrop/breathing_tanks/no_turf
spawn_on_turf = FALSE
@@ -644,3 +644,90 @@
/obj/effect/spawner/lootdrop/glowstick/no_turf
spawn_on_turf = FALSE
// Random Parts
/obj/effect/spawner/lootdrop/stock_parts
name = "random stock parts spawner"
lootcount = 1
loot = list(
/obj/item/stock_parts/capacitor,
/obj/item/stock_parts/scanning_module,
/obj/item/stock_parts/manipulator,
/obj/item/stock_parts/micro_laser,
/obj/item/stock_parts/matter_bin,
/obj/item/stock_parts/cell
)
// Random Weapon Parts
/obj/effect/spawner/lootdrop/weapon_parts
name = "random weapon parts spawner 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 10,
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 5,
/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 5,
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 10,
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 3,
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 3,
/obj/item/weaponcrafting/improvised_parts/laser_receiver = 1,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 10,
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 3,
)
/obj/effect/spawner/lootdrop/weapon_parts
name = "random weapon parts spawner 25%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 75,
/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 5,
/obj/item/weaponcrafting/improvised_parts/barrel_pistol = 5,
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 5,
/obj/item/weaponcrafting/improvised_parts/pistol_receiver = 2,
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 5,
/obj/item/weaponcrafting/improvised_parts/makeshift_lens = 3,
)
/obj/effect/spawner/lootdrop/ammo
name = "random ammo 75%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 25,
/obj/item/ammo_box/c32mm = 15,
/obj/item/ammo_box/r32mm = 15,
/obj/item/ammo_box/magazine/wt550m9 = 1,
/obj/item/ammo_casing/shotgun/buckshot = 7,
/obj/item/ammo_casing/shotgun/rubbershot = 7,
/obj/item/ammo_casing/a762 = 15,
/obj/item/ammo_box/a762 = 15,
)
/obj/effect/spawner/lootdrop/ammo/fiftypercent
name = "random ammo 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/ammo_box/c32mm = 7,
/obj/item/ammo_box/r32mm = 7,
/obj/item/ammo_box/magazine/wt550m9 = 2,
/obj/item/ammo_casing/shotgun/buckshot = 10,
/obj/item/ammo_casing/shotgun/rubbershot = 10,
/obj/item/ammo_casing/a762 = 7,
/obj/item/ammo_box/a762 = 7,
)
/obj/effect/spawner/lootdrop/ammo/shotgun
name = "random ammo 50%"
lootcount = 1
spawn_on_turf = FALSE
loot = list("" = 50,
/obj/item/ammo_box/shotgun/loaded/buckshot = 5,
/obj/item/ammo_box/shotgun/loaded/beanbag = 5,
/obj/item/ammo_box/shotgun/loaded/incendiary = 5,
/obj/item/ammo_casing/shotgun/buckshot = 8,
/obj/item/ammo_casing/shotgun/rubbershot = 9,
/obj/item/ammo_casing/shotgun = 8,
/obj/item/ammo_casing/shotgun/incendiary = 10,
)
@@ -95,6 +95,56 @@
icon_state = "warden_gaze"
duration = 3
/obj/effect/temp_visual/ratvar/volt_hit
name = "volt blast"
layer = ABOVE_MOB_LAYER
duration = 8
icon_state = "volt_hit"
light_range = 1.5
light_power = 2
light_color = LIGHT_COLOR_ORANGE
var/mob/user
var/damage = 20
/obj/effect/temp_visual/ratvar/volt_hit/Initialize(mapload, caster)
. = ..()
user = caster
if(user)
var/matrix/M = new
M.Turn(Get_Angle(src, user))
transform = M
INVOKE_ASYNC(src, .proc/volthit)
/obj/effect/temp_visual/ratvar/volt_hit/proc/volthit()
if(user)
Beam(get_turf(user), "volt_ray", time=duration, maxdistance=8, beam_type=/obj/effect/ebeam/volt_ray)
var/hit_amount = 0
var/turf/T = get_turf(src)
for(var/mob/living/L in T)
if(is_servant_of_ratvar(L))
continue
var/obj/item/I = L.anti_magic_check()
if(I)
L.visible_message("<span class='warning'>Strange energy flows into [L]'s [I.name]!</span>", \
"<span class='userdanger'>Your [I.name] shields you from [src]!</span>")
continue
L.visible_message("<span class='warning'>[L] is struck by a [name]!</span>", "<span class='userdanger'>You're struck by a [name]!</span>")
L.apply_damage(damage, BURN, "chest", L.run_armor_check("chest", "laser", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 0, "Your armor was penetrated by [src]!"))
log_combat(user, L, "struck with a volt blast")
hit_amount++
for(var/obj/mecha/M in T)
if(M.occupant)
if(is_servant_of_ratvar(M.occupant))
continue
to_chat(M.occupant, "<span class='userdanger'>Your [M.name] is struck by a [name]!</span>")
M.visible_message("<span class='warning'>[M] is struck by a [name]!</span>")
M.take_damage(damage, BURN, 0, 0)
hit_amount++
if(hit_amount)
playsound(src, 'sound/machines/defib_zap.ogg', damage*hit_amount, 1, -1)
else
playsound(src, "sparks", 50, 1)
/obj/effect/temp_visual/ratvar/ocular_warden/Initialize()
. = ..()
pixel_x = rand(-8, 8)
+194 -19
View File
@@ -4,6 +4,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if true, everyone item when created will have its name changed to be
// more... RPG-like.
GLOBAL_VAR_INIT(stickpocalypse, FALSE) // if true, all non-embeddable items will be able to harmlessly stick to people when thrown
GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to embed in people, takes precedence over stickpocalypse
/obj/item
name = "item"
icon = 'icons/obj/items_and_weapons.dmi'
@@ -55,6 +58,15 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/// How long, in deciseconds, this staggers for, if null it will autocalculate from w_class and force. Unlike total mass this supports 0 and negatives.
var/stagger_force
/**
* Set FALSE and then checked at the end of on mob/living/attackby(), set TRUE on living/pre_attacked_by().
* Should it be FALSE by the end of the item/attack(), that means the item overrode the standard attack behaviour
* and the user still needs the delay applied. We can't be using return values since that'll stop afterattack() from being triggered.
*/
var/attack_delay_done = FALSE
///next_move click/attack delay of this item.
var/click_delay = CLICK_CD_MELEE
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
pass_flags = PASSTABLE
pressure_resistance = 4
@@ -95,7 +107,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
var/datum/embedding_behavior/embedding
var/list/embedding = NONE
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
var/heat = 0
@@ -132,6 +144,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
/* Our block parry data. Should be set in init, or something if you are using it.
* This won't be accessed without ITEM_CAN_BLOCK or ITEM_CAN_PARRY so do not set it unless you have to to save memory.
* If you decide it's a good idea to leave this unset while turning the flags on, you will runtime. Enjoy.
* If this is set to a path, it'll run get_block_parry_data(path). YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
*/
var/datum/block_parry_data/block_parry_data
///Skills vars
//list of skill PATHS exercised when using this item. An associated bitfield can be set to indicate additional ways the skill is used by this specific item.
var/list/datum/skill/used_skills
@@ -143,7 +162,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/Initialize()
if (attack_verb)
if(attack_verb)
attack_verb = typelist("attack_verb", attack_verb)
. = ..()
@@ -151,9 +170,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
new path(src)
actions_types = null
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(force_string)
item_flags |= FORCE_STRING_OVERRIDE
@@ -163,16 +179,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(damtype == "brute")
hitsound = "swing_hit"
if (!embedding)
embedding = getEmbeddingBehavior()
else if (islist(embedding))
embedding = getEmbeddingBehavior(arglist(embedding))
else if (!istype(embedding, /datum/embedding_behavior))
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
if(sharpness) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
/obj/item/Destroy()
item_flags &= ~DROPDEL //prevent reqdels
if(ismob(loc))
@@ -182,6 +188,26 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
qdel(X)
return ..()
/obj/item/ComponentInitialize()
. = ..()
// this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:)
if(!LAZYLEN(embedding))
if(GLOB.embedpocalypse)
embedding = EMBED_POINTY
name = "pointy [name]"
else if(GLOB.stickpocalypse)
embedding = EMBED_HARMLESS
name = "sticky [name]"
updateEmbedding()
if(GLOB.rpg_loot_items)
AddComponent(/datum/component/fantasy)
if(sharpness) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
return 0
@@ -232,8 +258,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
if(resistance_flags & FIRE_PROOF)
. += "[src] is made of fire-retardant materials."
if(item_flags & (ITEM_CAN_BLOCK | ITEM_CAN_PARRY))
var/datum/block_parry_data/data = return_block_parry_datum(block_parry_data)
. += "[src] has the capacity to be used to block and/or parry. <a href='?src=[REF(data)];name=[name];block=[item_flags & ITEM_CAN_BLOCK];parry=[item_flags & ITEM_CAN_PARRY];render=1'>\[Show Stats\]</a>"
if(!user.research_scanner)
return
@@ -395,6 +422,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
return ITALICS | REDUCE_RANGE
/obj/item/proc/dropped(mob/user)
SHOULD_CALL_PARENT(TRUE)
for(var/X in actions)
var/datum/action/A = X
A.Remove(user)
@@ -407,6 +435,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user)
item_flags |= IN_INVENTORY
@@ -606,6 +635,18 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/itempush = 1
if(w_class < 4)
itempush = 0 //too light to push anything
if(isliving(hit_atom)) //Living mobs handle hit sounds differently.
var/volume = get_volume_by_throwforce_and_or_w_class()
if (throwforce > 0)
if (throwhitsound)
playsound(hit_atom, throwhitsound, volume, TRUE, -1)
else if(hitsound)
playsound(hit_atom, hitsound, volume, TRUE, -1)
else
playsound(hit_atom, 'sound/weapons/genhit.ogg',volume, TRUE, -1)
else
playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1)
return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
@@ -899,11 +940,13 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// if w_volume is 0 you fucked up anyways lol
return w_volume || AUTO_SCALE_VOLUME(w_class)
/obj/item/proc/embedded(mob/living/carbon/human/embedded_mob)
/obj/item/proc/embedded(atom/embedded_target)
return
/obj/item/proc/unembedded()
return
if(item_flags & DROPDEL)
QDEL_NULL(src)
return TRUE
/**
* Sets our slowdown and updates equipment slowdown of any mob we're equipped on.
@@ -919,3 +962,135 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
. = ..()
if(var_name == NAMEOF(src, slowdown))
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
/**
* Does the current embedding var meet the criteria for being harmless? Namely, does it explicitly define the pain multiplier and jostle pain mult to be 0? If so, return true.
*
*/
/obj/item/proc/isEmbedHarmless()
if(embedding)
return !isnull(embedding["pain_mult"]) && !isnull(embedding["jostle_pain_mult"]) && embedding["pain_mult"] == 0 && embedding["jostle_pain_mult"] == 0
///In case we want to do something special (like self delete) upon failing to embed in something, return true
/obj/item/proc/failedEmbed()
if(item_flags & DROPDEL)
QDEL_NULL(src)
return TRUE
/**
* tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targetting the target.
*
* Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements.
*
* Arguments:
* * target- Either a body part, a carbon, or a closed turf. What are we hitting?
* * forced- Do we want this to go through 100%?
*/
/obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE)
if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target))
return
if(!forced && !LAZYLEN(embedding))
return
if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target, forced, silent))
return TRUE
failedEmbed()
///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it.
/obj/item/proc/disableEmbedding()
SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED)
return
///For when you want to add/update the embedding on an item. Uses the vars in [/obj/item/embedding], and defaults to config values for values that aren't set. Will automatically detach previous embed elements on this item.
/obj/item/proc/updateEmbedding()
if(!islist(embedding) || !LAZYLEN(embedding))
return
AddElement(/datum/element/embed,\
embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\
fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\
pain_chance = (!isnull(embedding["pain_chance"]) ? embedding["pain_chance"] : EMBEDDED_PAIN_CHANCE),\
pain_mult = (!isnull(embedding["pain_mult"]) ? embedding["pain_mult"] : EMBEDDED_PAIN_MULTIPLIER),\
remove_pain_mult = (!isnull(embedding["remove_pain_mult"]) ? embedding["remove_pain_mult"] : EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER),\
rip_time = (!isnull(embedding["rip_time"]) ? embedding["rip_time"] : EMBEDDED_UNSAFE_REMOVAL_TIME),\
ignore_throwspeed_threshold = (!isnull(embedding["ignore_throwspeed_threshold"]) ? embedding["ignore_throwspeed_threshold"] : FALSE),\
impact_pain_mult = (!isnull(embedding["impact_pain_mult"]) ? embedding["impact_pain_mult"] : EMBEDDED_IMPACT_PAIN_MULTIPLIER),\
jostle_chance = (!isnull(embedding["jostle_chance"]) ? embedding["jostle_chance"] : EMBEDDED_JOSTLE_CHANCE),\
jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\
pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT),\
embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD))
return TRUE
+2 -1
View File
@@ -154,7 +154,8 @@ RLD
icon_state = "rcd"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
custom_price = 900
custom_price = PRICE_ABOVE_EXPENSIVE
custom_premium_price = PRICE_ALMOST_ONE_GRAND
max_matter = 160
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
has_ammobar = TRUE
+1 -1
View File
@@ -157,7 +157,7 @@
to_chat(user, "<span class='notice'>You need to get closer!</span>")
return
if(use_paint(user) && isturf(F))
F.AddComponent(/datum/component/decal, 'icons/turf/decals.dmi', stored_decal_total, stored_dir, CLEAN_STRONG, color, null, null, alpha)
F.AddElement(/datum/element/decal, 'icons/turf/decals.dmi', stored_decal_total, turn(stored_dir, -dir2angle(F.dir)), CLEAN_STRONG, color, null, null, alpha)
/obj/item/airlock_painter/decal/attack_self(mob/user)
if((ink) && (ink.charges >= 1))
+55 -9
View File
@@ -83,7 +83,7 @@
/obj/item/card/emag/bluespace
name = "bluespace cryptographic sequencer"
desc = "It's a blue card with a magnetic strip attached to some circuitry. It appears to have some sort of transmitter attached to it."
color = rgb(40, 130, 255)
icon_state = "emag_bs"
prox_check = FALSE
/obj/item/card/emag/attack()
@@ -166,6 +166,7 @@
slot_flags = ITEM_SLOT_ID
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/id_type_name = "identification card"
var/mining_points = 0 //For redeeming at mining equipment vendors
var/list/access = list()
var/registered_name = null // The name registered_name on the card
@@ -174,6 +175,8 @@
var/bank_support = ID_FREE_BANK_ACCOUNT
var/datum/bank_account/registered_account
var/obj/machinery/paystand/my_store
var/uses_overlays = TRUE
var/icon/cached_flat_icon
/obj/item/card/id/Initialize(mapload)
. = ..()
@@ -187,6 +190,15 @@
if(ID_LOCKED_BANK_ACCOUNT)
registered_account = new /datum/bank_account/remote/non_transferable(pick(GLOB.redacted_strings))
/obj/item/card/id/Destroy()
if(bank_support == ID_LOCKED_BANK_ACCOUNT)
QDEL_NULL(registered_account)
else
registered_account = null
if(my_store)
my_store.my_card = null
my_store = null
return ..()
/obj/item/card/id/vv_edit_var(var_name, var_value)
. = ..()
@@ -353,20 +365,38 @@
/obj/item/card/id/RemoveID()
return src
/*
Usage:
update_label()
Sets the id name to whatever registered_name and assignment is
/obj/item/card/id/update_overlays()
. = ..()
if(!uses_overlays)
return
cached_flat_icon = null
var/job = assignment ? ckey(GetJobName()) : null
if(registered_name == "Captain")
job = "captain"
if(registered_name && registered_name != "Captain")
. += mutable_appearance(icon, "assigned")
if(job)
. += mutable_appearance(icon, "id[job]")
/obj/item/card/id/proc/get_cached_flat_icon()
if(!cached_flat_icon)
cached_flat_icon = getFlatIcon(src)
return cached_flat_icon
/obj/item/card/id/get_examine_string(mob/user, thats = FALSE)
if(uses_overlays)
return "[icon2html(get_cached_flat_icon(), user)] [thats? "That's ":""][get_examine_name(user)]" //displays all overlays in chat
return ..()
update_label("John Doe", "Clowny")
Properly formats the name and occupation and sets the id name to the arguments
*/
/obj/item/card/id/proc/update_label(newname, newjob)
if(newname || newjob)
name = "[(!newname) ? "identification card" : "[newname]'s ID Card"][(!newjob) ? "" : " ([newjob])"]"
update_icon()
return
name = "[(!registered_name) ? "identification card" : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
update_icon()
/obj/item/card/id/silver
name = "silver identification card"
@@ -379,6 +409,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/silver/reaper
name = "Thirteen's ID Card (Reaper)"
access = list(ACCESS_MAINT_TUNNELS)
icon_state = "reaper"
assignment = "Reaper"
registered_name = "Thirteen"
@@ -530,7 +561,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/ert
name = "\improper CentCom ID"
desc = "An ERT ID card."
icon_state = "centcom"
icon_state = "ert_commander"
registered_name = "Emergency Response Team Commander"
assignment = "Emergency Response Team Commander"
@@ -539,6 +570,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Security
icon_state = "ert_security"
registered_name = "Security Response Officer"
assignment = "Security Response Officer"
@@ -547,6 +579,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Engineer
icon_state = "ert_engineer"
registered_name = "Engineer Response Officer"
assignment = "Engineer Response Officer"
@@ -555,6 +588,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/Medical
icon_state = "ert_medical"
registered_name = "Medical Response Officer"
assignment = "Medical Response Officer"
@@ -563,6 +597,7 @@ update_label("John Doe", "Clowny")
. = ..()
/obj/item/card/id/ert/chaplain
icon_state = "ert_chaplain"
registered_name = "Religious Response Officer"
assignment = "Religious Response Officer"
@@ -615,40 +650,49 @@ update_label("John Doe", "Clowny")
. += "<span class='notice'>Your sentence is up! You're free!</span>"
/obj/item/card/id/prisoner/one
icon_state = "prisoner_001"
name = "Prisoner #13-001"
registered_name = "Prisoner #13-001"
/obj/item/card/id/prisoner/two
icon_state = "prisoner_002"
name = "Prisoner #13-002"
registered_name = "Prisoner #13-002"
/obj/item/card/id/prisoner/three
icon_state = "prisoner_003"
name = "Prisoner #13-003"
registered_name = "Prisoner #13-003"
/obj/item/card/id/prisoner/four
icon_state = "prisoner_004"
name = "Prisoner #13-004"
registered_name = "Prisoner #13-004"
/obj/item/card/id/prisoner/five
icon_state = "prisoner_005"
name = "Prisoner #13-005"
registered_name = "Prisoner #13-005"
/obj/item/card/id/prisoner/six
icon_state = "prisoner_006"
name = "Prisoner #13-006"
registered_name = "Prisoner #13-006"
/obj/item/card/id/prisoner/seven
icon_state = "prisoner_007"
name = "Prisoner #13-007"
registered_name = "Prisoner #13-007"
/obj/item/card/id/mining
name = "mining ID"
icon_state = "retro"
access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/away
name = "a perfectly generic identification card"
desc = "A perfectly generic identification card. Looks like it could use some flavor."
icon_state = "retro"
access = list(ACCESS_AWAY_GENERAL)
/obj/item/card/id/away/hotel
@@ -691,6 +735,7 @@ update_label("John Doe", "Clowny")
/obj/item/card/id/departmental_budget
name = "departmental card (FUCK)"
desc = "Provides access to the departmental budget."
icon_state = "budgetcard"
var/department_ID = ACCOUNT_CIV
var/department_name = ACCOUNT_CIV_NAME
@@ -703,6 +748,7 @@ update_label("John Doe", "Clowny")
B.bank_cards += src
name = "departmental card ([department_name])"
desc = "Provides access to the [department_name]."
icon_state = "[lowertext(department_ID)]_budget"
SSeconomy.dep_cards += src
/obj/item/card/id/departmental_budget/Destroy()
+1 -1
View File
@@ -65,7 +65,7 @@
. = ..()
AddElement(/datum/element/update_icon_blocker)
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0, stam_cost = 0)
if(field)
field_disconnect(field)
..()
+6 -1
View File
@@ -8,6 +8,9 @@ CIGARS
SMOKING PIPES
CHEAP LIGHTERS
ZIPPO
ROLLING PAPER
VAPES
BONGS
CIGARETTE PACKETS ARE IN FANCY.DM
*/
@@ -506,7 +509,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
resistance_flags = FIRE_PROOF
light_color = LIGHT_COLOR_FIRE
grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/oil = 5)
custom_price = 55
custom_price = PRICE_ALMOST_CHEAP
/obj/item/lighter/Initialize()
. = ..()
@@ -616,6 +619,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
desc = "A cheap-as-free lighter."
icon_state = "lighter"
fancy = FALSE
custom_price = PRICE_CHEAP_AS_FREE
overlay_list = list(
"transp",
"tall",
@@ -799,6 +803,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_chat(user, "<span class='warning'>You need to close the cap first!</span>")
/obj/item/clothing/mask/vape/dropped(mob/user)
. = ..()
var/mob/living/carbon/C = user
if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
@@ -14,6 +14,10 @@
name = "Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security
/obj/item/circuitboard/computer/security/shuttle
name = "Shuttlelinking Security Cameras (Computer Board)"
build_path = /obj/machinery/computer/security/shuttle
/obj/item/circuitboard/computer/xenobiology
name = "circuit board (Xenobiology Console)"
build_path = /obj/machinery/computer/camera_advanced/xenobio
@@ -293,6 +297,10 @@
name = "Mining Shuttle (Computer Board)"
build_path = /obj/machinery/computer/shuttle/mining
/obj/item/circuitboard/computer/snow_taxi
name = "Snow Taxi (Computer Board)"
build_path = /obj/machinery/computer/shuttle/snow_taxi
/obj/item/circuitboard/computer/white_ship
name = "White Ship (Computer Board)"
build_path = /obj/machinery/computer/shuttle/white_ship
@@ -375,3 +383,11 @@
/obj/item/circuitboard/computer/nanite_cloud_controller
name = "Nanite Cloud Control (Computer Board)"
build_path = /obj/machinery/computer/nanite_cloud_controller
/obj/item/circuitboard/computer/shuttle/flight_control
name = "Shuttle Flight Control (Computer Board)"
build_path = /obj/machinery/computer/custom_shuttle
/obj/item/circuitboard/computer/shuttle/docker
name = "Shuttle Navigation Computer (Computer Board)"
build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/custom
@@ -1102,3 +1102,28 @@
/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/scanning_module = 2
)
/obj/item/circuitboard/machine/shuttle/engine
name = "Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine
req_components = list()
/obj/item/circuitboard/machine/shuttle/engine/plasma
name = "Plasma Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine/plasma
req_components = list(/obj/item/stock_parts/capacitor = 2,
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/micro_laser = 1)
/obj/item/circuitboard/machine/shuttle/engine/void
name = "Void Thruster (Machine Board)"
build_path = /obj/machinery/shuttle/engine/void
req_components = list(/obj/item/stock_parts/capacitor/quadratic = 2,
/obj/item/stack/cable_coil = 5,
/obj/item/stock_parts/micro_laser/quadultra = 1)
/obj/item/circuitboard/machine/shuttle/heater
name = "Electronic Engine Heater (Machine Board)"
build_path = /obj/machinery/atmospherics/components/unary/shuttle/heater
req_components = list(/obj/item/stock_parts/micro_laser = 2,
/obj/item/stock_parts/matter_bin = 1)
@@ -1,7 +1,7 @@
/obj/item/flashlight
name = "flashlight"
desc = "A hand-held emergency light."
custom_price = 100
custom_price = PRICE_REALLY_CHEAP
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight"
item_state = "flashlight"
@@ -211,6 +211,7 @@
light_color = "#CDDDFF"
flashlight_power = 0.9
hitsound = 'sound/weapons/genhit1.ogg'
custom_price = PRICE_ALMOST_CHEAP
// the desk lamps are a bit special
/obj/item/flashlight/lamp
@@ -351,12 +352,13 @@
brightness_on = 6 // luminosity when on
light_color = "#FFAA44"
flashlight_power = 0.8
custom_price = PRICE_CHEAP
/obj/item/flashlight/lantern/jade
name = "jade lantern"
desc = "An ornate, green lantern."
color = LIGHT_COLOR_GREEN
light_color = LIGHT_COLOR_GREEN
light_color = LIGHT_COLOR_GREEN
/obj/item/flashlight/slime
gender = PLURAL
@@ -429,7 +431,7 @@
/obj/item/flashlight/glowstick
name = "glowstick"
desc = "A military-grade glowstick."
custom_price = 50
custom_price = PRICE_CHEAP_AS_FREE
w_class = WEIGHT_CLASS_SMALL
brightness_on = 4
color = LIGHT_COLOR_GREEN
+6 -3
View File
@@ -6,12 +6,14 @@ T-RAY
HEALTH ANALYZER
GAS ANALYZER
SLIME SCANNER
NANITE SCANNER
GENETICS SCANNER
*/
/obj/item/t_scanner
name = "\improper T-ray scanner"
desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
custom_price = 150
custom_price = PRICE_REALLY_CHEAP
icon = 'icons/obj/device.dmi'
icon_state = "t-ray0"
var/on = FALSE
@@ -653,9 +655,10 @@ SLIME SCANNER
amount += inaccurate
return DisplayTimeText(max(1,amount))
/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src)
/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src, visible = TRUE)
var/icon = target
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(user))] [target].", "<span class='notice'>You use the analyzer on [icon2html(icon, user)] [target].</span>")
if(visible)
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(user))] [target].", "<span class='notice'>You use the analyzer on [icon2html(icon, user)] [target].</span>")
to_chat(user, "<span class='boldnotice'>Results of analysis of [icon2html(icon, user)] [target].</span>")
var/list/airs = islist(mixture) ? mixture : list(mixture)
@@ -5,7 +5,7 @@
icon_state = "scanner"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
custom_price = 900
custom_price = PRICE_ABOVE_EXPENSIVE
/obj/item/sensor_device/attack_self(mob/user)
GLOB.crewmonitor.show(user,src) //Proc already exists, just had to call it
@@ -7,7 +7,8 @@
var/forced_value = 0
var/duration = 300
/obj/item/grenade/antigravity/prime()
/obj/item/grenade/antigravity/prime(mob/living/lanced_by)
. = ..()
update_mob()
for(var/turf/T in view(range,src))
@@ -174,10 +174,11 @@
message_admins(message)
user.log_message("primed [src] ([reagent_string])",LOG_GAME)
/obj/item/grenade/chem_grenade/prime()
/obj/item/grenade/chem_grenade/prime(mob/living/lanced_by)
if(stage != READY)
return FALSE
. = ..()
var/list/datum/reagents/reactants = list()
for(var/obj/item/reagent_containers/glass/G in beakers)
reactants += G.reagents
@@ -217,7 +218,7 @@
ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades.
threatscale = 1.1 // 10% more effective.
/obj/item/grenade/chem_grenade/large/prime()
/obj/item/grenade/chem_grenade/large/prime(mob/living/lanced_by)
if(stage != READY)
return FALSE
@@ -286,7 +287,7 @@
return
..()
/obj/item/grenade/chem_grenade/adv_release/prime()
/obj/item/grenade/chem_grenade/adv_release/prime(mob/living/lanced_by)
if(stage != READY)
return FALSE
@@ -14,7 +14,8 @@
var/max_spawned = 8
var/segment_chance = 35
/obj/item/grenade/clusterbuster/prime()
/obj/item/grenade/clusterbuster/prime(mob/living/lanced_by)
. = ..()
update_mob()
var/numspawned = rand(min_spawned,max_spawned)
var/again = 0
@@ -59,7 +60,7 @@
step_away(src,loc)
addtimer(CALLBACK(src, .proc/prime), rand(15,60))
/obj/item/grenade/clusterbuster/segment/prime()
/obj/item/grenade/clusterbuster/segment/prime(mob/living/lanced_by)
new payload_spawner(drop_location(), payload, rand(min_spawned,max_spawned))
playsound(src, prime_sound, 75, 1, -3)
qdel(src)
@@ -4,7 +4,8 @@
icon_state = "emp"
item_state = "emp"
/obj/item/grenade/empgrenade/prime()
/obj/item/grenade/empgrenade/prime(mob/living/lanced_by)
. = ..()
update_mob()
empulse(src, 4, 10)
qdel(src)
+91 -1
View File
@@ -6,7 +6,8 @@
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
var/flashbang_range = 7 //how many tiles away the mob will be stunned.
/obj/item/grenade/flashbang/prime()
/obj/item/grenade/flashbang/prime(mob/living/lanced_by)
. = ..()
update_mob()
var/flashbang_turf = get_turf(src)
if(!flashbang_turf)
@@ -42,3 +43,92 @@
var/distance = get_dist(get_turf(M), source)
if(M.flash_act(affect_silicon = 1))
M.DefaultCombatKnockdown(max(200/max(1,distance), 60))
/obj/item/grenade/stingbang
name = "stingbang"
icon_state = "timeg"
item_state = "flashbang"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
var/flashbang_range = 1 //how many tiles away the mob will be stunned.
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball
shrapnel_radius = 5
custom_premium_price = 700 // mostly gotten through cargo, but throw in one for the sec vendor ;)
/obj/item/grenade/stingbang/mega
name = "mega stingbang"
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball/mega
shrapnel_radius = 12
/obj/item/grenade/stingbang/prime(mob/living/lanced_by)
if(iscarbon(loc))
var/mob/living/carbon/C = loc
var/obj/item/bodypart/B = C.get_holding_bodypart_of_item(src)
if(B)
C.visible_message("<b><span class='danger'>[src] goes off in [C]'s hand, blowing [C.p_their()] [B.name] to bloody shreds!</span></b>", "<span class='userdanger'>[src] goes off in your hand, blowing your [B.name] to bloody shreds!</span>")
B.dismember()
. = ..()
update_mob()
var/flashbang_turf = get_turf(src)
if(!flashbang_turf)
return
do_sparks(rand(5, 9), FALSE, src)
playsound(flashbang_turf, 'sound/weapons/flashbang.ogg', 50, TRUE, 8, 0.9)
new /obj/effect/dummy/lighting_obj (flashbang_turf, LIGHT_COLOR_WHITE, (flashbang_range + 2), 2, 1)
for(var/mob/living/M in get_hearers_in_view(flashbang_range, flashbang_turf))
pop(get_turf(M), M)
qdel(src)
/obj/item/grenade/stingbang/proc/pop(turf/T , mob/living/M)
if(M.stat == DEAD) //They're dead!
return
M.show_message("<span class='warning'>POP</span>", MSG_AUDIBLE)
var/distance = max(0,get_dist(get_turf(src),T))
//Flash
if(M.flash_act(affect_silicon = 1))
M.Paralyze(max(10/max(1,distance), 5))
M.Knockdown(max(100/max(1,distance), 60))
//Bang
if(!distance || loc == M || loc == M.loc)
M.Paralyze(20)
M.Knockdown(200)
M.soundbang_act(1, 200, 10, 15)
if(M.apply_damages(10, 10))
to_chat(M, "<span class='userdanger'>The blast from \the [src] bruises and burns you!</span>")
// only checking if they're on top of the tile, cause being one tile over will be its own punishment
// Grenade that releases more shrapnel the more times you use it in hand between priming and detonation (sorta like the 9bang from MW3), for admin goofs
/obj/item/grenade/primer
name = "rotfrag grenade"
desc = "A grenade that generates more shrapnel the more you rotate it in your hand after pulling the pin. This one releases shrapnel shards."
icon_state = "timeg"
item_state = "flashbang"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
var/rots_per_mag = 3 /// how many times we need to "rotate" the charge in hand per extra tile of magnitude
shrapnel_type = /obj/item/projectile/bullet/shrapnel
var/rots = 1 /// how many times we've "rotated" the charge
/obj/item/grenade/primer/attack_self(mob/user)
. = ..()
if(active)
user.playsound_local(user, 'sound/misc/box_deploy.ogg', 50, TRUE)
rots++
user.changeNext_move(CLICK_CD_RAPID)
/obj/item/grenade/primer/prime(mob/living/lanced_by)
shrapnel_radius = round(rots / rots_per_mag)
. = ..()
qdel(src)
/obj/item/grenade/primer/stingbang
name = "rotsting"
desc = "A grenade that generates more shrapnel the more you rotate it in your hand after pulling the pin. This one releases stingballs."
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
rots_per_mag = 2
shrapnel_type = /obj/item/projectile/bullet/pellet/stingball
@@ -45,12 +45,13 @@
/obj/item/grenade/iedcasing/attack_self(mob/user) //
if(!active)
if(clown_check(user))
if(!botch_check(user))
to_chat(user, "<span class='warning'>You light the [name]!</span>")
cut_overlay("improvised_grenade_filled")
preprime(user, null, FALSE)
/obj/item/grenade/iedcasing/prime() //Blowing that can up
/obj/item/grenade/iedcasing/prime(mob/living/lanced_by) //Blowing that can up
. = ..()
update_mob()
explosion(src.loc,-1,-1,2, flame_range = 4) // small explosion, plus a very large fireball.
qdel(src)
+45 -6
View File
@@ -17,10 +17,31 @@
var/det_time = 50
var/display_timer = 1
var/clumsy_check = GRENADE_CLUMSY_FUMBLE
var/sticky = FALSE
// I moved the explosion vars and behavior to base grenades because we want all grenades to call [/obj/item/grenade/proc/prime] so we can send COMSIG_GRENADE_PRIME
///how big of a devastation explosion radius on prime
var/ex_dev = 0
///how big of a heavy explosion radius on prime
var/ex_heavy = 0
///how big of a light explosion radius on prime
var/ex_light = 0
///how big of a flame explosion radius on prime
var/ex_flame = 0
// dealing with creating a [/datum/component/pellet_cloud] on prime
/// if set, will spew out projectiles of this type
var/shrapnel_type
/// the higher this number, the more projectiles are created as shrapnel
var/shrapnel_radius
var/shrapnel_initialized
/obj/item/grenade/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user] primes [src], then eats it! It looks like [user.p_theyre()] trying to commit suicide!</span>")
if(shrapnel_type && shrapnel_radius)
shrapnel_initialized = TRUE
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_radius)
playsound(src, 'sound/items/eatfood.ogg', 50, 1)
SEND_SIGNAL(src, COMSIG_GRENADE_ARMED, det_time)
preprime(user, det_time)
user.transferItemToLoc(src, user, TRUE)//>eat a grenade set to 5 seconds >rush captain
sleep(det_time)//so you dont die instantly
@@ -32,19 +53,21 @@
if(!QDELETED(src))
qdel(src)
/obj/item/grenade/proc/clown_check(mob/living/carbon/human/user)
/obj/item/grenade/proc/botch_check(mob/living/carbon/human/user)
var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY)
if(clumsy)
if(clumsy_check == GRENADE_CLUMSY_FUMBLE && prob(50))
to_chat(user, "<span class='warning'>Huh? How does this thing work?</span>")
preprime(user, 5, FALSE)
return FALSE
return TRUE
else if(clumsy_check == GRENADE_NONCLUMSY_FUMBLE && !(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY)))
to_chat(user, "<span class='warning'>You pull the pin on [src]. Attached to it is a pink ribbon that says, \"<span class='clown'>HONK</span>\"</span>")
preprime(user, 5, FALSE)
return FALSE
return TRUE
return TRUE
else if(sticky && prob(50)) // to add risk to sticky tape grenade cheese, no return cause we still prime as normal after
to_chat(user, "<span class='warning'>What the... [src] is stuck to your hand!</span>")
ADD_TRAIT(src, TRAIT_NODROP, STICKY_NODROP)
/obj/item/grenade/examine(mob/user)
. = ..()
@@ -56,8 +79,16 @@
/obj/item/grenade/attack_self(mob/user)
if(HAS_TRAIT(src, TRAIT_NODROP))
to_chat(user, "<span class='notice'>You try prying [src] off your hand...</span>")
if(do_after(user, 70, target=src))
to_chat(user, "<span class='notice'>You manage to remove [src] from your hand.</span>")
REMOVE_TRAIT(src, TRAIT_NODROP, STICKY_NODROP)
return
if(!active)
if(clown_check(user))
if(!botch_check(user)) // if they botch the prime, it'll be handled in botch_check
preprime(user)
/obj/item/grenade/proc/log_grenade(mob/user, turf/T)
@@ -81,10 +112,18 @@
icon_state = initial(icon_state) + "_active"
addtimer(CALLBACK(src, .proc/prime), isnull(delayoverride)? det_time : delayoverride)
/obj/item/grenade/proc/prime()
/obj/item/grenade/proc/prime(mob/living/lanced_by)
var/turf/T = get_turf(src)
log_game("Grenade detonation at [AREACOORD(T)], location [loc]")
if(shrapnel_type && shrapnel_radius && !shrapnel_initialized) // add a second check for adding the component in case whatever triggered the grenade went straight to prime (badminnery for example)
shrapnel_initialized = TRUE
AddComponent(/datum/component/pellet_cloud, projectile_type=shrapnel_type, magnitude=shrapnel_radius)
SEND_SIGNAL(src, COMSIG_GRENADE_PRIME, lanced_by)
if(ex_dev || ex_heavy || ex_light || ex_flame)
explosion(loc, ex_dev, ex_heavy, ex_light, flame_range = ex_flame)
/obj/item/grenade/proc/update_mob()
if(ismob(loc))
var/mob/M = loc
+5 -2
View File
@@ -122,7 +122,9 @@
var/obj/item/I = AM
I.throw_speed = max(1, (I.throw_speed - 3))
I.throw_range = max(1, (I.throw_range - 3))
I.embedding = I.embedding.setRating(embed_chance = 0)
if(I.embedding)
I.embedding["embed_chance"] = 0
I.updateEmbedding()
target.add_overlay(plastic_overlay, TRUE)
if(!nadeassembly)
@@ -205,9 +207,10 @@
else
return ..()
/obj/item/grenade/plastic/c4/prime()
/obj/item/grenade/plastic/c4/prime(mob/living/lanced_by)
if(QDELETED(src))
return
. = ..()
var/turf/location
if(target)
if(!QDELETED(target))
@@ -17,7 +17,8 @@
qdel(smoke)
return ..()
/obj/item/grenade/smokebomb/prime()
/obj/item/grenade/smokebomb/prime(mob/living/lanced_by)
. = ..()
update_mob()
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.set_up(4, src)
@@ -7,7 +7,8 @@
var/spawner_type = null // must be an object path
var/deliveryamt = 1 // amount of type to deliver
/obj/item/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it.
/obj/item/grenade/spawnergrenade/prime(mob/living/lanced_by) // Prime now just handles the two loops that query for people in lockers and people who can see it.
. = ..()
update_mob()
if(spawner_type && deliveryamt)
// Make a quick flash
@@ -4,27 +4,45 @@
icon = 'icons/obj/grenade.dmi'
icon_state = "syndicate"
item_state = "flashbang"
ex_dev = 1
ex_heavy = 2
ex_light = 4
ex_flame = 2
/obj/item/grenade/syndieminibomb/prime()
/obj/item/grenade/syndieminibomb/prime(mob/living/lanced_by)
. = ..()
update_mob()
explosion(src.loc,1,2,4,flame_range = 2)
qdel(src)
/obj/item/grenade/syndieminibomb/concussion
name = "HE Grenade"
desc = "A compact shrapnel grenade meant to devastate nearby organisms and cause some damage in the process. Pull pin and throw opposite direction."
icon_state = "concussion"
ex_heavy = 2
ex_light = 3
ex_flame = 3
/obj/item/grenade/syndieminibomb/concussion/prime()
update_mob()
explosion(src.loc,0,2,3,flame_range = 3)
qdel(src)
/obj/item/grenade/syndieminibomb/concussion/frag
/obj/item/grenade/frag
name = "frag grenade"
desc = "Fire in the hole."
desc = "An anti-personnel fragmentation grenade, this weapon excels at killing soft targets by shredding them with metal shrapnel."
icon_state = "frag"
shrapnel_type = /obj/item/projectile/bullet/shrapnel
shrapnel_radius = 4
ex_heavy = 1
ex_light = 3
ex_flame = 4
/obj/item/grenade/frag/mega
name = "FRAG grenade"
desc = "An anti-everything fragmentation grenade, this weapon excels at killing anything any everything by shredding them with metal shrapnel."
shrapnel_type = /obj/item/projectile/bullet/shrapnel/mega
shrapnel_radius = 12
/obj/item/grenade/frag/prime(mob/living/lanced_by)
. = ..()
update_mob()
qdel(src)
/obj/item/grenade/gluon
desc = "An advanced grenade that releases a harmful stream of gluons inducing radiation in those nearby. These gluon streams will also make victims feel exhausted, and induce shivering. This extreme coldness will also likely wet any nearby floors."
@@ -36,7 +54,8 @@
var/rad_damage = 350
var/stamina_damage = 30
/obj/item/grenade/gluon/prime()
/obj/item/grenade/gluon/prime(mob/living/lanced_by)
. = ..()
update_mob()
playsound(loc, 'sound/effects/empulse.ogg', 50, 1)
radiation_pulse(src, rad_damage)
+6 -3
View File
@@ -71,7 +71,7 @@
sharpness = IS_SHARP_ACCURATE
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/bayonet = FALSE //Can this be attached to a gun?
custom_price = 250
custom_price = PRICE_NORMAL
/obj/item/kitchen/knife/Initialize()
. = ..()
@@ -131,13 +131,14 @@
custom_materials = list(/datum/material/iron=18000)
attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
w_class = WEIGHT_CLASS_NORMAL
custom_price = 600
custom_price = PRICE_EXPENSIVE
/obj/item/kitchen/knife/combat
name = "combat knife"
icon_state = "buckknife"
item_state = "knife"
desc = "A military combat utility survival knife."
embedding = list("pain_mult" = 4, "embed_chance" = 65, "fall_chance" = 10, "ignore_throwspeed_threshold" = TRUE)
force = 20
throwforce = 20
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut")
@@ -148,6 +149,7 @@
icon_state = "survivalknife"
item_state = "knife"
desc = "A hunting grade survival knife."
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10)
force = 15
throwforce = 15
bayonet = TRUE
@@ -159,6 +161,7 @@
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
desc = "A sharpened bone. The bare minimum in survival."
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10)
force = 15
throwforce = 15
custom_materials = null
@@ -200,7 +203,7 @@
w_class = WEIGHT_CLASS_NORMAL
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 1.5)
attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked")
custom_price = 200
custom_price = PRICE_ALMOST_CHEAP
/obj/item/kitchen/rollingpin/suicide_act(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user] begins flattening [user.p_their()] head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
+26 -2
View File
@@ -103,11 +103,30 @@
throw_speed = 3
throw_range = 5
sharpness = IS_SHARP
embedding = list("embed_chance" = 75, "embedded_impact_pain_multiplier" = 10)
embedding = list("embed_chance" = 75, "impact_pain_mult" = 10)
armour_penetration = 35
block_chance = 50
item_flags = NEEDS_PERMIT | ITEM_CAN_PARRY
block_parry_data = /datum/block_parry_data/energy_sword
var/list/possible_colors = list("red" = LIGHT_COLOR_RED, "blue" = LIGHT_COLOR_LIGHT_CYAN, "green" = LIGHT_COLOR_GREEN, "purple" = LIGHT_COLOR_LAVENDER)
/datum/block_parry_data/energy_sword
parry_time_windup = 0
parry_time_active = 25
parry_time_spindown = 0
// we want to signal to players the most dangerous phase, the time when automatic counterattack is a thing.
parry_time_windup_visual_override = 1
parry_time_active_visual_override = 3
parry_time_spindown_visual_override = 12
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK // esword users can attack while
parry_time_perfect = 2.5 // first ds isn't perfect
parry_time_perfect_leeway = 1.5
parry_imperfect_falloff_percent = 5
parry_efficiency_to_counterattack = 100
parry_efficiency_considered_successful = 65 // VERY generous
parry_efficiency_perfect = 100
parry_failed_stagger_duration = 4 SECONDS
parry_cooldown = 0.5 SECONDS
/obj/item/melee/transforming/energy/sword/Initialize(mapload)
. = ..()
set_sword_color()
@@ -273,6 +292,10 @@
light_color = "#37FFF7"
actions_types = list()
/obj/item/melee/transforming/energy/sword/cx/Initialize()
icon_state_on = icon_state
return ..()
/obj/item/melee/transforming/energy/sword/cx/ComponentInitialize()
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
@@ -290,6 +313,7 @@
if(!supress_message_text)
to_chat(user, "<span class='notice'>[src] [active ? "is now active":"can now be concealed"].</span>")
/obj/item/melee/transforming/energy/sword/cx/update_overlays()
. = ..()
var/mutable_appearance/blade_overlay = mutable_appearance(icon, "cxsword_blade")
+51 -10
View File
@@ -61,13 +61,25 @@
force = 18
throwforce = 15
w_class = WEIGHT_CLASS_BULKY
block_chance = 50
armour_penetration = 75
sharpness = IS_SHARP
attack_verb = list("slashed", "cut")
hitsound = 'sound/weapons/rapierhit.ogg'
custom_materials = list(/datum/material/iron = 1000)
total_mass = 3.4
item_flags = NEEDS_PERMIT | ITEM_CAN_PARRY
block_parry_data = /datum/block_parry_data/captain_saber
/datum/block_parry_data/captain_saber
parry_time_windup = 0.5
parry_time_active = 4
parry_time_spindown = 1
parry_time_perfect = 0.75
parry_time_perfect_leeway = 0.75
parry_imperfect_falloff_percent = 30
parry_efficiency_perfect = 100
parry_failed_stagger_duration = 3 SECONDS
parry_failed_clickcd_duration = 2 SECONDS
/obj/item/melee/sabre/Initialize()
. = ..()
@@ -150,7 +162,6 @@
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
force = 15
throwforce = 25
block_chance = 50
armour_penetration = 200 //Apparently this gives it the ability to pierce block
flags_1 = CONDUCT_1
obj_flags = UNIQUE_RENAME
@@ -159,16 +170,47 @@
attack_verb = list("stabs", "punctures", "pierces", "pokes")
hitsound = 'sound/weapons/rapierhit.ogg'
total_mass = 0.4
item_flags = ITEM_CAN_PARRY | NEEDS_PERMIT
block_parry_data = /datum/block_parry_data/traitor_rapier
// Fast, efficient parry.
/datum/block_parry_data/traitor_rapier
parry_time_windup = 0.5
parry_time_active = 5
parry_time_spindown = 0
parry_time_active_visual_override = 3
parry_time_spindown_visual_override = 2
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING
parry_time_perfect = 0
parry_time_perfect_leeway = 3
parry_time_perfect_leeway_override = list(
TEXT_ATTACK_TYPE_PROJECTILE = 1
)
parry_imperfect_falloff_percent_override = list(
TEXT_ATTACK_TYPE_PROJECTILE = 50 // useless after 3rd decisecond
)
parry_imperfect_falloff_percent = 30
parry_efficiency_to_counterattack = 100
parry_efficiency_considered_successful = 1
parry_efficiency_perfect = 100
parry_data = list(
PARRY_DISARM_ATTACKER = TRUE,
PARRY_KNOCKDOWN_ATTACKER = 10
)
parry_failed_stagger_duration = 2 SECONDS
parry_failed_clickcd_duration = CLICK_CD_RANGE
parry_cooldown = 0
/obj/item/melee/rapier/active_parry_reflex_counter(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, list/return_list, parry_efficiency, list/effect_text)
. = ..()
if((attack_type & ATTACK_TYPE_PROJECTILE) && (parry_efficiency >= 100))
. |= BLOCK_SHOULD_REDIRECT
return_list[BLOCK_RETURN_REDIRECT_METHOD] = REDIRECT_METHOD_DEFLECT
/obj/item/melee/rapier/Initialize()
. = ..()
AddComponent(/datum/component/butchering, 20, 65, 0)
/obj/item/melee/rapier/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(attack_type == ATTACK_TYPE_PROJECTILE)
final_block_chance = 0
return ..()
/obj/item/melee/rapier/on_exit_storage(datum/component/storage/S)
var/obj/item/storage/belt/sabre/rapier/B = S.parent
if(istype(B))
@@ -191,10 +233,9 @@
. = ..()
if(iscarbon(target))
var/mob/living/carbon/H = target
var/loss = H.getStaminaLoss()
H.Dizzy(10)
H.adjustStaminaLoss(30)
if((loss > 40) && prob(loss)) // if above 40, roll for sleep using 1% every 1 stamina damage
if(CHECK_STAMCRIT(H) != NOT_STAMCRIT)
H.Sleeping(180)
/obj/item/melee/classic_baton
@@ -664,4 +705,4 @@
. = ..()
overlay = mutable_appearance(icon, overlay_state)
overlay.appearance_flags = RESET_COLOR
add_overlay(overlay)
add_overlay(overlay)
@@ -53,6 +53,8 @@
throw_speed = 4
if(attack_verb_on.len)
attack_verb = attack_verb_on
if(embedding)
updateEmbedding()
icon_state = icon_state_on
w_class = w_class_on
else
@@ -62,6 +64,8 @@
throw_speed = initial(throw_speed)
if(attack_verb_off.len)
attack_verb = attack_verb_off
if(embedding)
updateEmbedding()
icon_state = initial(icon_state)
w_class = initial(w_class)
total_mass = initial(total_mass)
+38
View File
@@ -115,6 +115,44 @@
new /obj/item/toy/crayon/spraycan(src)
new /obj/item/clothing/shoes/sandal(src)
/obj/item/choice_beacon/hosgun
name = "personal weapon beacon"
desc = "Use this to summon your personal Head of Security issued firearm!"
/obj/item/choice_beacon/hosgun/generate_display_names()
var/static/list/hos_gun_list
if(!hos_gun_list)
hos_gun_list = list()
var/list/templist = subtypesof(/obj/item/storage/secure/briefcase/hos/) //we have to convert type = name to name = type, how lovely!
for(var/V in templist)
var/atom/A = V
hos_gun_list[initial(A.name)] = A
return hos_gun_list
/obj/item/choice_beacon/augments
name = "augment beacon"
desc = "Summons augmentations."
/obj/item/choice_beacon/augments/generate_display_names()
var/static/list/augment_list
if(!augment_list)
augment_list = list()
var/list/templist = list(
/obj/item/organ/cyberimp/brain/anti_drop,
/obj/item/organ/cyberimp/arm/toolset,
/obj/item/organ/cyberimp/arm/surgery,
/obj/item/organ/cyberimp/chest/thrusters,
/obj/item/organ/lungs/cybernetic,
/obj/item/organ/liver/cybernetic) //cyberimplants range from a nice bonus to fucking broken bullshit so no subtypesof
for(var/V in templist)
var/atom/A = V
augment_list[initial(A.name)] = A
return augment_list
/obj/item/choice_beacon/augments/spawn_option(obj/choice,mob/living/M)
new choice(get_turf(M))
to_chat(M, "<span class='hear'>You hear something crackle from the beacon for a moment before a voice speaks. \"Please stand by for a message from S.E.L.F. Message as follows: <b>Item request received. Your package has been transported, use the autosurgeon supplied to apply the upgrade.</b> Message ends.\"</span>")
/obj/item/skub
desc = "It's skub."
name = "skub"
+18 -1
View File
@@ -78,7 +78,7 @@
name = "crew pinpointer"
desc = "A handheld tracking device that points to crew suit sensors."
icon_state = "pinpointer_crew"
custom_price = 600
custom_price = PRICE_ABOVE_EXPENSIVE
var/has_owner = FALSE
var/pinpointer_owner = null
@@ -183,3 +183,20 @@
A.other_pair = B
B.other_pair = A
/obj/item/pinpointer/shuttle
name = "fugitive pinpointer"
desc = "A handheld tracking device that locates the bounty hunter shuttle for quick escapes."
icon_state = "pinpointer_hunter"
var/obj/shuttleport
/obj/item/pinpointer/shuttle/Initialize(mapload)
. = ..()
shuttleport = SSshuttle.getShuttle("huntership")
/obj/item/pinpointer/shuttle/scan_for_target()
target = shuttleport
/obj/item/pinpointer/shuttle/Destroy()
shuttleport = null
. = ..()
+5 -4
View File
@@ -140,7 +140,8 @@
if(jsonlist["icon_state"])
icon_state = jsonlist["icon_state"]
item_state = jsonlist["item_state"]
icon = 'config/plushies/sprites.dmi'
var/static/config_sprites = file("config/plushies/sprites.dmi")
icon = config_sprites
if(jsonlist["attack_verb"])
attack_verb = jsonlist["attack_verb"]
if(jsonlist["squeak_override"])
@@ -436,13 +437,13 @@ GLOBAL_LIST_INIT(valid_plushie_paths, valid_plushie_paths())
/obj/item/toy/plush/random/Initialize()
var/newtype
var/list/snowflake_list = CONFIG_GET(keyed_list/snowflake_plushies)
/// If there are no snowflake plushies we'll default to base plush, so we grab from the valid list
if (snowflake_list.len)
newtype = prob(CONFIG_GET(number/snowflake_plushie_prob)) ? /obj/item/toy/plush/random_snowflake : pick(GLOB.valid_plushie_paths)
else
else
newtype = pick(GLOB.valid_plushie_paths)
new newtype(loc)
return INITIALIZE_HINT_QDEL
+42 -37
View File
@@ -6,6 +6,7 @@
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
flags_1 = CONDUCT_1
item_flags = NEEDS_PERMIT | NO_COMBAT_MODE_FORCE_MODIFIER //To avoid ambushing and oneshotting healthy crewmembers on force setting 3.
attack_verb = list("whacked", "fisted", "power-punched")
force = 20
throwforce = 10
@@ -13,7 +14,7 @@
w_class = WEIGHT_CLASS_NORMAL
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 40)
resistance_flags = FIRE_PROOF
var/click_delay = 1.5
click_delay = CLICK_CD_MELEE * 1.5
var/fisto_setting = 1
var/gasperfist = 3
var/obj/item/tank/internals/tank = null //Tank used for the gauntlet's piston-ram.
@@ -70,42 +71,46 @@
/obj/item/melee/powerfist/attack(mob/living/target, mob/living/user)
if(!tank)
to_chat(user, "<span class='warning'>\The [src] can't operate without a source of gas!</span>")
return
var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
var/turf/T = get_turf(src)
if(!T)
return
T.assume_air(gasused)
T.air_update_turf()
if(!gasused)
to_chat(user, "<span class='warning'>\The [src]'s tank is empty!</span>")
target.apply_damage((force / 5), BRUTE)
playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
target.visible_message("<span class='danger'>[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>[user]'s punches you!</span>")
return
if(gasused.total_moles() < gasperfist * fisto_setting)
to_chat(user, "<span class='warning'>\The [src]'s piston-ram lets out a weak hiss, it needs more gas!</span>")
playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
target.apply_damage((force / 2), BRUTE)
target.visible_message("<span class='danger'>[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>[user]'s punch strikes with force!</span>")
return
target.apply_damage(force * fisto_setting, BRUTE)
target.visible_message("<span class='danger'>[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>You cry out in pain as [user]'s punch flings you backwards!</span>")
new /obj/effect/temp_visual/kinetic_blast(target.loc)
playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1)
playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
return FALSE
if(!tank)
to_chat(user, "<span class='warning'>\The [src] can't operate without a source of gas!</span>")
return FALSE
var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
var/turf/T = get_turf(src)
if(!T)
return FALSE
var/totalitemdamage = target.pre_attacked_by(src, user)
T.assume_air(gasused)
T.air_update_turf()
if(!gasused)
to_chat(user, "<span class='warning'>\The [src]'s tank is empty!</span>")
target.apply_damage((totalitemdamage / 5), BRUTE)
playsound(loc, 'sound/weapons/punch1.ogg', 50, 1)
target.visible_message("<span class='danger'>[user]'s powerfist lets out a dull thunk as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>[user]'s punches you!</span>")
return
if(gasused.total_moles() < gasperfist * fisto_setting)
to_chat(user, "<span class='warning'>\The [src]'s piston-ram lets out a weak hiss, it needs more gas!</span>")
playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
target.apply_damage((totalitemdamage / 2), BRUTE)
target.visible_message("<span class='danger'>[user]'s powerfist lets out a weak hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>[user]'s punch strikes with force!</span>")
return
target.apply_damage(totalitemdamage * fisto_setting, BRUTE)
target.visible_message("<span class='danger'>[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!</span>", \
"<span class='userdanger'>You cry out in pain as [user]'s punch flings you backwards!</span>")
new /obj/effect/temp_visual/kinetic_blast(target.loc)
playsound(loc, 'sound/weapons/resonator_blast.ogg', 50, 1)
playsound(loc, 'sound/weapons/genhit2.ogg', 50, 1)
var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
var/atom/throw_target = get_edge_target_turf(target, get_dir(src, get_step_away(target, src)))
target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2))
target.throw_at(throw_target, 5 * fisto_setting, 0.5 + (fisto_setting / 2))
log_combat(user, target, "power fisted", src)
log_combat(user, target, "power fisted", src)
user.changeNext_move(CLICK_CD_MELEE * click_delay)
return
var/weight = getweight(user, STAM_COST_ATTACK_MOB_MULT)
if(weight)
user.adjustStaminaLossBuffered(weight)
return TRUE
+2 -1
View File
@@ -215,8 +215,9 @@
/obj/item/clothing/head/helmet/plate/crusader/prophet
name = "Prophet's Hat"
desc = "A religious-looking hat."
icon_state = "prophet"
mob_overlay_icon = 'icons/mob/large-worn-icons/64x64/head.dmi'
flags_1 = 0
flags_1 = NONE
armor = list("melee" = 60, "bullet" = 60, "laser" = 60, "energy" = 50, "bomb" = 70, "bio" = 50, "rad" = 50, "fire" = 60, "acid" = 60) //religion protects you from disease and radiation, honk.
worn_x_dimension = 64
worn_y_dimension = 64
@@ -358,6 +358,7 @@
check_amount()
/obj/item/borg/lollipop/dropped(mob/user)
. = ..()
check_amount()
/obj/item/borg/lollipop/proc/check_amount() //Doesn't even use processing ticks.
@@ -545,7 +545,7 @@
to_chat(usr, "<span class='notice'>This unit already has an expand module installed!</span>")
return FALSE
R.notransform = TRUE
R.mob_transforming = TRUE
var/prev_locked_down = R.locked_down
R.SetLockdown(1)
R.anchored = TRUE
@@ -559,7 +559,7 @@
if(!prev_locked_down)
R.SetLockdown(0)
R.anchored = FALSE
R.notransform = FALSE
R.mob_transforming = FALSE
R.resize = 2
R.hasExpanded = TRUE
R.update_transform()
+44 -29
View File
@@ -1,7 +1,8 @@
/obj/item/shield
name = "shield"
icon = 'icons/obj/shields.dmi'
block_chance = 50
item_flags = ITEM_CAN_BLOCK
block_parry_data = /datum/block_parry_data/shield
armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 70)
/// Shield flags
var/shield_flags = SHIELD_FLAGS_DEFAULT
@@ -22,6 +23,18 @@
/// Shield bashing push distance
var/shieldbash_push_distance = 1
/datum/block_parry_data/shield
block_damage_multiplier = 0.25
block_stamina_efficiency = 2.5
block_stamina_cost_per_second = 3.5
block_slowdown = 0
block_lock_attacking = FALSE
block_lock_sprinting = TRUE
block_start_delay = 1.5
block_damage_absorption = 5
block_resting_stamina_penalty_multiplier = 2
block_projectile_mitigation = 75
/obj/item/shield/examine(mob/user)
. = ..()
if(shield_flags & SHIELD_CAN_BASH)
@@ -154,6 +167,22 @@
icon_state = "shield_bash"
duration = 3
/obj/item/shield/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(ismovable(object))
var/atom/movable/AM = object
if(CHECK_BITFIELD(shield_flags, SHIELD_TRANSPARENT) && (AM.pass_flags & PASSGLASS))
return BLOCK_NONE
if(attack_type & ATTACK_TYPE_THROWN)
final_block_chance += 30
if(attack_type & ATTACK_TYPE_TACKLE)
final_block_chance = 100
. = ..()
if(. & BLOCK_SUCCESS)
on_shield_block(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
/obj/item/shield/on_active_block(mob/living/owner, atom/object, damage, damage_blocked, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return, override_direction)
on_shield_block(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance)
/obj/item/shield/riot
name = "riot shield"
desc = "A shield adept at blocking blunt objects from connecting with the torso of the shield wielder."
@@ -172,20 +201,7 @@
var/repair_material = /obj/item/stack/sheet/mineral/titanium
var/can_shatter = TRUE
shield_flags = SHIELD_FLAGS_DEFAULT | SHIELD_TRANSPARENT
max_integrity = 75
/obj/item/shield/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(ismovable(object))
var/atom/movable/AM = object
if(CHECK_BITFIELD(shield_flags, SHIELD_TRANSPARENT) && (AM.pass_flags & PASSGLASS))
return BLOCK_NONE
if(attack_type & ATTACK_TYPE_THROWN)
final_block_chance += 30
if(attack_type & ATTACK_TYPE_TACKLE)
final_block_chance = 100
. = ..()
if(. & BLOCK_SUCCESS)
on_shield_block(owner, object, damage, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
max_integrity = 450
/obj/item/shield/riot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/melee/baton))
@@ -238,13 +254,13 @@
lefthand_file = 'icons/mob/inhands/equipment/shields_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
shield_flags = SHIELD_FLAGS_DEFAULT
max_integrity = 55 //Weak
max_integrity = 300
obj/item/shield/riot/bullet_proof
name = "bullet resistant shield"
desc = "A far more frail shield made of resistant plastics and kevlar meant to block ballistics."
armor = list("melee" = 30, "bullet" = 80, "laser" = 0, "energy" = 0, "bomb" = -40, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50)
max_integrity = 55 //Weaker
max_integrity = 300
/obj/item/shield/riot/roman
name = "\improper Roman shield"
@@ -255,13 +271,13 @@ obj/item/shield/riot/bullet_proof
righthand_file = 'icons/mob/inhands/equipment/shields_righthand.dmi'
repair_material = /obj/item/stack/sheet/mineral/wood
shield_flags = SHIELD_FLAGS_DEFAULT
max_integrity = 65
max_integrity = 250
/obj/item/shield/riot/roman/fake
desc = "Bears an inscription on the inside: <i>\"Romanes venio domus\"</i>. It appears to be a bit flimsy."
block_chance = 0
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
max_integrity = 30
max_integrity = 40
/obj/item/shield/riot/roman/shatter(mob/living/carbon/human/owner)
playsound(owner, 'sound/effects/grillehit.ogg', 100)
@@ -279,7 +295,7 @@ obj/item/shield/riot/bullet_proof
repair_material = /obj/item/stack/sheet/mineral/wood
block_chance = 30
shield_flags = SHIELD_FLAGS_DEFAULT
max_integrity = 55
max_integrity = 150
/obj/item/shield/riot/buckler/shatter(mob/living/carbon/human/owner)
playsound(owner, 'sound/effects/bang.ogg', 50)
@@ -297,13 +313,16 @@ obj/item/shield/riot/bullet_proof
throw_speed = 3
throw_range = 4
w_class = WEIGHT_CLASS_NORMAL
var/active = 0
var/active = FALSE
/obj/item/shield/riot/tele/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!active)
return BLOCK_NONE
return ..()
/obj/item/shield/riot/tele/can_active_block()
return ..() && active
/obj/item/shield/riot/tele/attack_self(mob/living/user)
active = !active
icon_state = "teleriot[active]"
@@ -335,8 +354,7 @@ obj/item/shield/riot/bullet_proof
icon_state = "makeshift_shield"
custom_materials = list(/datum/material/iron = 18000)
slot_flags = null
block_chance = 35
max_integrity = 100 //Made of metal welded together its strong but not unkillable
max_integrity = 300 //Made of metal welded together its strong but not unkillable
force = 10
throwforce = 7
@@ -346,7 +364,6 @@ obj/item/shield/riot/bullet_proof
armor = list("melee" = 95, "bullet" = 95, "laser" = 75, "energy" = 60, "bomb" = 90, "bio" = 90, "rad" = 0, "fire" = 90, "acid" = 10) //Armor for the item, dosnt transfer to user
item_state = "metal"
icon_state = "metal"
block_chance = 75 //1/4 shots will hit*
force = 16
slowdown = 2
throwforce = 15 //Massive pice of metal
@@ -357,19 +374,17 @@ obj/item/shield/riot/bullet_proof
/obj/item/shield/riot/tower/swat
name = "swat shield"
desc = "A massive, heavy shield that can block a lot of attacks, can take a lot of abuse before breaking."
max_integrity = 175
block_chance = 50
max_integrity = 250
/obj/item/shield/riot/implant
name = "telescoping shield implant"
desc = "A compact, arm-mounted telescopic shield. While nigh-indestructible when powered by a host user, it will eventually overload from damage. Recharges while inside its implant."
item_state = "metal"
icon_state = "metal"
block_chance = 50
slowdown = 1
shield_flags = SHIELD_FLAGS_DEFAULT
max_integrity = 60
obj_integrity = 60
max_integrity = 100
obj_integrity = 100
can_shatter = FALSE
item_flags = SLOWS_WHILE_IN_HAND
var/recharge_timerid
+64
View File
@@ -0,0 +1,64 @@
/obj/item/shrapnel // frag grenades
name = "shrapnel shard"
embedding = list(embed_chance=70, ignore_throwspeed_threshold=TRUE, fall_chance=4, embed_chance_turf_mod=-100)
custom_materials = list(/datum/material/iron=50)
armour_penetration = -20
icon = 'icons/obj/shards.dmi'
icon_state = "large"
w_class = WEIGHT_CLASS_TINY
item_flags = DROPDEL
/obj/item/shrapnel/stingball // stingbang grenades
name = "stingball"
embedding = list(embed_chance=90, fall_chance=3, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.7, pain_mult=5, jostle_pain_mult=6, rip_time=15, embed_chance_turf_mod=-100)
icon_state = "tiny"
/obj/item/shrapnel/bullet // bullets
name = "bullet"
icon = 'icons/obj/ammo.dmi'
icon_state = "s-casing"
item_flags = NONE
/obj/item/shrapnel/bullet/c38 // .38 round
name = "\improper .38 bullet"
/obj/item/shrapnel/bullet/c38/dumdum // .38 DumDum round
name = "\improper .38 DumDum bullet"
embedding = list(embed_chance=70, fall_chance=7, jostle_chance=7, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10, embed_chance_turf_mod=-100)
/obj/item/projectile/bullet/shrapnel
name = "flying shrapnel shard"
damage = 9
range = 10
armour_penetration = -30
dismemberment = 5
ricochets_max = 2
ricochet_chance = 40
shrapnel_type = /obj/item/shrapnel
ricochet_incidence_leeway = 60
/obj/item/projectile/bullet/shrapnel/mega
name = "flying shrapnel hunk"
range = 25
dismemberment = 10
ricochets_max = 4
ricochet_chance = 90
ricochet_decay_chance = 0.9
/obj/item/projectile/bullet/pellet/stingball
name = "stingball pellet"
damage = 3
stamina = 8
ricochets_max = 4
ricochet_chance = 66
ricochet_decay_chance = 1
ricochet_decay_damage = 0.9
ricochet_auto_aim_angle = 10
ricochet_auto_aim_range = 2
ricochet_incidence_leeway = 0
shrapnel_type = /obj/item/shrapnel/stingball
/obj/item/projectile/bullet/pellet/stingball/mega
name = "megastingball pellet"
ricochets_max = 6
ricochet_chance = 110
+122 -2
View File
@@ -13,18 +13,33 @@
novariants = FALSE
item_flags = NOBLUDGEON
var/self_delay = 50
var/other_delay = 0
var/repeating = FALSE
/obj/item/stack/medical/attack(mob/living/M, mob/user)
. = ..()
try_heal(M, user)
/obj/item/stack/medical/proc/try_heal(mob/living/M, mob/user, silent = FALSE)
if(!M.can_inject(user, TRUE))
return
if(M == user)
user.visible_message("<span class='notice'>[user] starts to apply \the [src] on [user.p_them()]self...</span>", "<span class='notice'>You begin applying \the [src] on yourself...</span>")
if(!silent)
user.visible_message("<span class='notice'>[user] starts to apply \the [src] on [user.p_them()]self...</span>", "<span class='notice'>You begin applying \the [src] on yourself...</span>")
if(!do_mob(user, M, self_delay, extra_checks=CALLBACK(M, /mob/living/proc/can_inject, user, TRUE)))
return
else if(other_delay)
if(!silent)
user.visible_message("<span class='notice'>[user] starts to apply \the [src] on [M].</span>", "<span class='notice'>You begin applying \the [src] on [M]...</span>")
if(!do_mob(user, M, other_delay, extra_checks=CALLBACK(M, /mob/living/proc/can_inject, user, TRUE)))
return
if(heal(M, user))
log_combat(user, M, "healed", src.name)
use(1)
if(repeating && amount > 0)
try_heal(M, user, TRUE)
/obj/item/stack/medical/proc/heal(mob/living/M, mob/user)
@@ -96,7 +111,7 @@
var/stop_bleeding = 1800
var/heal_brute = 5
self_delay = 10
custom_price = 100
custom_price = PRICE_REALLY_CHEAP
/obj/item/stack/medical/gauze/heal(mob/living/M, mob/user)
if(ishuman(M))
@@ -174,3 +189,108 @@
/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
user.visible_message("<span class='suicide'>[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?</span>")
return TOXLOSS
/obj/item/stack/medical/suture
name = "suture"
desc = "Sterile sutures used to seal up cuts and lacerations."
gender = PLURAL
singular_name = "suture"
icon_state = "suture"
self_delay = 30
other_delay = 10
amount = 15
max_amount = 15
repeating = TRUE
var/heal_brute = 10
grind_results = list(/datum/reagent/medicine/spaceacillin = 2)
/obj/item/stack/medical/suture/one
amount = 1
/obj/item/stack/medical/suture/heal(mob/living/M, mob/user)
. = ..()
if(M.stat == DEAD)
to_chat(user, "<span class='warning'>[M] is dead! You can not help [M.p_them()].</span>")
return
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, 0)
if(isanimal(M))
var/mob/living/simple_animal/critter = M
if (!(critter.healable))
to_chat(user, "<span class='warning'>You cannot use \the [src] on [M]!</span>")
return FALSE
else if (critter.health == critter.maxHealth)
to_chat(user, "<span class='notice'>[M] is at full health.</span>")
return FALSE
user.visible_message("<span class='green'>[user] applies \the [src] on [M].</span>", "<span class='green'>You apply \the [src] on [M].</span>")
M.heal_bodypart_damage(heal_brute)
return TRUE
to_chat(user, "<span class='warning'>You can't heal [M] with the \the [src]!</span>")
/obj/item/stack/medical/mesh
name = "regenerative mesh"
desc = "A bacteriostatic mesh used to dress burns."
gender = PLURAL
singular_name = "regenerative mesh"
icon_state = "regen_mesh"
self_delay = 30
other_delay = 10
amount = 15
max_amount = 15
repeating = TRUE
var/heal_burn = 10
var/is_open = TRUE ///This var determines if the sterile packaging of the mesh has been opened.
grind_results = list(/datum/reagent/medicine/spaceacillin = 2)
/obj/item/stack/medical/mesh/one
amount = 1
/obj/item/stack/medical/mesh/Initialize()
. = ..()
if(amount == max_amount) //only seal full mesh packs
is_open = FALSE
update_icon()
/obj/item/stack/medical/mesh/update_icon_state()
if(!is_open)
icon_state = "regen_mesh_closed"
else
return ..()
/obj/item/stack/medical/mesh/heal(mob/living/M, mob/user)
. = ..()
if(M.stat == DEAD)
to_chat(user, "<span class='warning'>[M] is dead! You can not help [M.p_them()].</span>")
return
if(iscarbon(M))
return heal_carbon(M, user, 0, heal_burn)
to_chat(user, "<span class='warning'>You can't heal [M] with the \the [src]!</span>")
/obj/item/stack/medical/mesh/try_heal(mob/living/M, mob/user, silent = FALSE)
if(!is_open)
to_chat(user, "<span class='warning'>You need to open [src] first.</span>")
return
. = ..()
/obj/item/stack/medical/mesh/AltClick(mob/living/user)
if(!is_open)
to_chat(user, "<span class='warning'>You need to open [src] first.</span>")
return
. = ..()
/obj/item/stack/medical/mesh/attack_hand(mob/user)
if(!is_open & user.get_inactive_held_item() == src)
to_chat(user, "<span class='warning'>You need to open [src] first.</span>")
return
. = ..()
/obj/item/stack/medical/mesh/attack_self(mob/user)
if(!is_open)
is_open = TRUE
to_chat(user, "<span class='notice'>You open the sterile mesh package.</span>")
update_icon()
playsound(src, 'sound/items/poster_ripped.ogg', 20, TRUE)
return
. = ..()
+1
View File
@@ -21,6 +21,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
max_amount = 50
attack_verb = list("hit", "bludgeoned", "whacked")
hitsound = 'sound/weapons/grenadelaunch.ogg'
embedding = list()
novariants = TRUE
/obj/item/stack/rods/suicide_act(mob/living/carbon/user)
@@ -291,6 +291,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
max_integrity = 40
sharpness = IS_SHARP
var/icon_prefix
embedding = list("embed_chance" = 65)
/obj/item/shard/suicide_act(mob/user)
@@ -242,6 +242,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
null, \
new/datum/stack_recipe("wooden firearm body", /obj/item/weaponcrafting/improvised_parts/wooden_body, 10, time = 40), \
new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \
new/datum/stack_recipe("pistol grip", /obj/item/weaponcrafting/improvised_parts/wooden_grip, 5, time = 40), \
new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 30), \
new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/glass/bucket/wood, 2, time = 30), \
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
@@ -778,6 +779,9 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
/obj/item/stack/sheet/plastic/fifty
amount = 50
/obj/item/stack/sheet/plastic/twenty
amount = 20
/obj/item/stack/sheet/plastic/five
amount = 5
+61
View File
@@ -0,0 +1,61 @@
/obj/item/stack/sticky_tape
name = "sticky tape"
singular_name = "sticky tape"
desc = "Used for sticking to things for sticking said things to people."
icon = 'icons/obj/tapes.dmi'
icon_state = "tape_w"
var/prefix = "sticky"
item_flags = NOBLUDGEON
amount = 5
max_amount = 5
resistance_flags = FLAMMABLE
var/list/conferred_embed = EMBED_HARMLESS
var/overwrite_existing = FALSE
/obj/item/stack/sticky_tape/afterattack(obj/item/I, mob/living/user)
if(!istype(I))
return
if(I.embedding && I.embedding == conferred_embed)
to_chat(user, "<span class='warning'>[I] is already coated in [src]!</span>")
return
user.visible_message("<span class='notice'>[user] begins wrapping [I] with [src].</span>", "<span class='notice'>You begin wrapping [I] with [src].</span>")
if(do_after(user, 30, target=I))
I.embedding = conferred_embed
I.updateEmbedding()
to_chat(user, "<span class='notice'>You finish wrapping [I] with [src].</span>")
use(1)
I.name = "[prefix] [I.name]"
if(istype(I, /obj/item/grenade))
var/obj/item/grenade/sticky_bomb = I
sticky_bomb.sticky = TRUE
/obj/item/stack/sticky_tape/super
name = "super sticky tape"
singular_name = "super sticky tape"
desc = "Quite possibly the most mischevious substance in the galaxy. Use with extreme lack of caution."
icon_state = "tape_y"
prefix = "super sticky"
conferred_embed = EMBED_HARMLESS_SUPERIOR
/obj/item/stack/sticky_tape/pointy
name = "pointy tape"
singular_name = "pointy tape"
desc = "Used for sticking to things for sticking said things inside people."
icon_state = "tape_evil"
prefix = "pointy"
conferred_embed = EMBED_POINTY
/obj/item/stack/sticky_tape/pointy/super
name = "super pointy tape"
singular_name = "super pointy tape"
desc = "You didn't know tape could look so sinister. Welcome to Space Station 13."
icon_state = "tape_spikes"
prefix = "super pointy"
conferred_embed = EMBED_POINTY_SUPERIOR
@@ -266,6 +266,9 @@
/obj/item/stack/tile/carpet/blackred/twenty
amount = 20
/obj/item/stack/tile/carpet/blackred/thirty
amount = 30
/obj/item/stack/tile/carpet/blackred/fifty
amount = 50
@@ -275,6 +278,9 @@
/obj/item/stack/tile/carpet/monochrome/twenty
amount = 20
/obj/item/stack/tile/carpet/monochrome/thirty
amount = 30
/obj/item/stack/tile/carpet/monochrome/fifty
amount = 50
@@ -284,6 +290,9 @@
/obj/item/stack/tile/carpet/blue/twenty
amount = 20
/obj/item/stack/tile/carpet/blue/thirty
amount = 30
/obj/item/stack/tile/carpet/blue/fifty
amount = 50
@@ -293,6 +302,9 @@
/obj/item/stack/tile/carpet/cyan/twenty
amount = 20
/obj/item/stack/tile/carpet/cyan/thirty
amount = 30
/obj/item/stack/tile/carpet/cyan/fifty
amount = 50
@@ -302,6 +314,9 @@
/obj/item/stack/tile/carpet/green/twenty
amount = 20
/obj/item/stack/tile/carpet/green/thirty
amount = 30
/obj/item/stack/tile/carpet/green/fifty
amount = 50
@@ -311,6 +326,9 @@
/obj/item/stack/tile/carpet/orange/twenty
amount = 20
/obj/item/stack/tile/carpet/orange/thirty
amount = 30
/obj/item/stack/tile/carpet/orange/fifty
amount = 50
@@ -320,6 +338,9 @@
/obj/item/stack/tile/carpet/purple/twenty
amount = 20
/obj/item/stack/tile/carpet/purple/thirty
amount = 30
/obj/item/stack/tile/carpet/purple/fifty
amount = 50
@@ -329,6 +350,9 @@
/obj/item/stack/tile/carpet/red/twenty
amount = 20
/obj/item/stack/tile/carpet/red/thirty
amount = 30
/obj/item/stack/tile/carpet/red/fifty
amount = 50
@@ -338,6 +362,9 @@
/obj/item/stack/tile/carpet/royalblack/twenty
amount = 20
/obj/item/stack/tile/carpet/royalblack/thirty
amount = 30
/obj/item/stack/tile/carpet/royalblack/fifty
amount = 50
@@ -347,6 +374,9 @@
/obj/item/stack/tile/carpet/royalblue/twenty
amount = 20
/obj/item/stack/tile/carpet/royalblue/thirty
amount = 30
/obj/item/stack/tile/carpet/royalblue/fifty
amount = 50
+23 -5
View File
@@ -382,16 +382,16 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "bag"
desc = "A bag for storing pills, patches, and bottles."
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_POCKET
resistance_flags = FLAMMABLE
/obj/item/storage/bag/chemistry/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = 200
STR.max_items = 50
STR.storage_flags = STORAGE_FLAGS_VOLUME_DEFAULT
STR.max_volume = STORAGE_VOLUME_CHEMISTRY_BAG
STR.insert_preposition = "in"
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart))
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/syringe/dart, /obj/item/reagent_containers/chem_pack))
/*
* Biowaste bag (mostly for xenobiologists)
@@ -402,7 +402,7 @@
icon = 'icons/obj/chemical.dmi'
icon_state = "biobag"
desc = "A bag for the safe transportation and disposal of biowaste and other biological materials."
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT|ITEM_SLOT_POCKET
resistance_flags = FLAMMABLE
/obj/item/storage/bag/bio/ComponentInitialize()
@@ -427,3 +427,21 @@
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_combined_w_class = INFINITY
STR.max_items = 100
/obj/item/storage/bag/ammo
name = "ammo pouch"
desc = "A pouch for your ammo that goes in your pocket."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "ammopouch"
slot_flags = ITEM_SLOT_POCKET
w_class = WEIGHT_CLASS_BULKY
resistance_flags = FLAMMABLE
/obj/item/storage/bag/ammo/ComponentInitialize()
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_w_class = WEIGHT_CLASS_NORMAL
STR.max_combined_w_class = 30
STR.max_items = 3
STR.display_numerical_stacking = FALSE
STR.can_hold = typecacheof(list(/obj/item/ammo_box/magazine, /obj/item/ammo_casing))
+13 -12
View File
@@ -180,7 +180,8 @@
/obj/item/implantcase,
/obj/item/implant,
/obj/item/implanter,
/obj/item/pinpointer/crew
/obj/item/pinpointer/crew,
/obj/item/reagent_containers/chem_pack
))
/obj/item/storage/belt/medical/surgery_belt_adv
@@ -512,16 +513,16 @@
new /obj/item/grenade/smokebomb(src)
new /obj/item/grenade/empgrenade(src)
new /obj/item/grenade/empgrenade(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/syndieminibomb/concussion/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/frag(src)
new /obj/item/grenade/gluon(src)
new /obj/item/grenade/gluon(src)
new /obj/item/grenade/gluon(src)
@@ -713,7 +714,7 @@
icon_state = "fannypack_leather"
item_state = "fannypack_leather"
dying_key = DYE_REGISTRY_FANNYPACK
custom_price = 100
custom_price = PRICE_ALMOST_CHEAP
/obj/item/storage/belt/fannypack/ComponentInitialize()
. = ..()
+15 -3
View File
@@ -275,6 +275,16 @@
for(var/i in 1 to 7)
new /obj/item/grenade/flashbang(src)
obj/item/storage/box/stingbangs
name = "box of stingbangs (WARNING)"
desc = "<B>WARNING: These devices are extremely dangerous and can cause severe injuries or death in repeated use.</B>"
icon_state = "secbox"
illustration = "flashbang"
/obj/item/storage/box/stingbangs/PopulateContents()
for(var/i in 1 to 5)
new /obj/item/grenade/stingbang(src)
/obj/item/storage/box/flashes
name = "box of flashbulbs"
desc = "<B>WARNING: Flashes can cause serious eye damage, protective eyewear is required.</B>"
@@ -434,6 +444,7 @@
desc = "<B>Instructions:</B> <I>Heat in microwave. Product will cool if not eaten within seven minutes.</I>"
icon_state = "donkpocketbox"
illustration=null
custom_premium_price = PRICE_ABOVE_NORMAL // git gud
/obj/item/storage/box/donkpockets/ComponentInitialize()
. = ..()
@@ -622,7 +633,7 @@
item_state = "zippo"
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT
custom_price = 20
custom_price = PRICE_REALLY_CHEAP
/obj/item/storage/box/matches/ComponentInitialize()
. = ..()
@@ -744,8 +755,8 @@
//////
/obj/item/storage/box/hug/medical/PopulateContents()
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/ointment(src)
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/mesh(src)
new /obj/item/reagent_containers/hypospray/medipen(src)
// Clown survival box
@@ -1343,6 +1354,7 @@
name = "box of marshmallows"
desc = "A box of marshmallows."
illustration = "marshmallow"
custom_premium_price = PRICE_BELOW_NORMAL
/obj/item/storage/box/marshmallow/PopulateContents()
for (var/i in 1 to 5)
+22 -2
View File
@@ -70,6 +70,7 @@
name = "donut box"
spawn_type = /obj/item/reagent_containers/food/snacks/donut
fancy_open = TRUE
custom_price = PRICE_NORMAL
/obj/item/storage/fancy/donut_box/ComponentInitialize()
. = ..()
@@ -136,7 +137,23 @@
slot_flags = ITEM_SLOT_BELT
icon_type = "cigarette"
spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette
custom_price = 75
custom_price = PRICE_ALMOST_CHEAP
var/spawn_coupon = TRUE
/obj/item/storage/fancy/cigarettes/attack_self(mob/user)
if(contents.len == 0 && spawn_coupon)
to_chat(user, "<span class='notice'>You rip the back off \the [src] and get a coupon!</span>")
var/obj/item/coupon/attached_coupon = new
user.put_in_hands(attached_coupon)
attached_coupon.generate()
attached_coupon = null
spawn_coupon = FALSE
name = "discarded cigarette packet"
desc = "An old cigarette packet with the back torn off, worth less than nothing now."
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.max_items = 0
return
return ..()
/obj/item/storage/fancy/cigarettes/ComponentInitialize()
. = ..()
@@ -147,6 +164,8 @@
/obj/item/storage/fancy/cigarettes/examine(mob/user)
. = ..()
. += "<span class='notice'>Alt-click to extract contents.</span>"
if(spawn_coupon)
. += "<span class='notice'>There's a coupon on the back of the pack! You can tear it off once it's empty.</span>"
/obj/item/storage/fancy/cigarettes/AltClick(mob/living/carbon/user)
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
@@ -278,7 +297,7 @@
///The value in here has NOTHING to do with icons. It needs to be this for the proper examine.
icon_type = "rolling paper"
spawn_type = /obj/item/rollingpaper
custom_price = 25
custom_price = PRICE_REALLY_CHEAP
/obj/item/storage/fancy/rollingpapers/ComponentInitialize()
. = ..()
@@ -307,6 +326,7 @@
w_class = WEIGHT_CLASS_NORMAL
icon_type = "premium cigar"
spawn_type = /obj/item/clothing/mask/cigarette/cigar
spawn_coupon = FALSE
/obj/item/storage/fancy/cigarettes/cigars/ComponentInitialize()
. = ..()
+15 -14
View File
@@ -37,10 +37,10 @@
if(empty)
return
new /obj/item/stack/medical/gauze(src)
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/ointment(src)
new /obj/item/stack/medical/ointment(src)
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/mesh(src)
new /obj/item/stack/medical/mesh(src)
new /obj/item/reagent_containers/hypospray/medipen(src)
new /obj/item/healthanalyzer(src)
@@ -52,12 +52,12 @@
if(empty)
return
new /obj/item/stack/medical/gauze(src)
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/ointment(src)
new /obj/item/stack/medical/ointment(src)
new /obj/item/stack/medical/ointment(src)
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/suture(src)
new /obj/item/stack/medical/mesh(src)
new /obj/item/stack/medical/mesh(src)
new /obj/item/stack/medical/mesh(src)
/obj/item/storage/firstaid/fire
name = "burn treatment kit"
@@ -224,7 +224,7 @@
. = ..()
var/datum/component/storage/STR = GetComponent(/datum/component/storage)
STR.storage_flags = STORAGE_FLAGS_VOLUME_DEFAULT
STR.max_volume = 14
STR.max_volume = STORAGE_VOLUME_PILL_BOTTLE
STR.allow_quick_gather = TRUE
STR.click_gather = TRUE
STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice))
@@ -426,7 +426,8 @@
/obj/item/circuitboard/computer/crew,
/obj/item/stack/sheet/glass,
/obj/item/stack/sheet/mineral/silver,
/obj/item/organ_storage
/obj/item/organ_storage,
/obj/item/reagent_containers/chem_pack
))
//hijacking the minature first aids for hypospray boxes. <3
@@ -440,8 +441,8 @@
throw_range = 7
var/empty = FALSE
item_state = "firstaid"
custom_price = 300
custom_premium_price = 500
custom_price = PRICE_ABOVE_NORMAL
custom_premium_price = PRICE_EXPENSIVE
/obj/item/storage/hypospraykit/ComponentInitialize()
. = ..()
+43 -10
View File
@@ -188,19 +188,52 @@
new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
/obj/item/storage/lockbox/medal/engineering
name = "engineering medal box"
desc = "A locked box used to store medals to be given to the members of the engineering department."
req_access = list(ACCESS_CE)
name = "engineering medal box"
desc = "A locked box used to store medals to be given to the members of the engineering department."
req_access = list(ACCESS_CE)
/obj/item/storage/lockbox/medal/engineering/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/accessory/medal/engineer(src)
for(var/i in 1 to 3)
new /obj/item/clothing/accessory/medal/engineer(src)
/obj/item/storage/lockbox/medal/medical
name = "medical medal box"
desc = "A locked box used to store medals to be given to the members of the medical department."
req_access = list(ACCESS_CMO)
name = "medical medal box"
desc = "A locked box used to store medals to be given to the members of the medical department."
req_access = list(ACCESS_CMO)
/obj/item/storage/lockbox/medal/medical/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/accessory/medal/ribbon/medical_doctor(src)
for(var/i in 1 to 3)
new /obj/item/clothing/accessory/medal/ribbon/medical_doctor(src)
/obj/item/storage/lockbox/order
name = "order lockbox"
desc = "A box used to secure small cargo orders from being looted by those who didn't order it. Yeah, cargo tech, that means you."
icon = 'icons/obj/storage.dmi'
icon_state = "secure"
item_state = "sec-case"
lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
w_class = WEIGHT_CLASS_HUGE
var/datum/bank_account/buyer_account
var/privacy_lock = TRUE
/obj/item/storage/lockbox/order/Initialize(datum/bank_account/_buyer_account)
. = ..()
buyer_account = _buyer_account
/obj/item/storage/lockbox/order/attackby(obj/item/W, mob/user, params)
if(!istype(W, /obj/item/card/id))
return ..()
var/obj/item/card/id/id_card = W
if(iscarbon(user))
add_fingerprint(user)
if(id_card.registered_account != buyer_account)
to_chat(user, "<span class='notice'>Bank account does not match with buyer!</span")
return
SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, !privacy_lock)
privacy_lock = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
user.visible_message("<span class='notice'>[user] [privacy_lock ? "" : "un"]locks [src]'s privacy lock.</span>",
"<span class='notice'>You [privacy_lock ? "" : "un"]lock [src]'s privacy lock.</span>")
+29
View File
@@ -147,6 +147,35 @@
for(var/i = 0, i < STR.max_items - 2, i++)
new /obj/item/stack/spacecash/c1000(src)
/obj/item/storage/secure/briefcase/mws_pack
name = "\improper \'MWS\' gun kit"
desc = "A storage case for a multi-purpose handgun. Variety hour!"
/obj/item/storage/secure/briefcase/mws_pack/PopulateContents()
new /obj/item/gun/ballistic/revolver/mws(src)
new /obj/item/ammo_box/magazine/mws_mag(src)
for(var/path in subtypesof(/obj/item/ammo_casing/mws_batt))
new path(src)
/obj/item/storage/secure/briefcase/hos/mws_pack_hos
name = "\improper \'MWS\' gun kit"
desc = "A storage case for a multi-purpose handgun. Variety hour!"
/obj/item/storage/secure/briefcase/hos/mws_pack_hos/PopulateContents()
new /obj/item/gun/ballistic/revolver/mws(src)
new /obj/item/ammo_box/magazine/mws_mag(src)
new /obj/item/ammo_casing/mws_batt/lethal(src)
new /obj/item/ammo_casing/mws_batt/lethal(src)
new /obj/item/ammo_casing/mws_batt/stun(src)
new /obj/item/ammo_casing/mws_batt/stun(src)
new /obj/item/ammo_casing/mws_batt/ion(src)
/obj/item/storage/secure/briefcase/hos/multiphase_box
name = "\improper X-01 Multiphase energy gun box"
desc = "A storage case for a high-tech energy firearm."
/obj/item/storage/secure/briefcase/hos/multiphase_box/PopulateContents()
new /obj/item/gun/energy/e_gun/hos(src)
// -----------------------------
// Secure Safe
+5 -3
View File
@@ -141,7 +141,7 @@
/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
var/interrupt = common_baton_melee(M, user, FALSE)
if(!interrupt)
..()
return ..()
/obj/item/melee/baton/alt_pre_attack(atom/A, mob/living/user, params)
. = common_baton_melee(A, user, TRUE) //return true (attackchain interrupt) if this also returns true. no harm-disarming.
@@ -154,7 +154,7 @@
if(turned_on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
clowning_around(user)
if(IS_STAMCRIT(user)) //CIT CHANGE - makes it impossible to baton in stamina softcrit
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")
to_chat(user, "<span class='danger'>You're too exhausted to use [src] properly.</span>")
return TRUE
if(ishuman(M))
var/mob/living/carbon/human/L = M
@@ -170,10 +170,12 @@
return disarming || (user.a_intent != INTENT_HARM)
/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user, disarming = FALSE)
if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; check_shields() handles that
var/list/return_list = list()
if(L.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, return_list) & BLOCK_SUCCESS) //No message; check_shields() handles that
playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
return FALSE
var/stunpwr = stamforce
stunpwr = block_calculate_resultant_damage(stunpwr, return_list)
var/obj/item/stock_parts/cell/our_cell = get_cell()
if(!our_cell)
switch_status(FALSE)
+4 -1
View File
@@ -93,11 +93,13 @@
F.update_icon()
else
return ..()
//Makes empty oxygen tanks spawn without gas
/obj/item/tank/internals/plasma/empty/populate_gas()
return
/obj/item/tank/internals/plasma/full/populate_gas()
air_contents.gases[/datum/gas/plasma] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
/*
* Plasmaman Plasma Tank
*/
@@ -130,6 +132,7 @@
air_contents.gases[/datum/gas/plasma] = (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)
return
//makes empty plasma tanks spawn without gas.
/obj/item/tank/internals/plasmaman/belt/empty/populate_gas()
return
+4
View File
@@ -153,6 +153,10 @@
return (BRUTELOSS)
/obj/item/tank/attack_ghost(mob/dead/observer/O)
. = ..()
atmosanalyzer_scan(air_contents, O, src, FALSE)
/obj/item/tank/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
if(istype(W, /obj/item/assembly_holder))
+1 -1
View File
@@ -145,7 +145,7 @@
desc = "A janitorial watertank backpack with nozzle to clean dirt and graffiti."
icon_state = "waterbackpackjani"
item_state = "waterbackpackjani"
custom_price = 1000
custom_price = PRICE_ALMOST_ONE_GRAND
/obj/item/watertank/janitor/Initialize()
. = ..()
+4 -3
View File
@@ -446,6 +446,7 @@
throw_range = 5
force_unwielded = 0
force_wielded = 0
block_parry_data = null
attack_verb = list("attacked", "struck", "hit")
total_mass_on = TOTAL_MASS_TOY_SWORD
sharpness = IS_BLUNT
@@ -835,11 +836,11 @@
/obj/item/toy/cards/deck/update_icon_state()
switch(cards.len)
if(INFINITY to original_size/2)
if(original_size*0.5 to INFINITY)
icon_state = "deck_[deckstyle]_full"
if(original_size/2 to original_size/4)
if(original_size*0.25 to original_size*0.5)
icon_state = "deck_[deckstyle]_half"
if(original_size/4 to 1)
if(1 to original_size*0.25)
icon_state = "deck_[deckstyle]_low"
else
icon_state = "deck_[deckstyle]_empty"
+100 -20
View File
@@ -30,6 +30,8 @@
var/wieldsound = null
var/unwieldsound = null
var/slowdown_wielded = 0
/// Do we need to be wielded to actively block/parry?
var/requires_wield_to_block_parry = TRUE
item_flags = SLOWS_WHILE_IN_HAND
/obj/item/twohanded/proc/unwield(mob/living/carbon/user, show_message = TRUE)
@@ -90,6 +92,12 @@
user.put_in_inactive_hand(O)
set_slowdown(slowdown + slowdown_wielded)
/obj/item/twohanded/can_active_block()
return ..() && (!requires_wield_to_block_parry || wielded)
/obj/item/twohanded/can_active_parry()
return ..() && (!requires_wield_to_block_parry || wielded)
/obj/item/twohanded/dropped(mob/user)
. = ..()
//handles unwielding a twohanded weapon when dropped as well as clearing up the offhand
@@ -129,6 +137,7 @@
return ..()
/obj/item/twohanded/offhand/dropped(mob/living/user, show_message = TRUE) //Only utilized by dismemberment since you can't normally switch to the offhand to drop it.
. = ..()
var/obj/I = user.get_active_held_item()
if(I && istype(I, /obj/item/twohanded))
var/obj/item/twohanded/thw = I
@@ -274,6 +283,8 @@
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
var/w_class_on = WEIGHT_CLASS_BULKY
item_flags = ITEM_CAN_PARRY | SLOWS_WHILE_IN_HAND | ITEM_CAN_BLOCK
block_parry_data = /datum/block_parry_data/dual_esword
force_unwielded = 3
force_wielded = 34
wieldsound = 'sound/weapons/saberon.ogg'
@@ -284,7 +295,6 @@
var/saber_color = "green"
light_color = "#00ff00"//green
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
block_chance = 75
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70)
resistance_flags = FIRE_PROOF
@@ -298,6 +308,42 @@
total_mass = 0.4 //Survival flashlights typically weigh around 5 ounces.
var/total_mass_on = 3.4
/datum/block_parry_data/dual_esword
block_damage_absorption = 2
block_damage_multiplier = 0.15
block_damage_multiplier_override = list(
ATTACK_TYPE_MELEE = 0.25
)
block_start_delay = 0 // instantaneous block
block_stamina_cost_per_second = 2.5
block_stamina_efficiency = 3
block_lock_sprinting = TRUE
// no attacking while blocking
block_lock_attacking = TRUE
block_projectile_mitigation = 75
parry_time_windup = 0
parry_time_active = 8
parry_time_spindown = 0
// we want to signal to players the most dangerous phase, the time when automatic counterattack is a thing.
parry_time_windup_visual_override = 1
parry_time_active_visual_override = 3
parry_time_spindown_visual_override = 4
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK // esword users can attack while parrying.
parry_time_perfect = 2 // first ds isn't perfect
parry_time_perfect_leeway = 1
parry_imperfect_falloff_percent = 10
parry_efficiency_to_counterattack = 100
parry_efficiency_considered_successful = 25 // VERY generous
parry_efficiency_perfect = 90
parry_failed_stagger_duration = 3 SECONDS
parry_failed_clickcd_duration = CLICK_CD_MELEE
// more efficient vs projectiles
block_stamina_efficiency_override = list(
TEXT_ATTACK_TYPE_PROJECTILE = 4
)
/obj/item/twohanded/dualsaber/suicide_act(mob/living/carbon/user)
if(wielded)
user.visible_message("<span class='suicide'>[user] begins spinning way too fast! It looks like [user.p_theyre()] trying to commit suicide!</span>")
@@ -582,7 +628,7 @@
force_wielded = 18
throwforce = 20
throw_speed = 4
embedding = list("embedded_impact_pain_multiplier" = 3, "embed_chance" = 90)
embedding = list("impact_pain_mult" = 3)
armour_penetration = 10
custom_materials = list(/datum/material/iron=1150, /datum/material/glass=2075)
hitsound = 'sound/weapons/bladeslice.ogg'
@@ -667,6 +713,7 @@
force_wielded = 19
force_unwielded = 11
throwforce = 21
embedding = list(embed_chance = 75, pain_mult = 1.5) //plasmaglass spears are sharper
icon_prefix = "spearplasma"
qdel(tip)
var/obj/item/twohanded/spear/S = locate() in parts_list
@@ -681,6 +728,7 @@
if(G)
explosive = G
name = "explosive lance"
embedding = list(embed_chance = 0, pain_mult = 1)//elances should not be embeddable
desc = "A makeshift spear with [G] attached to it."
update_icon()
@@ -847,6 +895,7 @@
return (BRUTELOSS)
/obj/item/twohanded/pitchfork/demonic/pickup(mob/living/user)
. = ..()
if(isliving(user) && user.mind && user.owns_soul() && !is_devil(user))
var/mob/living/U = user
U.visible_message("<span class='warning'>As [U] picks [src] up, [U]'s arms briefly catch fire.</span>", \
@@ -1028,13 +1077,12 @@
force_wielded = 10
throwforce = 15 //if you are a madman and finish someone off with this, power to you.
throw_speed = 1
item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND
block_chance = 30
item_flags = NO_MAT_REDEMPTION | SLOWS_WHILE_IN_HAND | ITEM_CAN_BLOCK | ITEM_CAN_PARRY
block_parry_data = /datum/block_parry_data/electrostaff
attack_verb = list("struck", "beaten", "thwacked", "pulped")
total_mass = 5 //yeah this is a heavy thing, beating people with it while it's off is not going to do you any favors. (to curb stun-kill rampaging without it being on)
var/obj/item/stock_parts/cell/cell = /obj/item/stock_parts/cell/high
var/on = FALSE
var/can_block_projectiles = FALSE //can't block guns
var/lethal_cost = 400 //10000/400*20 = 500. decent enough?
var/lethal_damage = 20
var/lethal_stam_cost = 4
@@ -1044,6 +1092,43 @@
var/stun_status_duration = 25
var/stun_stam_cost = 3.5
// haha security desword time /s
/datum/block_parry_data/electrostaff
block_damage_absorption = 0
block_damage_multiplier = 1
can_block_attack_types = ~ATTACK_TYPE_PROJECTILE // only able to parry non projectiles
block_damage_multiplier_override = list(
TEXT_ATTACK_TYPE_MELEE = 0.5, // only useful on melee and unarmed
TEXT_ATTACK_TYPE_UNARMED = 0.3
)
block_start_delay = 0.5 // near instantaneous block
block_stamina_cost_per_second = 3
block_stamina_efficiency = 2 // haha this is a horrible idea
// more slowdown that deswords because security
block_slowdown = 2
// no attacking while blocking
block_lock_attacking = TRUE
parry_time_windup = 1
parry_time_active = 5
parry_time_spindown = 0
parry_time_spindown_visual_override = 1
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK | PARRY_LOCK_ATTACKING // no attacking while parrying
parry_time_perfect = 0
parry_time_perfect_leeway = 0.5
parry_efficiency_perfect = 100
parry_imperfect_falloff_percent = 1
parry_imperfect_falloff_percent_override = list(
TEXT_ATTACK_TYPE_PROJECTILE = 45 // really crappy vs projectiles
)
parry_time_perfect_leeway_override = list(
TEXT_ATTACK_TYPE_PROJECTILE = 1 // extremely harsh window for projectiles
)
// not extremely punishing to fail, but no spamming the parry.
parry_cooldown = 2.5 SECONDS
parry_failed_stagger_duration = 1.5 SECONDS
parry_failed_clickcd_duration = 1 SECONDS
/obj/item/twohanded/electrostaff/Initialize(mapload)
. = ..()
if(ispath(cell))
@@ -1059,11 +1144,6 @@
var/mob/living/silicon/robot/R = loc
. = R.get_cell()
/obj/item/twohanded/electrostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
if(!on || (!can_block_projectiles && (attack_type & ATTACK_TYPE_PROJECTILE)))
return BLOCK_NONE
return ..()
/obj/item/twohanded/electrostaff/proc/min_hitcost()
return min(stun_cost, lethal_cost)
@@ -1174,30 +1254,30 @@
/obj/item/twohanded/electrostaff/attack(mob/living/target, mob/living/user)
if(IS_STAMCRIT(user))//CIT CHANGE - makes it impossible to baton in stamina softcrit
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")//CIT CHANGE - ditto
to_chat(user, "<span class='danger'>You're too exhausted to use [src] properly.</span>")//CIT CHANGE - ditto
return //CIT CHANGE - ditto
if(on && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
clowning_around(user) //ouch!
return
if(iscyborg(target))
..()
return
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, null) & BLOCK_SUCCESS) //No message; run_block() handles that
return ..()
var/list/return_list = list()
if(target.mob_run_block(src, 0, "[user]'s [name]", ATTACK_TYPE_MELEE, 0, user, null, return_list) & BLOCK_SUCCESS) //No message; run_block() handles that
playsound(target, 'sound/weapons/genhit.ogg', 50, 1)
return FALSE
if(user.a_intent != INTENT_HARM)
if(stun_act(target, user))
if(stun_act(target, user, null, return_list))
user.do_attack_animation(target)
user.adjustStaminaLossBuffered(stun_stam_cost)
return
else if(!harm_act(target, user))
else if(!harm_act(target, user, null, return_list))
return ..() //if you can't fry them just beat them with it
else //we did harm act them
user.do_attack_animation(target)
user.adjustStaminaLossBuffered(lethal_stam_cost)
/obj/item/twohanded/electrostaff/proc/stun_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE)
var/stunforce = stun_stamdmg
/obj/item/twohanded/electrostaff/proc/stun_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE, list/block_return = list())
var/stunforce = block_calculate_resultant_damage(stun_stamdmg, block_return)
if(!no_charge_and_force)
if(!on)
target.visible_message("<span class='warning'>[user] has bapped [target] with [src]. Luckily it was off.</span>", \
@@ -1227,8 +1307,8 @@
H.forcesay(GLOB.hit_appends)
return TRUE
/obj/item/twohanded/electrostaff/proc/harm_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE)
var/lethal_force = lethal_damage
/obj/item/twohanded/electrostaff/proc/harm_act(mob/living/target, mob/living/user, no_charge_and_force = FALSE, list/block_return = list())
var/lethal_force = block_calculate_resultant_damage(lethal_damage, block_return)
if(!no_charge_and_force)
if(!on)
return FALSE //standard item attack
+20 -2
View File
@@ -122,11 +122,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
/obj/item/claymore/highlander/pickup(mob/living/user)
. = ..()
to_chat(user, "<span class='notice'>The power of Scotland protects you! You are shielded from all stuns and knockdowns.</span>")
user.add_stun_absorption("highlander", INFINITY, 1, " is protected by the power of Scotland!", "The power of Scotland absorbs the stun!", " is protected by the power of Scotland!")
user.ignore_slowdown(HIGHLANDER)
/obj/item/claymore/highlander/dropped(mob/living/user)
. = ..()
user.unignore_slowdown(HIGHLANDER)
if(!QDELETED(src))
qdel(src) //If this ever happens, it's because you lost an arm
@@ -297,12 +299,28 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
force = 2
throwforce = 20 //This is never used on mobs since this has a 100% embed chance.
throw_speed = 4
embedding = list("embedded_pain_multiplier" = 4, "embed_chance" = 100, "embedded_fall_chance" = 0)
embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0, "embed_chance_turf_mod" = 15)
armour_penetration = 40
w_class = WEIGHT_CLASS_SMALL
sharpness = IS_SHARP
custom_materials = list(/datum/material/iron=500, /datum/material/glass=500)
resistance_flags = FIRE_PROOF
/obj/item/throwing_star/stamina
name = "shock throwing star"
desc = "An aerodynamic disc designed to cause excruciating pain when stuck inside fleeing targets, hopefully without causing fatal harm."
throwforce = 5
embedding = list("pain_chance" = 5, "embed_chance" = 100, "fall_chance" = 0, "jostle_chance" = 10, "pain_stam_pct" = 0.8, "jostle_pain_mult" = 3)
/obj/item/throwing_star/toy
name = "toy throwing star"
desc = "An aerodynamic disc strapped with adhesive for sticking to people, good for playing pranks and getting yourself killed by security."
sharpness = IS_BLUNT
force = 0
throwforce = 0
embedding = list("pain_mult" = 0, "jostle_pain_mult" = 0, "embed_chance" = 100, "fall_chance" = 0)
/obj/item/switchblade
name = "switchblade"
icon_state = "switchblade"
@@ -675,7 +693,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
to_chat(user, "<span class='warning'>You easily land a critical blow on the [target].</span>")
if(istype(target, /mob/living/))
var/mob/living/bug = target
bug.adjustBruteLoss(-35) //What kinda mad man would go into melee with a spider?!
bug.adjustBruteLoss(35) //What kinda mad man would go into melee with a spider?!
else
qdel(target)
+2 -1
View File
@@ -74,7 +74,8 @@
/obj/bullet_act(obj/item/projectile/P)
. = ..()
playsound(src, P.hitsound, 50, 1)
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>", null, null, COMBAT_MESSAGE_RANGE)
if(P.suppressed != SUPPRESSED_VERY)
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>", null, null, COMBAT_MESSAGE_RANGE)
if(!QDELETED(src)) //Bullet on_hit effect might have already destroyed this object
take_damage(P.damage, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration)
+5
View File
@@ -323,3 +323,8 @@
/obj/proc/rnd_crafted(obj/machinery/rnd/production/P)
return
/obj/handle_ricochet(obj/item/projectile/P)
. = ..()
if(. && ricochet_damage_mod)
take_damage(P.damage * ricochet_damage_mod, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration) // pass along ricochet_damage_mod damage to the structure for the ricochet
+2
View File
@@ -9,6 +9,8 @@
var/mob/living/structureclimber
var/broken = 0 //similar to machinery's stat BROKEN
layer = BELOW_OBJ_LAYER
flags_ricochet = RICOCHET_HARD
ricochet_chance_mod = 0.5
/obj/structure/Initialize()
if (!armor)
+2 -2
View File
@@ -41,7 +41,7 @@ LINEN BINS
return
/obj/item/bedsheet/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/wirecutters) || I.get_sharpness())
if(!(flags_1 & HOLOGRAM_1) && (istype(I, /obj/item/wirecutters) || I.get_sharpness()))
var/obj/item/stack/sheet/cloth/C = new (get_turf(src), 3)
transfer_fingerprints_to(C)
C.add_fingerprint(user)
@@ -369,4 +369,4 @@ LINEN BINS
/obj/structure/bedsheetbin/color
sheet_types = list(/obj/item/bedsheet, /obj/item/bedsheet/blue, /obj/item/bedsheet/green, /obj/item/bedsheet/orange, \
/obj/item/bedsheet/purple, /obj/item/bedsheet/red, /obj/item/bedsheet/yellow, /obj/item/bedsheet/brown, \
/obj/item/bedsheet/black)
/obj/item/bedsheet/black)
@@ -51,7 +51,6 @@
new /obj/item/storage/backpack/satchel/leather/withwallet( src )
new /obj/item/instrument/piano_synth(src)
new /obj/item/radio/headset( src )
new /obj/item/clothing/head/colour(src)
/obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params)
var/obj/item/card/id/I = W.GetID()
@@ -6,8 +6,16 @@
max_integrity = 250
armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
secure = TRUE
var/melee_min_damage = 20
/obj/structure/closet/secure_closet/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
if(damage_flag == "melee" && damage_amount < 20)
if(damage_flag == "melee" && damage_amount < melee_min_damage)
return 0
. = ..()
. = ..()
// Exists to work around the minimum 700 cr price for goodies / small items
/obj/structure/closet/secure_closet/goodies
icon_state = "goodies"
desc = "A sturdier card-locked storage unit used for bulky shipments."
max_integrity = 500 // Same as crates.
melee_min_damage = 25 // Idem.
@@ -76,12 +76,13 @@
new /obj/item/storage/box/flashbangs(src)
new /obj/item/shield/riot/tele(src)
new /obj/item/storage/belt/security/full(src)
new /obj/item/gun/energy/e_gun/hos(src)
new /obj/item/choice_beacon/hosgun(src)
new /obj/item/flashlight/seclite(src)
new /obj/item/pinpointer/nuke(src)
new /obj/item/circuitboard/machine/techfab/department/security(src)
new /obj/item/storage/photo_album/HoS(src)
new /obj/item/clothing/suit/hooded/wintercoat/hos(src)
/obj/structure/closet/secure_closet/warden
name = "\proper warden's locker"
req_access = list(ACCESS_ARMORY)

Some files were not shown because too many files have changed in this diff Show More