Security / PseudoCargo Expansion (#6482)

* Security Expansion work.

* Weaponized Racism, Stowaways, Meteors

* Fix Fix. Prep modular armor for addition.

* Fix the boots.

* More modular armor work. Now in cargo!

* Fixfix

* Fixfix

* Thank you anxiety very cool.

* Make a Stowaway Antag

* FixFix
This commit is contained in:
Mechoid
2019-11-24 14:22:25 -08:00
committed by Anewbe
parent 2dddf3d594
commit 7ecdcb40d2
83 changed files with 2710 additions and 68 deletions
+10
View File
@@ -80,6 +80,16 @@
return 0
return 1
/obj/item/clothing/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
. = ..()
if((. == 0) && LAZYLEN(accessories))
for(var/obj/item/I in accessories)
var/check = I.handle_shield(user, damage, damage_source, attacker, def_zone, attack_text)
if(check != 0) // Projectiles sometimes use negatives IIRC, 0 is only returned if something is not blocked.
. = check
break
/obj/item/clothing/proc/refit_for_species(var/target_species)
if(!species_restricted)
return //this item doesn't use the species_restricted system
@@ -12,6 +12,10 @@
if(H.wear_suit.body_parts_covered & ARMS)
to_chat(H, "<span class='warning'>You can't wear \the [src] with \the [H.wear_suit], it's in the way.</span>")
return 0
for(var/obj/item/clothing/accessory/A in H.wear_suit)
if(A.body_parts_covered & ARMS)
to_chat(H, "<span class='warning'>You can't wear \the [src] with \the [H.wear_suit]'s [A], it's in the way.</span>")
return 0
return 1
/obj/item/clothing/gloves/arm_guard/laserproof
@@ -14,6 +14,10 @@
if(H.wear_suit.body_parts_covered & LEGS)
H << "<span class='warning'>You can't wear \the [src] with \the [H.wear_suit], it's in the way.</span>"
return 0
for(var/obj/item/clothing/accessory/A in H.wear_suit)
if(A.body_parts_covered & LEGS)
to_chat(H, "<span class='warning'>You can't wear \the [src] with \the [H.wear_suit]'s [A], it's in the way.</span>")
return 0
return 1
/obj/item/clothing/shoes/leg_guard/laserproof
+21
View File
@@ -520,6 +520,22 @@
|ACCESSORY_SLOT_ARMOR_M)
blood_overlay_type = "armor"
/obj/item/clothing/suit/armor/pcarrier/mob_can_equip(var/mob/living/carbon/human/H, slot)
if(..()) //This will only run if no other problems occured when equiping.
if(H.gloves)
if(H.gloves.body_parts_covered & ARMS)
for(var/obj/item/clothing/accessory/A in src)
if(A.body_parts_covered & ARMS)
to_chat(H, "<span class='warning'>You can't wear \the [A] with \the [H.gloves], they're in the way.</span>")
return 0
if(H.shoes)
if(H.shoes.body_parts_covered & LEGS)
for(var/obj/item/clothing/accessory/A in src)
if(A.body_parts_covered & LEGS)
to_chat(H, "<span class='warning'>You can't wear \the [A] with \the [H.shoes], they're in the way.</span>")
return 0
return 1
/obj/item/clothing/suit/armor/pcarrier/light
starting_accessories = list(/obj/item/clothing/accessory/armor/armorplate)
@@ -549,6 +565,11 @@
desc = "A lightweight blue plate carrier vest. It can be equipped with armor plates, but provides no protection of its own."
icon_state = "pcarrier_blue"
/obj/item/clothing/suit/armor/pcarrier/press
name = "light blue plate carrier"
desc = "A lightweight light blue plate carrier vest. It can be equipped with armor plates, but provides no protection of its own."
icon_state = "pcarrier_press"
/obj/item/clothing/suit/armor/pcarrier/blue/sol
name = "peacekeeper plate carrier"
desc = "A lightweight plate carrier vest in SCG Peacekeeper colors. It can be equipped with armor plates, but provides no protection of its own."
@@ -10,6 +10,24 @@
icon_state = "pouches"
w_class = ITEMSIZE_NORMAL
/obj/item/clothing/accessory/armor/on_attached(var/obj/item/clothing/S, var/mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.wear_suit == S)
if((body_parts_covered & ARMS) && istype(H.gloves, /obj/item/clothing))
var/obj/item/clothing/G = H.gloves
if(G.body_parts_covered & ARMS)
to_chat(H, "<span class='warning'>You can't wear \the [src] with \the [G], it's in the way.</span>")
S.accessories -= src
return
else if((body_parts_covered & LEGS) && istype(H.shoes, /obj/item/clothing))
var/obj/item/clothing/Sh = H.shoes
if(Sh.body_parts_covered & LEGS)
to_chat(H, "<span class='warning'>You can't wear \the [src] with \the [Sh], it's in the way.</span>")
S.accessories -= src
return
..()
///////////
//Pouches
///////////
@@ -74,6 +92,13 @@
armor = list(melee = 30, bullet = 15, laser = 40, energy = 10, bomb = 25, bio = 0, rad = 0)
slot = ACCESSORY_SLOT_ARMOR_C
/obj/item/clothing/accessory/armor/armorplate/stab
name = "mesh armor plate"
desc = "A mesh armor plate made of steel-reinforced synthetic fibers, great for dealing with small blades. Attaches to a plate carrier."
icon_state = "armor_stab"
armor = list(melee = 25, bullet = 5, laser = 20, energy = 10, bomb = 15, bio = 0, rad = 0)
armorsoak = list(melee = 7, bullet = 5, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0)
/obj/item/clothing/accessory/armor/armorplate/medium
name = "medium armor plate"
desc = "A plasteel-reinforced synthetic armor plate, providing good protection. Attaches to a plate carrier."
@@ -92,6 +117,56 @@
icon_state = "armor_merc"
armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 40, bio = 0, rad = 0)
/obj/item/clothing/accessory/armor/armorplate/bulletproof
name = "ballistic armor plate"
desc = "A woven armor plate with additional plating, providing good protection against high-velocity trauma. Attaches to a plate carrier."
icon_state = "armor_ballistic"
slowdown = 0.6
armor = list(melee = 10, bullet = 70, laser = 10, energy = 10, bomb = 0, bio = 0, rad = 0)
armorsoak = list(melee = 0, bullet = 10, laser = 0, energy = 5, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 0.7
/obj/item/clothing/accessory/armor/armorplate/riot
name = "riot armor plate"
desc = "A thick armor plate with additional padding, providing good protection against low-velocity trauma. Attaches to a plate carrier."
icon_state = "armor_riot"
slowdown = 0.6
armor = list(melee = 70, bullet = 10, laser = 10, energy = 10, bomb = 0, bio = 0, rad = 0)
armorsoak = list(melee = 10, bullet = 0, laser = 0, energy = 5, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 0.7
/obj/item/clothing/accessory/armor/armorplate/laserproof
name = "ablative armor plate"
desc = "A durasteel-scaled synthetic armor plate, providing good protection against lasers. Attaches to a plate carrier."
icon_state = "armor_medium"
slowdown = 0.6
armor = list(melee = 10, bullet = 10, laser = 70, energy = 50, bomb = 0, bio = 0, rad = 0)
armorsoak = list(melee = 0, bullet = 0, laser = 10, energy = 15, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 0.1
/obj/item/clothing/accessory/armor/armorplate/ablative/handle_shield(mob/user, var/damage, atom/damage_source = null, mob/attacker = null, var/def_zone = null, var/attack_text = "the attack")
if(istype(damage_source, /obj/item/projectile/energy) || istype(damage_source, /obj/item/projectile/beam))
var/obj/item/projectile/P = damage_source
if(P.reflected)
return ..()
var/reflectchance = 40 - round(damage/3)
if(!(def_zone in list(BP_TORSO, BP_GROIN)))
reflectchance /= 2
if(P.starting && prob(reflectchance))
visible_message("<span class='danger'>\The [user]'s [src.name] reflects [attack_text]!</span>")
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/turf/curloc = get_turf(user)
P.redirect(new_x, new_y, curloc, user)
P.reflected = 1
return PROJECTILE_CONTINUE
//////////////
//Arm guards
//////////////
@@ -12,7 +12,7 @@
var/closed = 0
var/scanning = 0
var/scanner_progress = 0
var/scanner_rate = 2.50
var/scanner_rate = 5
var/last_process_worldtime = 0
var/report_num = 0
@@ -32,7 +32,7 @@
user << "<span class='notice'>The microscope whirrs as you examine \the [sample].</span>"
if(!do_after(user, 25) || !sample)
if(!do_after(user, 2 SECONDS) || !sample)
user << "<span class='notice'>You stop examining \the [sample].</span>"
return
@@ -71,8 +71,8 @@
report.info += "Surface analysis has determined unique fingerprint strings:<br><br>"
for(var/prints in card.evidence)
report.info += "<span class='notice'>Fingerprint string: </span>"
if(!is_complete_print(prints))
report.info += "INCOMPLETE PRINT"
if(!is_complete_print(card.evidence[prints]))
report.info += "INCOMPLETE PRINT:[card.evidence[prints]]"
else
report.info += "[prints]"
report.info += "<br>"
+201
View File
@@ -0,0 +1,201 @@
/obj/item/device/detective_scanner
name = "forensic scanner"
desc = "Used to scan objects for DNA and fingerprints."
icon_state = "forensic"
var/list/stored = list()
w_class = ITEMSIZE_SMALL
item_state = "electronic"
flags = NOBLUDGEON
slot_flags = SLOT_BELT
var/reveal_fingerprints = TRUE
var/reveal_incompletes = FALSE
var/reveal_blood = TRUE
var/reveal_fibers = FALSE
/obj/item/device/detective_scanner/attack(mob/living/carbon/human/M as mob, mob/user as mob)
if (!ishuman(M))
to_chat(user, "<span class='warning'>\The [M] does not seem to be compatible with this device.</span>")
flick("[icon_state]0",src)
return 0
if(reveal_fingerprints)
if((!( istype(M.dna, /datum/dna) ) || M.gloves))
to_chat(user, "<span class='notice'>No fingerprints found on [M]</span>")
flick("[icon_state]0",src)
return 0
else if(user.zone_sel.selecting == "r_hand" || user.zone_sel.selecting == "l_hand")
var/obj/item/weapon/sample/print/P = new /obj/item/weapon/sample/print(user.loc)
P.attack(M, user)
to_chat(user,"<span class='notice'>Done printing.</span>")
// user << "<span class='notice'>[M]'s Fingerprints: [md5(M.dna.uni_identity)]</span>"
if(reveal_blood && M.blood_DNA && M.blood_DNA.len)
to_chat(user,"<span class='notice'>Blood found on [M]. Analysing...</span>")
spawn(15)
for(var/blood in M.blood_DNA)
to_chat(user,"<span class='notice'>Blood type: [M.blood_DNA[blood]]\nDNA: [blood]</span>")
return
/obj/item/device/detective_scanner/afterattack(atom/A as obj|turf, mob/user, proximity)
if(!proximity) return
if(ismob(A))
return
/*
if(istype(A,/obj/machinery/computer/forensic_scanning))
user.visible_message("[user] takes a cord out of [src] and hooks its end into [A]" ,\
"<span class='notice'>You download data from [src] to [A]</span>")
var/obj/machinery/computer/forensic_scanning/F = A
F.sync_data(stored)
return
*/
if(istype(A,/obj/item/weapon/sample/print))
to_chat(user,"The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\"")
flick("[icon_state]0",src)
return
add_fingerprint(user)
if(!(do_after(user, 1 SECOND)))
to_chat(user,"<span class='warning'>You must remain still for the device to complete its work.</span>")
return 0
//General
if ((!A.fingerprints || !A.fingerprints.len) && !A.suit_fibers && !A.blood_DNA)
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
"<span class='warning'>Unable to locate any fingerprints, materials, fibers, or blood on [A]!</span>",\
"You hear a faint hum of electrical equipment.")
flick("[icon_state]0",src)
return 0
if(add_data(A))
to_chat(user,"<span class='notice'>Object already in internal memory. Consolidating data...</span>")
flick("[icon_state]2",src)
return
//PRINTS
if(A.fingerprints && A.fingerprints.len)
to_chat(user,"<span class='notice'>Isolated [A.fingerprints.len] fingerprints:</span>")
if(!reveal_incompletes)
to_chat(user,"<span class='warning'>Rapid Analysis Imperfect: Scan samples with H.R.F.S. equipment to determine nature of incomplete prints.</span>")
var/list/complete_prints = list()
var/list/incomplete_prints = list()
for(var/i in A.fingerprints)
var/print = A.fingerprints[i]
if(stringpercent(print) <= FINGERPRINT_COMPLETE)
complete_prints += print
else
incomplete_prints += print
if(complete_prints.len < 1)
to_chat(user,"<span class='notice'>No intact prints found</span>")
else
to_chat(user,"<span class='notice'>Found [complete_prints.len] intact prints</span>")
if(reveal_fingerprints)
for(var/i in complete_prints)
to_chat(user,"<span class='notice'>&nbsp;&nbsp;&nbsp;&nbsp;[i]</span>")
to_chat(user,"<span class='notice'>Found [incomplete_prints.len] incomplete prints</span>")
if(reveal_incompletes)
for(var/i in incomplete_prints)
to_chat(user,"<span class='notice'>&nbsp;&nbsp;&nbsp;&nbsp;[i]</span>")
//FIBERS
if(A.suit_fibers && A.suit_fibers.len)
to_chat(user,"<span class='notice'>Fibers/Materials detected.[reveal_fibers ? " Analysing..." : " Acquisition of fibers for H.R.F.S. analysis advised."]</span>")
flick("[icon_state]2",src)
if(reveal_fibers && do_after(user, 5 SECONDS))
to_chat(user,"<span class='notice'>Apparel samples scanned:</span>")
for(var/sample in A.suit_fibers)
to_chat(user," - <span class='notice'>[sample]</span>")
//Blood
if (A.blood_DNA && A.blood_DNA.len)
to_chat(user,"<span class='notice'>Blood detected.[reveal_blood ? " Analysing..." : " Acquisition of swab for H.R.F.S. analysis advised."]</span>")
if(reveal_blood && do_after(user, 5 SECONDS))
flick("[icon_state]2",src)
for(var/blood in A.blood_DNA)
to_chat(user,"Blood type: <span class='warning'>[A.blood_DNA[blood]]</span> DNA: <span class='warning'>[blood]</span>")
user.visible_message("\The [user] scans \the [A] with \a [src], the air around [user.gender == MALE ? "him" : "her"] humming[prob(70) ? " gently." : "."]" ,\
"<span class='notice'>You finish scanning \the [A].</span>",\
"You hear a faint hum of electrical equipment.")
flick("[icon_state]2",src)
return 0
/obj/item/device/detective_scanner/proc/add_data(atom/A as mob|obj|turf|area)
var/datum/data/record/forensic/old = stored["\ref [A]"]
var/datum/data/record/forensic/fresh = new(A)
if(old)
fresh.merge(old)
. = 1
stored["\ref [A]"] = fresh
/obj/item/device/detective_scanner/verb/examine_data()
set name = "Examine Forensic Data"
set category = "Object"
set src in view(1)
world << "usr is [usr]"
display_data(usr)
/obj/item/device/detective_scanner/proc/display_data(var/mob/user)
if(user && stored && stored.len)
for(var/objref in stored)
if(!do_after(user, 1 SECOND)) // So people can move and stop the spam, if they refuse to wipe data.
break
var/datum/data/record/forensic/F = stored[objref]
var/list/fprints = F.fields["fprints"]
var/list/fibers = F.fields["fibers"]
var/list/bloods = F.fields["blood"]
to_chat(user, "<span class='notice'>Data for: [F.fields["name"]]</span>")
if(reveal_fingerprints)
var/list/complete_prints = list()
var/list/incomplete_prints = list()
for(var/i in fprints)
var/print = fprints[i]
if(stringpercent(print) <= FINGERPRINT_COMPLETE)
complete_prints += print
to_chat(user, " - <span class='notice'>[print]</span>")
else
incomplete_prints += print
if(complete_prints.len < 1)
to_chat(user,"<span class='notice'>No intact prints found.</span>")
if(reveal_incompletes)
for(var/print in incomplete_prints)
to_chat(user, " - <span class='notice'>[print]</span>")
if(fibers && fibers.len)
to_chat(user, "<span class='notice'>[fibers.len] samples of material were present.</span>")
if(reveal_fibers)
for(var/sample in fibers)
to_chat(user," - <span class='notice'>[sample]</span>")
if(bloods && bloods.len)
to_chat(user, "<span class='notice'>[bloods.len] samples of blood were present.</span>")
if(reveal_blood)
for(var/bloodsample in bloods)
to_chat(user, " - <span class='warning'>[bloodsample]</span> Type: [bloods[bloodsample]]")
/obj/item/device/detective_scanner/verb/wipe()
set name = "Wipe Forensic Data"
set category = "Object"
set src in view(1)
if (alert("Are you sure you want to wipe all data from [src]?",,"Yes","No") == "Yes")
stored = list()
to_chat(usr,"<span class='notice'>Forensic data erase complete.</span>")
/obj/item/device/detective_scanner/advanced
name = "advanced forensic scanner"
icon_state = "forensic_neo"
reveal_fibers = TRUE
reveal_incompletes = TRUE
@@ -0,0 +1,10 @@
/datum/gm_action/security_drill
name = "security drills"
departments = list(ROLE_SECURITY, ROLE_EVERYONE)
/datum/gm_action/security_drill/announce()
spawn(rand(1 MINUTE, 2 MINUTES))
command_announcement.Announce("[pick("A NanoTrasen security director", "A Vir-Gov correspondant", "Local Sif authoritiy")] has advised the enactment of [pick("a rampant wildlife", "a fire", "a hostile boarding", "a nonstandard", "a bomb", "an emergent intelligence")] drill with the personnel onboard \the [station_name()].", "Security Advisement")
/datum/gm_action/security_drill/get_weight()
return max(-20, 10 + gm.staleness - (gm.danger * 2)) + (metric.count_people_in_department(ROLE_SECURITY) * 5) + (metric.count_people_in_department(ROLE_EVERYONE) * 1.5)
+1 -1
View File
@@ -14,4 +14,4 @@
/datum/gm_action/dust/start()
..()
dust_swarm("norm")
dust_swarm("norm")
@@ -0,0 +1,116 @@
#define LOC_KITCHEN 0
#define LOC_ATMOS 1
#define LOC_CHAPEL 2
#define LOC_LIBRARY 3
#define LOC_HYDRO 4
#define LOC_VAULT 5
#define LOC_CONSTR 6
#define LOC_TECH 7
#define LOC_GARDEN 8
#define VERM_MICE 0
#define VERM_LIZARDS 1
#define VERM_SPIDERS 2
/datum/gm_action/infestation
name = "animal infestation"
departments = list(ROLE_EVERYONE)
var/location
var/locstring
var/vermin
var/vermstring
var/list/turf/simulated/floor/turfs = list()
var/spawn_types
var/max_number
/datum/gm_action/infestation/set_up()
location = rand(0,8)
turfs.Cut()
var/spawn_area_type
switch(location)
if(LOC_KITCHEN)
spawn_area_type = /area/crew_quarters/kitchen
locstring = "the kitchen"
if(LOC_ATMOS)
spawn_area_type = /area/engineering/atmos
locstring = "atmospherics"
if(LOC_CHAPEL)
spawn_area_type = /area/chapel/main
locstring = "the chapel"
if(LOC_LIBRARY)
spawn_area_type = /area/library
locstring = "the library"
if(LOC_HYDRO)
spawn_area_type = /area/hydroponics
locstring = "hydroponics"
if(LOC_VAULT)
spawn_area_type = /area/security/nuke_storage
locstring = "the vault"
if(LOC_CONSTR)
spawn_area_type = /area/construction
locstring = "the construction area"
if(LOC_TECH)
spawn_area_type = /area/storage/tech
locstring = "technical storage"
if(LOC_GARDEN)
spawn_area_type = /area/hydroponics/garden
locstring = "the public garden"
for(var/areapath in typesof(spawn_area_type))
var/area/A = locate(areapath)
for(var/turf/simulated/floor/F in A.contents)
if(turf_clear(F))
turfs += F
spawn_types = list()
max_number = 0
vermin = rand(0,2)
switch(vermin)
if(VERM_MICE)
spawn_types = list(/mob/living/simple_mob/animal/passive/mouse/gray, /mob/living/simple_mob/animal/passive/mouse/brown, /mob/living/simple_mob/animal/passive/mouse/white, /mob/living/simple_mob/animal/passive/mouse/rat)
max_number = 12
vermstring = "mice"
if(VERM_LIZARDS)
spawn_types = list(/mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/lizard, /mob/living/simple_mob/animal/passive/lizard/large, /mob/living/simple_mob/animal/passive/lizard/large/defensive)
max_number = 6
vermstring = "lizards"
if(VERM_SPIDERS)
spawn_types = list(/obj/effect/spider/spiderling)
max_number = 3
vermstring = "spiders"
/datum/gm_action/infestation/start()
spawn()
var/num = rand(2,max_number)
while(turfs.len > 0 && num > 0)
var/turf/simulated/floor/T = pick(turfs)
turfs.Remove(T)
num--
if(vermin == VERM_SPIDERS)
var/obj/effect/spider/spiderling/S = new(T)
S.amount_grown = -1
else
var/spawn_type = pick(spawn_types)
new spawn_type(T)
/datum/gm_action/infestation/announce()
command_announcement.Announce("Bioscans indicate that [vermstring] have been breeding in [locstring]. Clear them out, before this starts to affect productivity.", "Vermin infestation")
/datum/gm_action/infestation/get_weight()
return 5 + (metric.count_people_in_department(ROLE_EVERYONE) * 20)
#undef LOC_KITCHEN
#undef LOC_ATMOS
#undef LOC_CHAPEL
#undef LOC_LIBRARY
#undef LOC_HYDRO
#undef LOC_VAULT
#undef LOC_TECH
#undef LOC_GARDEN
#undef VERM_MICE
#undef VERM_LIZARDS
#undef VERM_SPIDERS
@@ -1,4 +1,6 @@
/datum/gm_action/ionstorm
name = "ion storm"
departments = list(ROLE_SYNTHETIC)
var/botEmagChance = 0.5
var/list/players = list()
var/active = FALSE
@@ -41,3 +43,8 @@
spawn(rand(5000,8000))
if(prob(50))
ion_storm_announcement()
/datum/gm_action/ionstorm/get_weight()
var/bots = metric.count_people_in_department(ROLE_SYNTHETIC)
var/weight = 5 + (bots * 20)
return weight
@@ -0,0 +1,52 @@
/datum/gm_action/manifest_malfunction
name = "manifest malfunction"
enabled = TRUE
departments = list(ROLE_SECURITY, ROLE_SYNTHETIC, ROLE_EVERYONE)
chaotic = 3
reusable = FALSE
length = 0
var/recordtype
/datum/gm_action/manifest_malfunction/set_up()
severity = pickweight(EVENT_LEVEL_MUNDANE = 6,
EVENT_LEVEL_MODERATE = 2,
EVENT_LEVEL_MAJOR = 1
)
recordtype = pickweight("medical" = 10,"security" = (severity * 15))
return
/datum/gm_action/manifest_malfunction/get_weight()
. = -10
var/security = metric.count_people_in_department(ROLE_SECURITY)
if(security && data_core)
. += (metric.count_people_in_department(ROLE_EVERYONE) * 5) - (metric.count_people_in_department(ROLE_SYNTHETIC) * 5)
return .
/datum/gm_action/manifest_malfunction/start()
..()
var/manifest_cut_count = 1 * severity
for(var/I = 1 to manifest_cut_count)
var/datum/data/record/R
switch(recordtype)
if("security")
R = pick(data_core.security)
if("medical")
R = pick(data_core.medical)
qdel(R)
/datum/gm_action/manifest_malfunction/announce()
if(prob(30 * severity))
spawn(rand(5 MINUTES, 10 MINUTES))
command_announcement.Announce("An ongoing mass upload of malware for [recordtype] record cores has been detected onboard [station_name()]", "Data Breach Alert")
return
@@ -2,18 +2,38 @@
/datum/gm_action/meteor_defense
name = "meteor defense"
departments = list(ROLE_ENGINEERING)
departments = list(ROLE_ENGINEERING, ROLE_CARGO)
chaotic = 50
var/direction = null
var/dir_text = null
var/waves = 0
var/meteor_types
/datum/gm_action/meteor_defense/get_weight()
var/engineers = metric.count_people_in_department(ROLE_ENGINEERING)
var/weight = (max(engineers - 1, 0) * 25) // If only one engineer exists, no meteors for now.
var/cargo = metric.count_people_in_department(ROLE_CARGO)
var/bots = metric.count_people_in_department(ROLE_SYNTHETIC)
var/weight = (max(engineers - 1, 0) * 20) // If only one engineer exists, no meteors for now.
if(engineers >= 2)
weight += ((cargo - 1) * 10)
weight += (bots * 15)
return weight
/datum/gm_action/meteor_defense/set_up()
severity = pickweight(EVENT_LEVEL_MUNDANE = 10,
EVENT_LEVEL_MODERATE = 3
)
switch(severity)
if(EVENT_LEVEL_MUNDANE)
meteor_types = meteors_threatening.Copy()
if(EVENT_LEVEL_MODERATE)
meteor_types = meteors_catastrophic.Copy()
direction = pick(cardinal) // alldirs doesn't work with current meteor code unfortunately.
waves = rand(5, 8)
switch(direction)
@@ -27,17 +47,17 @@
dir_text = "starboard"
/datum/gm_action/meteor_defense/announce()
var/announcement = "Alert! Two other asteroids have collided near [station_name()]. Chunks of it are expected to approach from the [dir_text] side. ETA to arrival is \
approximately 10 minutes."
var/announcement = "Alert! Two asteroids have collided near [station_name()]. Chunks of it are expected to approach from the [dir_text] side. ETA to arrival is \
approximately [round(5 * severity * 2)] minutes."
command_announcement.Announce(announcement, "Meteor Alert", new_sound = 'sound/AI/meteors.ogg')
/datum/gm_action/meteor_defense/start()
..()
spawn(0)
sleep(5 MINUTES)
var/announcement = "The incoming debris are expected to approach from the [dir_text] side. ETA to arrival is approximately 5 minutes."
sleep(round(5 * severity) MINUTES)
var/announcement = "The incoming debris are expected to approach from the [dir_text] side. ETA to arrival is approximately [round(5 * severity)] minutes."
command_announcement.Announce(announcement, "Meteor Alert - Update")
sleep(5 MINUTES)
sleep(round(5 * severity) MINUTES)
announcement = "Incoming debris approaches from the [dir_text] side!"
command_announcement.Announce(announcement, "Meteor Alert - Update")
while(waves)
@@ -46,6 +66,6 @@
spawn_meteors(rand(8, 12), meteors_threatening, reverse_dir[direction])
waves--
sleep(30 SECONDS)
announcement = "The colony has cleared the incoming debris."
announcement = "The station has cleared the incoming debris."
command_announcement.Announce(announcement, "Meteor Alert - Update")
message_admins("Meteor defense event has ended.")
message_admins("Meteor defense event has ended.")
@@ -0,0 +1,49 @@
/datum/gm_action/security_screening
name = "security screening"
departments = list(ROLE_SECURITY, ROLE_EVERYONE)
var/list/species_weights = list(
SPECIES_SKRELL = 9,
SPECIES_UNATHI = 15,
SPECIES_HUMAN_VATBORN = 6,
SPECIES_TESHARI = 2,
SPECIES_TAJ = 3,
SPECIES_DIONA = 1,
SPECIES_ZADDAT = 25,
SPECIES_HUMAN = 3,
SPECIES_PROMETHEAN = 30
)
var/list/synth_weights = list(
"Cybernetic" = 15,
"Drone" = 30,
"Positronic" = 25
)
var/list/end_weights = list()
/datum/gm_action/security_screening/set_up()
for(var/species_name in species_weights)
var/giveweight = 0
for(var/datum/data/record/R in data_core.general)
if(R.fields["species"] == species_name)
giveweight += species_weights[species_name]
end_weights[species_name] = giveweight
for(var/bottype in synth_weights)
var/giveweight = 0
for(var/datum/data/record/R in data_core.general)
if(R.fields["brain_type"] == bottype)
giveweight += synth_weights[bottype]
end_weights[bottype] = giveweight
/datum/gm_action/security_screening/announce()
spawn(rand(1 MINUTE, 2 MINUTES))
command_announcement.Announce("[pick("A nearby Navy vessel", "A Solar official", "A Vir-Gov official", "A NanoTrasen board director")] has requested the screening of [pick("every other", "every", "suspicious", "willing")] [pickweight(end_weights)] personnel onboard \the [station_name()].", "Security Advisement")
/datum/gm_action/security_screening/get_weight()
return max(-20, 10 + round(gm.staleness * 1.5) - (gm.danger * 2)) + (metric.count_people_in_department(ROLE_SECURITY) * 10) + (metric.count_people_in_department(ROLE_EVERYONE) * 1.5)
@@ -7,21 +7,28 @@
var/spawncount = 1
/datum/gm_action/spider_infestation/set_up()
spawn(rand(600, 6000))
announce()
var/spawntype = /obj/effect/spider/spiderling
if(prob(40))
severity = rand(2,3)
else
severity = 1
/datum/gm_action/spider_infestation/set_up()
severity = pickweight(EVENT_LEVEL_MUNDANE = max(1,(12 - (3 * metric.count_people_in_department(ROLE_SECURITY)))),
EVENT_LEVEL_MODERATE = (7 + (2 * metric.count_people_in_department(ROLE_SECURITY))),
EVENT_LEVEL_MAJOR = (1 + (2 * metric.count_people_in_department(ROLE_SECURITY)))
)
switch(severity)
if(EVENT_LEVEL_MUNDANE)
spawntype = /obj/effect/spider/spiderling/stunted
if(EVENT_LEVEL_MODERATE)
spawntype = /obj/effect/spider/spiderling
if(EVENT_LEVEL_MAJOR)
spawntype = /obj/effect/spider/spiderling
spawncount = rand(4 * severity, 6 * severity)
/datum/gm_action/spider_infestation/announce()
command_announcement.Announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", new_sound = 'sound/AI/aliens.ogg')
if(severity >= 3)
if(severity >= EVENT_LEVEL_MAJOR)
spawn(rand(600, 3000))
command_announcement.Announce("Unidentified lifesigns previously detected coming aboard [station_name()] have been classified as a swarm of arachnids. Extreme caution is advised.", "Arachnid Alert")
@@ -0,0 +1,14 @@
/datum/gm_action/station_fund_raise
name = "local funding drive"
departments = list(ROLE_SECURITY, ROLE_CARGO, ROLE_EVERYONE)
/datum/gm_action/station_fund_raise/announce()
spawn(rand(1 MINUTE, 2 MINUTES))
command_announcement.Announce("Due to [pick("recent", "unfortunate", "possible future")] budget [pick("changes", "issues")], in-system stations are now advised to increase funding income.", "Security & Supply Advisement")
/datum/gm_action/station_fund_raise/get_weight()
var/weight_modifier = 0.5
if(station_account.money <= 80000)
weight_modifier = 1
return (max(-20, 10 + gm.staleness) + ((metric.count_people_in_department(ROLE_SECURITY) + (metric.count_people_in_department(ROLE_CARGO))) * 5) + (metric.count_people_in_department(ROLE_EVERYONE) * 3)) * weight_modifier
@@ -0,0 +1,80 @@
/datum/gm_action/stowaway
name = "stowaway pod"
departments = list(ROLE_EVERYONE, ROLE_SECURITY)
chaotic = 10
observers_used = TRUE
var/area/target_area // Chosen target area
var/area/target_turf // Chosen target turf in target_area
var/list/area/excluded = list(
/area/submap,
/area/shuttle,
/area/crew_quarters,
/area/holodeck,
/area/engineering/engine_room
)
var/list/area/included = list(
/area/maintenance
)
/datum/gm_action/stowaway/set_up()
severity = pickweight(EVENT_LEVEL_MUNDANE = 20,
EVENT_LEVEL_MODERATE = 5,
EVENT_LEVEL_MAJOR = 1
)
var/list/area/grand_list_of_areas = get_station_areas(excluded)
for(var/area/Incl in included)
for(var/area/A in grand_list_of_areas)
if(!istype(A, Incl))
grand_list_of_areas -= A
// Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
for(var/i in 1 to 10)
var/area/A = pick(grand_list_of_areas)
if(is_area_occupied(A))
log_debug("[name] event: Rejected [A] because it is occupied.")
continue
// A good area, great! Lets try and pick a turf
var/list/turfs = list()
for(var/turf/simulated/floor/F in A)
if(turf_clear(F))
turfs += F
if(turfs.len == 0)
log_debug("[name] event: Rejected [A] because it has no clear turfs.")
continue
target_area = A
target_turf = pick(turfs)
if(!target_area)
log_debug("[name] event: Giving up after too many failures to pick target area")
return
/datum/gm_action/stowaway/start()
if(!target_turf)
return
..()
var/obj/structure/ghost_pod/ghost_activated/human/HP = new (target_turf)
if(severity == EVENT_LEVEL_MUNDANE || istype(ticker.mode, /datum/game_mode/extended))
HP.make_antag = MODE_STOWAWAY
else if(severity == EVENT_LEVEL_MODERATE)
HP.make_antag = MODE_RENEGADE
HP.occupant_type = "renegade [HP.occupant_type]"
else if(severity == EVENT_LEVEL_MAJOR)
HP.make_antag = MODE_INFILTRATOR
HP.occupant_type = "volatile [HP.occupant_type]"
say_dead_object("A <span class='notice'>[HP.occupant_type]</span> pod is now available in \the [target_area].", HP)
/datum/gm_action/stowaway/get_weight()
return -20 + (metric.count_people_in_department(ROLE_SECURITY) * 15 + metric.count_people_in_department(ROLE_SYNTHETIC) * 5 + metric.count_people_in_department(ROLE_EVERYONE) * 1)
/datum/gm_action/stowaway/announce()
spawn(rand(15 MINUTES, 30 MINUTES))
if(prob(20) && severity >= EVENT_LEVEL_MODERATE && atc && !atc.squelched)
atc.msg("Attention civilian vessels in [using_map.starsys_name] shipping lanes, caution is advised as [pick("an unidentified vessel", "a known criminal's vessel", "a derelict vessel")] has been detected passing multiple local stations.")
@@ -0,0 +1,62 @@
/datum/gm_action/nanotrasen_budget_allocation
name = "supply point to cargo budget"
enabled = TRUE
departments = list(ROLE_CARGO)
chaotic = 0
reusable = TRUE
var/datum/controller/supply/SC
var/running = FALSE
var/last_run
var/thaler_earned
/datum/gm_action/nanotrasen_budget_allocation/set_up()
SC = supply_controller
running = TRUE
return
/datum/gm_action/nanotrasen_budget_allocation/get_weight()
. = round(SC.points / 15)
var/cargo = metric.count_people_in_department(ROLE_CARGO)
var/personnel = metric.count_people_in_department(ROLE_EVERYONE)
if(cargo)
. = round(SC.points / (10 + personnel)) + cargo * 10
if(running || ( world.time < (last_run + 30 MINUTES)))
. = 0
return .
/datum/gm_action/nanotrasen_budget_allocation/start()
. = ..()
last_run = world.time
var/point_difference = SC.points
if(SC.points >= 1000)
SC.points = round(SC.points / 3)
point_difference -= SC.points
else if(SC.points >= 500)
SC.points -= 100 * (rand(5, 20) / 10)
point_difference -= SC.points
else
SC.points = round(SC.points / 1.25)
point_difference -= SC.points
if(point_difference > 0)
thaler_earned = round(point_difference / SC.points_per_money)
/datum/gm_action/nanotrasen_budget_allocation/end()
spawn(5 MINUTES)
running = FALSE
return
/datum/gm_action/nanotrasen_budget_allocation/announce()
spawn(rand(1 MINUTE, 5 MINUTES))
command_announcement.Announce("[station_name()] Supply Department has earned a converted thaler budget of [thaler_earned] due to their backlogged daily requisition tokens.", "Supply Budget Conversion")
return
@@ -0,0 +1,11 @@
/datum/gm_action/request
name = "general request"
departments = list(ROLE_CARGO)
/datum/gm_action/request/announce()
spawn(rand(1 MINUTE, 2 MINUTES))
command_announcement.Announce("[pick("A nearby vessel", "A Solar contractor", "A Skrellian contractor", "A NanoTrasen board director")] has requested the delivery of [pick("one","two","three","several")] [pick("medical","engineering","research","civilian")] supply packages. The [station_name()] has been tasked with completing this request.", "Supply Request")
/datum/gm_action/request/get_weight()
return max(15, 15 + round(gm.staleness / 2) - gm.danger) + (metric.count_people_in_department(ROLE_CARGO) * 10)
@@ -0,0 +1,75 @@
/datum/gm_action/swarm_boarder
name = "swarmer shell"
departments = list(ROLE_EVERYONE, ROLE_SECURITY, ROLE_ENGINEERING)
chaotic = 30
observers_used = TRUE
var/area/target_area // Chosen target area
var/area/target_turf // Chosen target turf in target_area
var/list/area/excluded = list(
/area/submap,
/area/shuttle,
/area/crew_quarters,
/area/holodeck,
/area/engineering/engine_room
)
var/list/area/included = list(
/area/maintenance
)
/datum/gm_action/swarm_boarder/set_up()
severity = pickweight(EVENT_LEVEL_MUNDANE = 30,
EVENT_LEVEL_MODERATE = 10,
EVENT_LEVEL_MAJOR = 1
)
var/list/area/grand_list_of_areas = get_station_areas(excluded)
for(var/area/Incl in included)
for(var/area/A in grand_list_of_areas)
if(!istype(A, Incl))
grand_list_of_areas -= A
// Okay, now lets try and pick a target! Lets try 10 times, otherwise give up
for(var/i in 1 to 10)
var/area/A = pick(grand_list_of_areas)
if(is_area_occupied(A))
log_debug("[name] event: Rejected [A] because it is occupied.")
continue
// A good area, great! Lets try and pick a turf
var/list/turfs = list()
for(var/turf/simulated/floor/F in A)
if(turf_clear(F))
turfs += F
if(turfs.len == 0)
log_debug("[name] event: Rejected [A] because it has no clear turfs.")
continue
target_area = A
target_turf = pick(turfs)
if(!target_area)
log_debug("[name] event: Giving up after too many failures to pick target area")
return
/datum/gm_action/swarm_boarder/start()
if(!target_turf)
return
..()
var/swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event
if(severity == EVENT_LEVEL_MODERATE)
swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee
if(severity == EVENT_LEVEL_MAJOR)
swarmertype = /obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner
new swarmertype(target_turf)
/datum/gm_action/swarm_boarder/get_weight()
return -60 + (metric.count_people_in_department(ROLE_SECURITY) * 20 + metric.count_people_in_department(ROLE_SYNTHETIC) * 5 + metric.count_people_in_department(ROLE_EVERYONE) * 1)
/datum/gm_action/swarm_boarder/announce()
spawn(rand(5 MINUTES, 15 MINUTES))
if(prob(80) && severity >= EVENT_LEVEL_MODERATE && atc && !atc.squelched)
atc.msg("Attention civilian vessels in [using_map.starsys_name] shipping lanes, caution is advised as [pick("an unidentified vessel", "a known criminal's vessel", "a derelict vessel")] has been detected passing multiple local stations.")
+10 -1
View File
@@ -15,13 +15,22 @@
var/next_action = 0 // Minimum amount of time of nothingness until the GM can pick something again.
var/last_department_used = null // If an event was done for a specific department, it is written here, so it doesn't do it again.
/datum/game_master/New()
..()
available_actions = init_subtypes(/datum/gm_action)
for(var/datum/gm_action/action in available_actions)
action.gm = src
var/config_setup_delay = TRUE
spawn(0)
while(config_setup_delay)
if(config)
config_setup_delay = FALSE
if(config.enable_game_master)
suspended = FALSE
else
sleep(30 SECONDS)
/datum/game_master/process()
if(ticker && ticker.current_state == GAME_STATE_PLAYING && !suspended)
adjust_staleness(1)
+12
View File
@@ -116,6 +116,18 @@
return 0
/datum/language/swarmbot
name = LANGUAGE_SWARMBOT
desc = "A confusing mechanical language spoken by some form of ancient machine."
speech_verb = "clatters"
ask_verb = "chatters"
exclaim_verb = "shrieks"
colour = "changeling"
key = "_"
flags = NO_STUTTER | RESTRICTED
syllables = list("^", "v", "-", ".", "~")
space_chance = 60
//for your antag purposes.
/datum/language/minbus
name = LANGUAGE_MINBUS
+36 -3
View File
@@ -32,6 +32,7 @@
var/will_patrol = 0 // If set to 1, will patrol, duh
var/patrol_speed = 1 // How many times per tick we move when patrolling
var/target_speed = 2 // Ditto for chasing the target
var/panic_on_alert = FALSE // Will the bot go faster when the alert level is raised?
var/min_target_dist = 1 // How close we try to get to the target
var/max_target_dist = 50 // How far we are willing to go
var/max_patrol_dist = 250
@@ -170,14 +171,20 @@
if(!A || !A.loc || prob(1))
ignore_list -= A
handleRegular()
var/panic_speed_mod = 0
if(panic_on_alert)
panic_speed_mod = handlePanic()
if(target && confirmTarget(target))
if(Adjacent(target))
handleAdjacentTarget()
else
handleRangedTarget()
if(!wait_if_pulled || !pulledby)
for(var/i = 1 to target_speed)
sleep(20 / (target_speed + 1))
for(var/i = 1 to (target_speed + panic_speed_mod))
sleep(20 / (target_speed + panic_speed_mod + 1))
stepToTarget()
if(max_frustration && frustration > max_frustration * target_speed)
handleFrustrated(1)
@@ -186,7 +193,7 @@
lookForTargets()
if(will_patrol && !pulledby && !target)
if(patrol_path && patrol_path.len)
for(var/i = 1 to patrol_speed)
for(var/i = 1 to (patrol_speed + panic_speed_mod))
sleep(20 / (patrol_speed + 1))
handlePatrol()
if(max_frustration && frustration > max_frustration * patrol_speed)
@@ -205,6 +212,32 @@
/mob/living/bot/proc/handleRangedTarget()
return
/mob/living/bot/proc/handlePanic() // Speed modification based on alert level.
. = 0
switch(get_security_level())
if("green")
. = 0
if("yellow")
. = 0
if("violet")
. = 0
if("orange")
. = 0
if("blue")
. = 1
if("red")
. = 2
if("delta")
. = 2
return .
/mob/living/bot/proc/stepToTarget()
if(!target || !target.loc)
return
+26
View File
@@ -38,6 +38,32 @@
spawn(600)
ignore_list -= g
/mob/living/bot/cleanbot/handlePanic() // Speed modification based on alert level.
. = 0
switch(get_security_level())
if("green")
. = 0
if("yellow")
. = 1
if("violet")
. = 1
if("orange")
. = 1
if("blue")
. = 2
if("red")
. = 2
if("delta")
. = 2
return .
/mob/living/bot/cleanbot/lookForTargets()
for(var/obj/effect/decal/cleanable/D in view(world.view, src)) // There was some odd code to make it start with nearest decals, it's unnecessary, this works
if(confirmTarget(D))
+26
View File
@@ -300,6 +300,32 @@
else if(amount > maxAmount)
amount = maxAmount
/mob/living/bot/floorbot/handlePanic() // Speed modification based on alert level.
. = 0
switch(get_security_level())
if("green")
. = 0
if("yellow")
. = 0
if("violet")
. = 0
if("orange")
. = 1
if("blue")
. = 1
if("red")
. = 2
if("delta")
. = 2
return .
/* Assembly */
/obj/item/weapon/storage/toolbox/mechanical/attackby(var/obj/item/stack/tile/floor/T, mob/living/user as mob)
+26
View File
@@ -49,6 +49,32 @@
/mob/living/bot/medbot/handleAdjacentTarget()
UnarmedAttack(target)
/mob/living/bot/medbot/handlePanic() // Speed modification based on alert level.
. = 0
switch(get_security_level())
if("green")
. = 0
if("yellow")
. = 0
if("violet")
. = 1
if("orange")
. = 0
if("blue")
. = 1
if("red")
. = 2
if("delta")
. = 2
return .
/mob/living/bot/medbot/lookForTargets()
for(var/mob/living/carbon/human/H in view(7, src)) // Time to find a patient!
if(confirmTarget(H))
+32
View File
@@ -13,6 +13,8 @@
patrol_speed = 2
target_speed = 3
density = 1
var/default_icon_state = "secbot"
var/idcheck = FALSE // If true, arrests for having weapons without authorization.
var/check_records = FALSE // If true, arrests people without a record.
@@ -39,6 +41,8 @@
name = "Officer Beepsky"
desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
will_patrol = TRUE
maxHealth = 130
health = 130
/mob/living/bot/secbot/slime
name = "Slime Securitron"
@@ -56,6 +60,8 @@
/mob/living/bot/secbot/slime/slimesky
name = "Doctor Slimesky"
desc = "An old friend of Officer Beep O'sky. He prescribes beatings to rowdy slimes so that real doctors don't need to treat the xenobiologists."
maxHealth = 130
health = 130
/mob/living/bot/secbot/update_icons()
if(on && busy)
@@ -219,6 +225,32 @@
global_announcer.autosay("[src] is [action] a level [threat] [action != "fighting" ? "suspect" : "threat"] <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", "[src]", "Security")
UnarmedAttack(target)
/mob/living/bot/secbot/handlePanic() // Speed modification based on alert level.
. = 0
switch(get_security_level())
if("green")
. = 0
if("yellow")
. = 0
if("violet")
. = 0
if("orange")
. = 0
if("blue")
. = 1
if("red")
. = 2
if("delta")
. = 2
return .
// So Beepsky talks while beating up simple mobs.
/mob/living/bot/secbot/proc/insult(var/mob/living/L)
if(can_next_insult > world.time)
@@ -419,6 +419,10 @@
// Called in life() when the mob has no client.
/datum/species/proc/handle_npc(var/mob/living/carbon/human/H)
if(H.stat == CONSCIOUS && H.ai_holder)
if(H.resting)
H.resting = FALSE
H.update_canmove()
return
// Called when lying down on a water tile.
@@ -50,8 +50,10 @@
if(H)
if(H.looksSynthetic())
return "flashing a 'system offline' light"
else
else if(!H.ai_holder)
return show_ssd
else
return
/datum/species/proc/get_blood_colour(var/mob/living/carbon/human/H)
if(H)
@@ -62,6 +62,8 @@
if(prob(1))
H.emote(pick("scratch","jump","roll","tail"))
..()
/datum/species/monkey/get_random_name()
return "[lowertext(name)] ([rand(100,999)])"
@@ -60,6 +60,8 @@ var/list/mob_hat_cache = list()
var/serial_number = 0
var/name_override = 0
var/foreign_droid = FALSE
holder_type = /obj/item/weapon/holder/drone
can_be_antagged = FALSE
@@ -118,7 +120,8 @@ var/list/mob_hat_cache = list()
updatename()
/mob/living/silicon/robot/drone/init()
aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
if(!scrambledcodes && !foreign_droid)
aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
additional_law_channels["Drone"] = ":d"
if(!laws) laws = new law_type
if(!module) module = new module_type(src)
@@ -253,10 +256,10 @@ var/list/mob_hat_cache = list()
//For some goddamn reason robots have this hardcoded. Redefining it for our fragile friends here.
/mob/living/silicon/robot/drone/updatehealth()
if(status_flags & GODMODE)
health = 35
health = maxHealth
stat = CONSCIOUS
return
health = 35 - (getBruteLoss() + getFireLoss())
health = maxHealth - (getBruteLoss() + getFireLoss())
return
//Easiest to check this here, then check again in the robot proc.
@@ -29,6 +29,9 @@
for(var/mob/living/silicon/robot/drone/D in mob_list)
if(D.z != src.z)
continue
if(D.foreign_droid)
continue
dat += "<BR>[D.real_name] ([D.stat == 2 ? "<font color='red'>INACTIVE</FONT>" : "<font color='green'>ACTIVE</FONT>"])"
dat += "<font dize = 9><BR>Cell charge: [D.cell.charge]/[D.cell.maxcharge]."
dat += "<BR>Currently located in: [get_area(D)]."
@@ -56,6 +56,22 @@
/obj/item/weapon/stock_parts
)
/obj/item/weapon/gripper/security
name = "security gripper"
desc = "A simple grasping tool for corporate security work."
icon_state = "gripper-sec"
can_hold = list(
/obj/item/weapon/paper,
/obj/item/weapon/paper_bundle,
/obj/item/weapon/pen,
/obj/item/weapon/sample,
/obj/item/weapon/forensics/sample_kit,
/obj/item/device/taperecorder,
/obj/item/device/tape,
/obj/item/device/uv_light
)
/obj/item/weapon/gripper/paperwork
name = "paperwork gripper"
desc = "A simple grasping tool for clerical work."
@@ -0,0 +1,98 @@
/mob/living/silicon/robot/drone/swarm
name = "swarm drone"
real_name = "drone"
icon = 'icons/mob/swarmbot.dmi'
icon_state = "swarmer"
faction = "swarmer"
maxHealth = 75
health = 75
cell_emp_mult = 0.5
universal_speak = 0
universal_understand = 1
gender = NEUTER
pass_flags = PASSTABLE
braintype = "Drone"
lawupdate = 0
density = 1
idcard_type = /obj/item/weapon/card/id/syndicate
req_access = list(999)
integrated_light_power = 3
local_transmit = 0
can_pull_size = ITEMSIZE_NO_CONTAINER
can_pull_mobs = MOB_PULL_SMALLER
can_enter_vent_with = list(
/obj)
mob_always_swap = 1
softfall = TRUE
mob_size = MOB_LARGE
law_type = /datum/ai_laws/swarm_drone
module_type = /obj/item/weapon/robot_module/drone/swarm
hat_x_offset = 0
hat_y_offset = -10
foreign_droid = TRUE
scrambledcodes = TRUE
holder_type = /obj/item/weapon/holder/drone
can_be_antagged = TRUE
var/spell_setup = list(
/spell/aoe_turf/conjure/swarmer,
/spell/aoe_turf/conjure/forcewall/swarm,
/spell/aoe_turf/blink/swarm,
/spell/aoe_turf/conjure/swarmer/gunner,
/spell/aoe_turf/conjure/swarmer/melee
)
/mob/living/silicon/robot/drone/swarm/Initialize()
..()
add_language(LANGUAGE_SWARMBOT, 1)
for(var/spell in spell_setup)
src.add_spell(new spell, "nano_spell_ready", /obj/screen/movable/spell_master/swarm)
/mob/living/silicon/robot/drone/swarm/init()
..()
QDEL_NULL(aiCamera)
flavor_text = "Some form of ancient machine."
/mob/living/silicon/robot/drone/swarm/gunner
name = "swarm gunner"
real_name = "drone"
icon = 'icons/mob/swarmbot.dmi'
icon_state = "swarmer_ranged"
faction = "swarmer"
law_type = /datum/ai_laws/swarm_drone/soldier
module_type = /obj/item/weapon/robot_module/drone/swarm/ranged
spell_setup = list(
/spell/aoe_turf/conjure/swarmer,
/spell/aoe_turf/conjure/forcewall/swarm,
/spell/aoe_turf/blink/swarm
)
/mob/living/silicon/robot/drone/swarm/melee
name = "swarm melee"
real_name = "drone"
icon = 'icons/mob/swarmbot.dmi'
icon_state = "swarmer_melee"
faction = "swarmer"
law_type = /datum/ai_laws/swarm_drone/soldier
module_type = /obj/item/weapon/robot_module/drone/swarm/melee
spell_setup = list(
/spell/aoe_turf/conjure/swarmer,
/spell/aoe_turf/conjure/forcewall/swarm,
/spell/aoe_turf/blink/swarm
)
@@ -0,0 +1,117 @@
/spell/aoe_turf/conjure/swarmer
name = "Self Replication"
desc = "This ability constructs a standard swarmer shell that may activate at some point."
school = "conjuration"
charge_max = 120 SECONDS
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event)
hud_state = "swarm_replicate"
/spell/aoe_turf/conjure/swarmer/conjure_animation(var/atom/movable/overlay/animation, var/turf/target)
animation.icon_state = "deflect_static"
flick("shield2",animation)
spawn(1 SECOND)
qdel(animation)
/spell/aoe_turf/conjure/forcewall/swarm
name = "Null-Field"
desc = "Create a bubble of null-point energy."
summon_type = list(/obj/effect/forcefield/swarm)
duration = 30 SECONDS
charge_max = 60 SECONDS
school = "conjuration"
invocation = "none"
invocation_type = SpI_NONE
range = 0
hud_state = "wiz_shield"
/obj/effect/forcefield/swarm
desc = "A pocket of strange energy."
name = "Null-Field"
icon = 'icons/effects/effects.dmi'
icon_state = "shield-old"
invisibility = 0
/spell/aoe_turf/conjure/zeropointwell
name = "Zero-Point Well"
desc = "This ability constructs a standard zero-point energy well, capable of charging nearby swarmers."
school = "conjuration"
charge_max = 120 SECONDS
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/cult/pylon/swarm/zp_well)
hud_state = "swarm_zeropoint"
/spell/aoe_turf/conjure/zeropointbarricade
name = "Zero-Point Barricade"
desc = "This ability constructs a standard zero-point energy wall, used to create a secure passageway for allies, and a bastion for defense."
school = "conjuration"
charge_max = 120 SECONDS
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/cult/pylon/swarm/defender)
hud_state = "swarm_barricade"
/spell/aoe_turf/blink/swarm
name = "Warp"
desc = "Your null-point drive jaunts you to a new location."
school = "abjuration"
charge_max = 5 MINUTES
spell_flags = Z2NOCAST | IGNOREDENSE
invocation = "none"
invocation_type = SpI_NONE
range = 10
inner_radius = 5
hud_state = "swarm_warp"
/spell/aoe_turf/conjure/swarmer/gunner
name = "Generate Gunner"
desc = "This spell constructs a gunner swarmer shell that may activate at some point."
school = "conjuration"
charge_type = Sp_CHARGES
charge_max = 1
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner)
hud_state = "swarm_replicate"
/spell/aoe_turf/conjure/swarmer/melee
name = "Generate Impaler"
desc = "This spell constructs an impaler swarmer shell that may activate at some point."
school = "conjuration"
charge_type = Sp_CHARGES
charge_max = 1
spell_flags = 0
invocation = "none"
invocation_type = SpI_NONE
range = 0
summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee)
hud_state = "swarm_replicate"
@@ -0,0 +1,162 @@
//Swarm Assimilator / Breacher
/obj/item/weapon/matter_decompiler/swarm
name = "matter assimilator"
desc = "Used to eat some forms of simple machinery; and large, wall-shaped blocks of metal with energetic fields."
icon = 'icons/obj/device.dmi'
icon_state = "decompiler_swarm"
var/field_cooldown = 1 MINUTE
var/last_field = 0
/obj/item/weapon/matter_decompiler/swarm/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params)
if(!proximity) return //Not adjacent.
//We only want to deal with using this on turfs. Specific items aren't important.
var/turf/T = get_turf(target)
if(!istype(T))
return
//Used to give the right message.
var/grabbed_something = FALSE
for(var/mob/M in T)
if(istype(M,/mob/living/simple_mob/animal/passive/lizard) || istype(M,/mob/living/simple_mob/animal/passive/mouse))
src.loc.visible_message("<span class='danger'>[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.</span>","<span class='danger'>It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(M)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
return
else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
var/mob/living/silicon/robot/D = src.loc
if(!istype(D))
return
to_chat(D, "<span class='danger'>You begin decompiling [M].</span>")
if(!do_after(D,50))
to_chat(D, "<span class='danger'>You need to remain still while decompiling such a large object.</span>")
return
if(!M || !D) return
to_chat(D, "<span class='danger'>You carefully and thoroughly decompile [M], storing as much of its resources as you can within yourself.</span>")
qdel(M)
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
if(metal)
metal.add_charge(15000)
if(glass)
glass.add_charge(15000)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(1000)
return
else
continue
for(var/obj/W in T)
//Different classes of items give different commodities.
if(istype(W,/obj/structure/girder))
if(metal)
metal.add_charge(500)
else if(istype(W,/obj/machinery/power/emitter))
if(metal)
metal.add_charge(3000)
if(plastic)
plastic.add_charge(1000)
else if(istype(W,/obj/machinery/space_heater))
if(metal)
metal.add_charge(1500)
if(plastic)
plastic.add_charge(750)
else if(istype(W,/obj/structure/closet))
var/obj/structure/closet/C = W
if(!C.opened)
continue
if(istype(W,/obj/structure/closet/coffin))
if(wood)
wood.add_charge(1000)
else if(istype(W,/obj/structure/closet/crate/plastic))
if(plastic)
plastic.add_charge(750)
else
if(metal)
metal.add_charge(1000)
else
continue
qdel(W)
grabbed_something = TRUE
if(istype(T,/turf/simulated/wall) && (last_field < world.time + field_cooldown))
if(!(locate(/obj/effect/temporary_effect/pulse/disintegrate)))
last_field = world.time
to_chat(user, "<span class='alien'>You deploy an energetic field through \the [T], beginning its deconstruction.</span>")
to_chat(user, "<span class='warning'>You should stand back.</span>")
new /obj/effect/temporary_effect/pulse/disintegrate(T)
else
to_chat(user, "<span class='notice'>There is already a disintigration field affecting \the [T].</span>")
if(grabbed_something)
to_chat(user, "<span class='notice'>You deploy your decompiler and clear out the contents of \the [T].</span>")
else
to_chat(user, "<span class='danger'>Nothing on \the [T] is useful to you.</span>")
return
/obj/effect/temporary_effect/pulse/disintegrate
name = "molecular debonding field"
desc = "This is something you do not want to near."
icon = 'icons/mob/swarmbot.dmi'
icon_state = "disintegrate_pulse"
light_range = 4
light_power = 5
light_color = "#00B4D9"
pulses_remaining = 5
pulse_delay = 2 SECONDS
/obj/effect/temporary_effect/pulse/disintegrate/emp_act()
visible_message("<span class='warning'>\The [src] flickers, before dispersing energetically.</span>")
qdel(src)
/obj/effect/temporary_effect/pulse/disintegrate/on_pulse()
var/turf/T = get_turf(src)
if(istype(T,/turf/simulated/wall))
explosion(get_turf(src), -1, -1, 1, 3, adminlog = 0)
else
qdel(src)
/obj/effect/temporary_effect/pulse/disintegrate/Destroy()
if(istype(get_turf(src), /turf/simulated/wall))
explosion(get_turf(src), -1, 1, 2, 5, adminlog = 1)
..()
/obj/item/weapon/gun/energy/xray/swarm
name = "spectral projector"
desc = "A high-power laser gun capable of expelling concentrated gamma blasts, which are able to penetrate matter easier than \
standard xray beams, resulting in an effective 'anti-everything' energy weapon."
icon_state = "xray"
item_state = "xray"
origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
projectile_type = /obj/item/projectile/beam/shock
charge_cost = 175
self_recharge = TRUE
use_external_power = TRUE
firemodes = list(
list(mode_name="kill", projectile_type=/obj/item/projectile/beam/gamma, charge_cost = 300),
list(mode_name="deter", projectile_type=/obj/item/projectile/beam/shock, charge_cost = 175),
)
/obj/item/weapon/gun/energy/xray/swarm/Initialize()
..()
adjust_scale(-1, 1)
@@ -521,6 +521,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/gun/energy/taser/xeno/sec/robot(src)
src.modules += new /obj/item/taperoll/police(src)
src.modules += new /obj/item/weapon/reagent_containers/spray/pepper(src)
src.modules += new /obj/item/weapon/gripper/security(src)
src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src)
/obj/item/weapon/robot_module/robot/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
@@ -0,0 +1,29 @@
/obj/item/weapon/robot_module/drone/swarm
name = "swarm drone module"
var/id
/obj/item/weapon/robot_module/drone/swarm/New(var/mob/living/silicon/robot/robot)
..()
id = robot.idcard
src.modules += id
src.modules += new /obj/item/weapon/rcd/electric/mounted/borg/swarm(src)
src.modules += new /obj/item/device/flash/robot(src)
src.modules += new /obj/item/weapon/handcuffs/cable/tape/cyborg(src)
src.modules += new /obj/item/weapon/melee/baton/robot(src)
src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg/swarm(src)
src.modules += new /obj/item/weapon/matter_decompiler/swarm(src)
/obj/item/weapon/robot_module/drone/swarm/ranged
name = "swarm gunner module"
/obj/item/weapon/robot_module/drone/swarm/ranged/New(var/mob/living/silicon/robot/robot)
..()
src.modules += new /obj/item/weapon/gun/energy/xray/swarm(src)
/obj/item/weapon/robot_module/drone/swarm/melee/New(var/mob/living/silicon/robot/robot)
..()
src.modules += new /obj/item/weapon/melee/energy/sword/ionic_rapier/lance(src)
@@ -117,3 +117,17 @@
if(prob(poison_chance))
to_chat(L, "<span class='warning'>You feel a tiny prick.</span>")
L.reagents.add_reagent(poison_type, poison_per_bite)
/mob/living/simple_mob/animal/giant_spider/proc/make_spiderling()
adjust_scale(icon_scale_x * 0.7, icon_scale_y * 0.7)
maxHealth = round(maxHealth * 0.5)
health = round(health * 0.5)
melee_damage_lower *= 0.7
melee_damage_upper *= 0.7
response_harm = "kicks"
see_in_dark = max(2, round(see_in_dark * 0.6))
if(poison_per_bite)
poison_per_bite *= 1.3
@@ -22,3 +22,23 @@
speak_emote = list("hisses")
say_list_type = /datum/say_list/lizard
/mob/living/simple_mob/animal/passive/lizard/large
desc = "A cute, big lizard."
maxHealth = 20
health = 20
melee_damage_lower = 5
melee_damage_upper = 15
attack_sharp = TRUE
/mob/living/simple_mob/animal/passive/lizard/large/Initialize()
..()
adjust_scale(rand(12, 20) / 10)
/mob/living/simple_mob/animal/passive/lizard/large/defensive
maxHealth = 30
health = 30
ai_holder_type = /datum/ai_holder/simple_mob/retaliate/cooperative
@@ -97,6 +97,17 @@
body_color = "brown"
icon_state = "mouse_brown"
/mob/living/simple_mob/animal/passive/mouse/rat
name = "rat"
maxHealth = 20
health = 20
ai_holder_type = /datum/ai_holder/simple_mob/melee/evasive
/mob/living/simple_mob/animal/passive/mouse/rat/Initialize()
..()
adjust_scale(1.2)
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_mob/animal/passive/mouse/brown/Tom
name = "Tom"
+14
View File
@@ -425,6 +425,20 @@ proc/is_blind(A)
lname = "<span class='name'>[lname]</span> "
M << "<span class='deadsay'>" + create_text_tag("dead", "DEAD:", M.client) + " [lname][follow][message]</span>"
/proc/say_dead_object(var/message, var/obj/subject = null)
for(var/mob/M in player_list)
if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && M.client.holder.rights)) && M.is_preference_enabled(/datum/client_preference/show_dsay))
var/follow
var/lname = "Game Master"
if(M.forbid_seeing_deadchat && !M.client.holder)
continue
if(subject)
lname = "[subject.name] ([subject.x],[subject.y],[subject.z])"
lname = "<span class='name'>[lname]</span> "
M << "<span class='deadsay'>" + create_text_tag("event_dead", "EVENT:", M.client) + " [lname][follow][message]</span>"
//Announces that a ghost has joined/left, mainly for use with wizards
/proc/announce_ghost_joinleave(O, var/joined_ghosts = 1, var/message = "")
var/client/C
+6 -1
View File
@@ -22,6 +22,12 @@
charge_cost = 400
recharge_time = 7 //Time it takes for shots to recharge (in ticks)
/obj/item/weapon/gun/energy/taser/mounted/cyborg/swarm
name = "disabler"
desc = "An archaic device which attacks the target's nervous-system or control circuits."
projectile_type = /obj/item/projectile/beam/stun/disabler
charge_cost = 200
recharge_time = 0.5 SECONDS
/obj/item/weapon/gun/energy/stunrevolver
name = "stun revolver"
@@ -32,7 +38,6 @@
projectile_type = /obj/item/projectile/energy/electrode/strong
charge_cost = 300
/obj/item/weapon/gun/energy/crossbow
name = "mini energy-crossbow"
desc = "A weapon favored by many mercenary stealth specialists."
@@ -108,3 +108,89 @@
list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_handed_penalty=15, burst_accuracy=null, dispersion=null),
list(mode_name="short bursts", burst=3, fire_delay=null, move_delay=5, one_handed_penalty=30, burst_accuracy=list(0,-15,-15), dispersion=list(0.0, 0.6, 1.0)),
)
/obj/item/weapon/gun/magnetic/railgun/heater
name = "coil rifle"
desc = "A large rifle designed and produced after the Grey Hour."
description_info = "The MI-51B is a Martian weapon designed in the days after the Grey Hour, in preparation for the need for updated equipment by Solar forces.<br>\
The design is based upon a larger rail-type weapon design."
icon_state = "railgun_sec"
item_state = "cshotgun"
removable_components = TRUE
initial_cell_type = /obj/item/weapon/cell/high
initial_capacitor_type = /obj/item/weapon/stock_parts/capacitor
fire_delay = 8
slot_flags = SLOT_BACK
slowdown = 0
slowdown_held = 0
slowdown_worn = 0
power_cost = 400
projectile_type = /obj/item/projectile/bullet/magnetic/heated
loaded = null
empty_sound = 'sound/weapons/smg_empty_alarm.ogg'
firemodes = list(
list(mode_name="high power", power_cost = 400, projectile_type = /obj/item/projectile/bullet/magnetic/heated, burst=1, fire_delay=8, move_delay=null, one_handed_penalty=15),
list(mode_name="low power", power_cost = 150, projectile_type = /obj/item/projectile/bullet/magnetic/heated/weak, burst=1, fire_delay=5, move_delay=null, one_handed_penalty=15),
)
/obj/item/weapon/gun/magnetic/railgun/heater/pistol
name = "coil pistol"
desc = "A large pistol designed and produced after the Grey Hour."
description_info = "The MI-60D `Peacemaker` is a Martian weapon designed in the days after the Grey Hour, in preparation for the need for updated equipment by Solar forces.<br>\
The design is based upon a larger rail-type hybrid weapon design, though much smaller in scale."
icon_state = "peacemaker"
item_state = "revolver"
w_class = ITEMSIZE_NORMAL
initial_cell_type = /obj/item/weapon/cell/high
initial_capacitor_type = /obj/item/weapon/stock_parts/capacitor
slot_flags = SLOT_BELT|SLOT_HOLSTER
firemodes = list(
list(mode_name="lethal", power_cost = 2000, projectile_type = /obj/item/projectile/bullet/magnetic/heated, burst=1, fire_delay=8, move_delay=null, one_handed_penalty=0),
list(mode_name="stun", power_cost = 1500, projectile_type = /obj/item/projectile/energy/electrode/stunshot, burst=1, fire_delay=5, move_delay=null, one_handed_penalty=0),
)
/obj/item/weapon/gun/magnetic/railgun/heater/pistol/hos
name = "prototype peacemaker"
dna_lock = TRUE
description_antag = "This weapon starts with a DNA locking chip attached. Using an EMAG on the weapon will disarm it, and allow you to use the chip as your own."
firemodes = list(
list(mode_name="lethal", power_cost = 1500, projectile_type = /obj/item/projectile/bullet/magnetic/heated, burst=1, fire_delay=8, move_delay=null, one_handed_penalty=0),
list(mode_name="stun", power_cost = 1200, projectile_type = /obj/item/projectile/energy/electrode/stunshot, burst=1, fire_delay=5, move_delay=null, one_handed_penalty=0),
)
/obj/item/weapon/gun/magnetic/railgun/flechette/sif
name = "shredder rifle"
desc = "The MI-12B Kaldr is a burst fire capable coilgun that fires modified slugs intended for damaging soft targets."
description_fluff = "The Kaldr is a weapon recently deployed to various outposts on Sif, as well as local hunting guilds for the rapid dispatching of invasive wildlife."
icon_state = "railgun_sifguard"
item_state = "z8carbine"
initial_cell_type = /obj/item/weapon/cell/high
initial_capacitor_type = /obj/item/weapon/stock_parts/capacitor/adv
slot_flags = SLOT_BACK
slowdown = 0.3
power_cost = 200
projectile_type = /obj/item/projectile/bullet/magnetic/flechette/hunting
empty_sound = 'sound/weapons/smg_empty_alarm.ogg'
firemodes = list(
list(mode_name="semiauto", burst=1, fire_delay=0, move_delay=null, one_handed_penalty=15, burst_accuracy=null, dispersion=null),
list(mode_name="short bursts", burst=3, fire_delay=null, move_delay=5, one_handed_penalty=30, burst_accuracy=list(0,-15,-15), dispersion=list(0.0, 0.6, 1.0)),
)
@@ -86,6 +86,19 @@
tracer_type = /obj/effect/projectile/tracer/xray
impact_type = /obj/effect/projectile/impact/xray
/obj/item/projectile/beam/gamma
name = "gamma beam"
icon_state = "xray"
fire_sound = 'sound/weapons/eluger.ogg'
damage = 10
armor_penetration = 90
irradiate = 20
light_color = "#00CC33"
muzzle_type = /obj/effect/projectile/muzzle/xray
tracer_type = /obj/effect/projectile/tracer/xray
impact_type = /obj/effect/projectile/impact/xray
/obj/item/projectile/beam/cyan
name = "cyan beam"
icon_state = "cyan"
@@ -215,6 +228,23 @@
icon_state = "stun"
agony = 30
/obj/item/projectile/beam/stun/disabler
muzzle_type = /obj/effect/projectile/muzzle/laser_omni
tracer_type = /obj/effect/projectile/tracer/laser_omni
impact_type = /obj/effect/projectile/impact/laser_omni
/obj/item/projectile/beam/stun/disabler/on_hit(atom/target, blocked = 0, def_zone)
. = ..(target, blocked, def_zone)
if(. && istype(target, /mob/living/silicon/robot) && prob(agony))
var/mob/living/silicon/robot/R = target
var/drainamt = agony * (rand(5, 15) / 10)
R.drain_power(0, 0, drainamt)
if(istype(firer, /mob/living/silicon/robot)) // Mischevious sappers, the swarm drones are.
var/mob/living/silicon/robot/A = firer
if(A.cell)
A.cell.give(drainamt * 2)
/obj/item/projectile/beam/shock
name = "shock beam"
icon_state = "lightning"
@@ -22,6 +22,28 @@
damage = 20
armor_penetration = 100
/obj/item/projectile/bullet/magnetic/flechette/hunting
name = "shredder slug"
armor_penetration = 30
SA_bonus_damage = 40
SA_vulnerability = SA_ANIMAL
/obj/item/projectile/bullet/magnetic/heated
name = "slug"
icon_state = "gauss"
weaken = 0
stun = 0
damage = 30
damage_type = SEARING
embed_chance = 0
/obj/item/projectile/bullet/magnetic/heated/weak
icon_state = "gauss_silenced"
damage = 15
agony = 5
embed_chance = 0
armor_penetration = 50
/obj/item/projectile/bullet/magnetic/fuelrod
name = "fuel rod"
icon_state = "fuel-deuterium"