mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2026-07-11 08:14:26 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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'> [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'> [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)
|
||||
@@ -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.")
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user