Merge remote-tracking branch 'upstream/dev' into runtime

This commit is contained in:
mwerezak
2015-02-22 21:13:20 -05:00
265 changed files with 7485 additions and 5929 deletions

View File

@@ -595,7 +595,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/weapon/cloaking_device(M), slot_r_store)
M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile(M), slot_r_hand)
M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver(M), slot_r_hand)
M.equip_to_slot_or_del(new /obj/item/ammo_magazine/a357(M), slot_l_store)
if ("tournament chef") //Steven Seagal FTW
@@ -710,7 +710,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
for(var/i=3, i>0, i--)
sec_briefcase.contents += new /obj/item/weapon/spacecash/c1000
sec_briefcase.contents += new /obj/item/weapon/gun/energy/crossbow
sec_briefcase.contents += new /obj/item/weapon/gun/projectile/mateba
sec_briefcase.contents += new /obj/item/weapon/gun/projectile/revolver/mateba
sec_briefcase.contents += new /obj/item/ammo_magazine/a357
sec_briefcase.contents += new /obj/item/weapon/plastique
M.equip_to_slot_or_del(sec_briefcase, slot_l_hand)
@@ -892,7 +892,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses)
M.equip_to_slot_or_del(new /obj/item/clothing/suit/hgpirate(M), slot_wear_suit)
M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(M), slot_back)
M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/mateba(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(M), slot_belt)
M.equip_to_slot_or_del(new /obj/item/clothing/under/soviet(M), slot_w_uniform)
var/obj/item/weapon/card/id/W = new(M)
W.name = "[M.real_name]'s ID Card"

View File

@@ -3,11 +3,13 @@
set desc = "Fires a laser bolt at your position. You should only do this as a(n) (a)ghost"
set category = "Fun"
var/turf/target = get_turf(src.mob)
admin_log_and_message_admins("has fired the Icarus point defense laser at [target.x]-[target.y]-[target.z]")
if(!src.holder)
src << "Only administrators may use this command."
return
Icarus_FireLaser(get_turf(src.mob))
Icarus_FireLaser(target)
/client/proc/FireCannons()
@@ -15,11 +17,13 @@
set desc = "Fires an explosive missile at your position. You should only do this as a(n) (a)ghost."
set category = "Fun"
var/turf/target = get_turf(src.mob)
admin_log_and_message_admins("has fired the Icarus main gun projectile at [target.x]-[target.y]-[target.z]")
if(!src.holder)
src << "Only administrators may use this command."
return
Icarus_FireCannon(get_turf(src.mob))
Icarus_FireCannon(target)
/client/proc/ChangeIcarusPosition()
@@ -27,6 +31,7 @@
set desc = "Lets you chose the position of the Icarus in regards to the map."
set category = "Fun"
admin_log_and_message_admins("is changing the Icarus position.")
if(!src.holder)
src << "Only administrators may use this command."
return
@@ -122,4 +127,4 @@ proc/Icarus_SetPosition(var/user)
if(!direction)
return
icarus_position = directions[direction]
icarus_position = directions[direction]

View File

@@ -153,7 +153,7 @@ var/global/sent_strike_team = 0
equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword(src), slot_l_store)
equip_to_slot_or_del(new /obj/item/weapon/grenade/flashbang(src), slot_r_store)
equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen(src), slot_s_store)
equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/mateba(src), slot_belt)
equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(src), slot_belt)
equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(src), slot_r_hand)

View File

@@ -37,7 +37,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt)
equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/monocle(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
equip_to_slot_or_del(new /obj/item/weapon/card/emag(src), slot_l_store)
equip_to_slot_or_del(new /obj/item/weapon/gun/dartgun/vox/raider(src), slot_r_hand)
equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/dartgun/vox/raider(src), slot_r_hand)
equip_to_slot_or_del(new /obj/item/device/multitool(src), slot_l_hand)
if(4) // Vox medic!
@@ -46,7 +46,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt) // Who needs actual surgical tools?
equip_to_slot_or_del(new /obj/item/clothing/glasses/hud/health(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
equip_to_slot_or_del(new /obj/item/weapon/circular_saw(src), slot_l_store)
equip_to_slot_or_del(new /obj/item/weapon/gun/dartgun/vox/medical, slot_r_hand)
equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/dartgun/vox/medical, slot_r_hand)
equip_to_slot_or_del(new /obj/item/clothing/mask/breath(src), slot_wear_mask)
equip_to_slot_or_del(new /obj/item/weapon/tank/nitrogen(src), slot_back)

View File

@@ -40,7 +40,7 @@
return
/obj/item/assembly/shock_kit/receive_signal()
if(istype(loc, /obj/structure/stool/bed/chair/e_chair))
var/obj/structure/stool/bed/chair/e_chair/C = loc
if(istype(loc, /obj/structure/bed/chair/e_chair))
var/obj/structure/bed/chair/e_chair/C = loc
C.shock()
return

View File

@@ -54,8 +54,8 @@ datum/preferences
var/age = 30 //age of character
var/spawnpoint = "Arrivals Shuttle" //where this character will spawn (0-2).
var/b_type = "A+" //blood type (not-chooseable)
var/underwear = 1 //underwear type
var/undershirt = 1 //undershirt type
var/underwear //underwear type
var/undershirt //undershirt type
var/backbag = 2 //backpack type
var/h_style = "Bald" //Hair type
var/r_hair = 0 //Hair color
@@ -373,12 +373,11 @@ datum/preferences
else
dat += "<br><br>"
if(gender == MALE)
dat += "Underwear: <a href ='?_src_=prefs;preference=underwear;task=input'><b>[underwear_m[underwear]]</b></a><br>"
else
dat += "Underwear: <a href ='?_src_=prefs;preference=underwear;task=input'><b>[underwear_f[underwear]]</b></a><br>"
var/list/undies = gender == MALE ? underwear_m : underwear_f
dat += "Undershirt: <a href='?_src_=prefs;preference=undershirt;task=input'><b>[undershirt_t[undershirt]]</b></a><br>"
dat += "Underwear: <a href ='?_src_=prefs;preference=underwear;task=input'><b>[get_key_by_value(undies,underwear)]</b></a><br>"
dat += "Undershirt: <a href='?_src_=prefs;preference=undershirt;task=input'><b>[get_key_by_value(undershirt_t,undershirt)]</b></a><br>"
dat += "Backpack Type:<br><a href ='?_src_=prefs;preference=bag;task=input'><b>[backbaglist[backbag]]</b></a><br>"
@@ -1178,10 +1177,12 @@ datum/preferences
if("f_style")
f_style = random_facial_hair_style(gender, species)
if("underwear")
underwear = rand(1,underwear_m.len)
var/r = pick(underwear_m)
underwear = underwear_m[r]
ShowChoices(user)
if("undershirt")
undershirt = rand(1,undershirt_t.len)
var/r = pick(undershirt_t)
undershirt = undershirt_t[r]
ShowChoices(user)
if("eyes")
r_eyes = rand(0,255)
@@ -1299,7 +1300,7 @@ datum/preferences
if("hair")
if(species == "Human" || species == "Unathi" || species == "Tajara" || species == "Skrell")
var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference") as color|null
var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference", rgb(r_hair, g_hair, b_hair)) as color|null
if(new_hair)
r_hair = hex2num(copytext(new_hair, 2, 4))
g_hair = hex2num(copytext(new_hair, 4, 6))
@@ -1319,7 +1320,7 @@ datum/preferences
h_style = new_h_style
if("facial")
var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference") as color|null
var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(r_facial, g_facial, b_facial)) as color|null
if(new_facial)
r_facial = hex2num(copytext(new_facial, 2, 4))
g_facial = hex2num(copytext(new_facial, 4, 6))
@@ -1351,7 +1352,7 @@ datum/preferences
var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options
if(new_underwear)
underwear = underwear_options.Find(new_underwear)
underwear = underwear_options[new_underwear]
ShowChoices(user)
if("undershirt")
@@ -1360,11 +1361,11 @@ datum/preferences
var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_options
if (new_undershirt)
undershirt = undershirt_options.Find(new_undershirt)
undershirt = undershirt_options[new_undershirt]
ShowChoices(user)
if("eyes")
var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference") as color|null
var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(r_eyes, g_eyes, b_eyes)) as color|null
if(new_eyes)
r_eyes = hex2num(copytext(new_eyes, 2, 4))
g_eyes = hex2num(copytext(new_eyes, 4, 6))
@@ -1379,7 +1380,7 @@ datum/preferences
if("skin")
if(species == "Unathi" || species == "Tajara" || species == "Skrell")
var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference") as color|null
var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(r_skin, g_skin, b_skin)) as color|null
if(new_skin)
r_skin = hex2num(copytext(new_skin, 2, 4))
g_skin = hex2num(copytext(new_skin, 4, 6))
@@ -1705,12 +1706,8 @@ datum/preferences
else if(status == "mechanical")
I.mechanize()
if(underwear > underwear_m.len || underwear < 1)
underwear = 0 //I'm sure this is 100% unnecessary, but I'm paranoid... sue me. //HAH NOW NO MORE MAGIC CLONING UNDIES
character.underwear = underwear
if(undershirt > undershirt_t.len || undershirt < 1)
undershirt = 0
character.undershirt = undershirt
if(backbag > 4 || backbag < 1)
@@ -1745,4 +1742,4 @@ datum/preferences
user << browse(dat, "window=saves;size=300x390")
/datum/preferences/proc/close_load_dialog(mob/user)
user << browse(null, "window=saves")
user << browse(null, "window=saves")

View File

@@ -416,11 +416,25 @@ var/global/list/gear_datums = list()
cost = 1
/datum/gear/armpit
display_name = "shoulder holster"
display_name = "holster, armpit"
path = /obj/item/clothing/accessory/holster/armpit
slot = slot_tie
cost = 2
allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security")
allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective")
/datum/gear/hip
display_name = "holster, hip"
path = /obj/item/clothing/accessory/holster/hip
slot = slot_tie
cost = 2
allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security", "Detective")
/datum/gear/waist
display_name = "holster, waist"
path = /obj/item/clothing/accessory/holster/waist
slot = slot_tie
cost = 2
allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security", "Detective")
/datum/gear/tie_blue
display_name = "tie, blue"

View File

@@ -192,6 +192,13 @@
if(isnull(species) || !(species in playable_species))
species = "Human"
if(isnum(underwear))
var/list/undies = gender == MALE ? underwear_m : underwear_f
underwear = undies[undies[underwear]]
if(isnum(undershirt))
undershirt = undershirt_t[undershirt_t[undershirt]]
if(isnull(language)) language = "None"
if(isnull(spawnpoint)) spawnpoint = "Arrivals Shuttle"
if(isnull(nanotrasen_relation)) nanotrasen_relation = initial(nanotrasen_relation)
@@ -214,8 +221,6 @@
r_eyes = sanitize_integer(r_eyes, 0, 255, initial(r_eyes))
g_eyes = sanitize_integer(g_eyes, 0, 255, initial(g_eyes))
b_eyes = sanitize_integer(b_eyes, 0, 255, initial(b_eyes))
underwear = sanitize_integer(underwear, 1, underwear_m.len, initial(underwear))
undershirt = sanitize_integer(undershirt, 1, undershirt_t.len, initial(undershirt))
backbag = sanitize_integer(backbag, 1, backbaglist.len, initial(backbag))
b_type = sanitize_text(b_type, initial(b_type))

View File

@@ -84,3 +84,18 @@
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30)
siemens_coefficient = 0.9
body_parts_covered = UPPER_TORSO|ARMS
//Orange emergency space suit
/obj/item/clothing/head/helmet/space/emergency
name = "Emergency Space Helmet"
icon_state = "emergencyhelm"
item_state = "emergencyhelm"
desc = "A simple helmet with a built in light, smells like mothballs."
/obj/item/clothing/suit/space/emergency
name = "Emergency Softsuit"
icon_state = "syndicate-orange"
item_state = "syndicate-orange"
desc = "A thin, ungainly softsuit colored in blaze orange for rescuers to easily locate, looks pretty fragile."
slowdown = 4

View File

@@ -1,51 +0,0 @@
//Weapon types intended to be used with rig modules
/obj/item/weapon/gun/energy/lasercannon/mounted/load_into_chamber()
if(in_chamber)
return 1
var/obj/item/rig_module/module = loc
if(!istype(module))
return 0
if(module.holder && module.holder.wearer)
var/mob/living/carbon/human/H = module.holder.wearer
if(istype(H) && H.back)
var/obj/item/weapon/rig/suit = H.back
if(istype(suit) && suit.cell && suit.cell.charge >= 250)
suit.cell.use(250)
in_chamber = new /obj/item/projectile/beam/heavylaser(src)
return 1
return 0
/obj/item/weapon/gun/energy/gun/mounted/load_into_chamber()
if(in_chamber)
return 1
var/obj/item/rig_module/module = loc
if(!istype(module))
return 0
if(module.holder && module.holder.wearer)
var/mob/living/carbon/human/H = module.holder.wearer
if(istype(H) && H.back)
var/obj/item/weapon/rig/suit = H.back
if(istype(suit) && suit.cell && suit.cell.charge >= 250)
suit.cell.use(250)
var/prog_path = projectile_type
in_chamber = new prog_path(src)
return 1
return 0
/obj/item/weapon/gun/energy/taser/mounted/load_into_chamber()
if(in_chamber)
return 1
var/obj/item/rig_module/module = loc
if(!istype(module))
return 0
if(module.holder && module.holder.wearer)
var/mob/living/carbon/human/H = module.holder.wearer
if(istype(H) && H.back)
var/obj/item/weapon/rig/suit = H.back
if(istype(suit) && suit.cell && suit.cell.charge >= 250)
suit.cell.use(250)
var/prog_path = projectile_type
in_chamber = new prog_path(src)
return 1
return 0

View File

@@ -196,38 +196,31 @@
slowdown = 1
armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 20, bio = 0, rad = 0)
siemens_coefficient = 0.7
var/obj/item/clothing/accessory/holster/holster
/obj/item/clothing/suit/armor/tactical/verb/holster()
set name = "Holster"
set category = "Object"
set src in usr
if(!istype(usr, /mob/living)) return
if(usr.stat) return
/obj/item/clothing/suit/armor/tactical/New()
..()
holster = new(src)
if(!holstered)
if(!istype(usr.get_active_hand(), /obj/item/weapon/gun))
usr << "\blue You need your gun equiped to holster it."
return
var/obj/item/weapon/gun/W = usr.get_active_hand()
if (!W.isHandgun())
usr << "\red This gun won't fit in \the belt!"
return
holstered = usr.get_active_hand()
usr.drop_item()
holstered.loc = src
usr.visible_message("\blue \The [usr] holsters \the [holstered].", "You holster \the [holstered].")
else
if(istype(usr.get_active_hand(),/obj) && istype(usr.get_inactive_hand(),/obj))
usr << "\red You need an empty hand to draw the gun!"
else
if(usr.a_intent == "hurt")
usr.visible_message("\red \The [usr] draws \the [holstered], ready to shoot!", \
"\red You draw \the [holstered], ready to shoot!")
else
usr.visible_message("\blue \The [usr] draws \the [holstered], pointing it at the ground.", \
"\blue You draw \the [holstered], pointing it at the ground.")
usr.put_in_hands(holstered)
holstered = null
/obj/item/clothing/suit/armor/tactical/attackby(obj/item/W as obj, mob/user as mob)
..()
holster.attackby(W, user)
/obj/item/clothing/suit/armor/tactical/verb/holster()
set name = "Holster"
set category = "Object"
set src in usr
if(!istype(usr, /mob/living)) return
if(usr.stat) return
if(!holster.holstered)
var/obj/item/W = usr.get_active_hand()
if(!istype(W, /obj/item))
usr << "<span class='warning'>You need your gun equiped to holster it.</span>"
return
holster.holster(W, usr)
else
holster.unholster(usr)
//Non-hardsuit ERT armor.
/obj/item/clothing/suit/armor/vest/ert
@@ -259,3 +252,101 @@
name = "emergency response team medical armor"
desc = "A set of armor worn by medical members of the NanoTrasen Emergency Response Team. Has red and white highlights."
icon_state = "ertarmor_med"
//New Vests
/obj/item/clothing/suit/storage/vest
name = "armor vest"
desc = "A simple kevlar plate carrier."
icon_state = "kvest"
item_state = "kvest"
armor = list(melee = 50, bullet = 15, laser = 50, energy = 10, bomb = 25, bio = 0, rad = 0)
allowed = list(/obj/item/weapon/gun,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs)
/obj/item/clothing/suit/storage/vest/officer
name = "officer armor vest"
desc = "A simple kevlar plate carrier beloning to Nanotrasen. This one has a security holobadge clipped to the chest."
icon_state = "officervest_nobadge"
item_state = "officervest_nobadge"
icon_badge = "officervest_badge"
icon_nobadge = "officervest_nobadge"
/obj/item/clothing/suit/storage/vest/warden
name = "warden armor vest"
desc = "A simple kevlar plate carrier belonging to Nanotrasen. This one has a silver badge clipped to the chest."
icon_state = "wardenvest_nobadge"
item_state = "wardenvest_nobadge"
icon_badge = "wardenvest_badge"
icon_nobadge = "wardenvest_nobadge"
/obj/item/clothing/suit/storage/vest/hos
name = "commander armor vest"
desc = "A simple kevlar plate carrier belonging to Nanotrasen. This one has a gold badge clipped to the chest."
icon_state = "hosvest_nobadge"
item_state = "hosvest_nobadge"
icon_badge = "hosvest_badge"
icon_nobadge = "hosvest_nobadge"
/obj/item/clothing/suit/storage/vest/pcrc
name = "PCRC armor vest"
desc = "A simple kevlar plate carrier belonging to Proxima Centauri Risk Control. This one has a PCRC crest clipped to the chest."
icon_state = "pcrcvest_nobadge"
item_state = "pcrcvest_nobadge"
icon_badge = "pcrcvest_badge"
icon_nobadge = "pcrcvest_nobadge"
/obj/item/clothing/suit/storage/vest/detective
name = "detective armor vest"
desc = "A simple kevlar plate carrier in a vintage brown, it has a badge clipped to the chest that reads, 'Private investigator'."
icon_state = "detectivevest_nobadge"
item_state = "detectivevest_nobadge"
icon_badge = "detectivevest_badge"
icon_nobadge = "detectivevest_nobadge"
/obj/item/clothing/suit/storage/vest/heavy
name = "heavy armor vest"
desc = "A heavy kevlar plate carrier with webbing attached."
icon_state = "webvest"
item_state = "webvest"
armor = list(melee = 50, bullet = 40, laser = 50, energy = 25, bomb = 30, bio = 0, rad = 0)
slowdown = 1
/obj/item/clothing/suit/storage/vest/heavy/officer
name = "officer heavy armor vest"
desc = "A heavy kevlar plate carrier belonging to Nanotrasen with webbing attached. This one has a security holobadge clipped to the chest."
icon_state = "officerwebvest_nobadge"
item_state = "officerwebvest_nobadge"
icon_badge = "officerwebvest_badge"
icon_nobadge = "officerwebvest_nobadge"
/obj/item/clothing/suit/storage/vest/heavy/warden
name = "warden heavy armor vest"
desc = "A heavy kevlar plate carrier belonging to Nanotrasen with webbing attached. This one has a silver badge clipped to the chest."
icon_state = "wardenwebvest_nobadge"
item_state = "wardenwebvest_nobadge"
icon_badge = "wardenwebvest_badge"
icon_nobadge = "wardenwebvest_nobadge"
/obj/item/clothing/suit/storage/vest/heavy/hos
name = "commander heavy armor vest"
desc = "A heavy kevlar plate carrier belonging to Nanotrasen with webbing attached. This one has a gold badge clipped to the chest."
icon_state = "hoswebvest_nobadge"
item_state = "hoswebvest_nobadge"
icon_badge = "hoswebvest_badge"
icon_nobadge = "hoswebvest_nobadge"
/obj/item/clothing/suit/storage/vest/heavy/pcrc
name = "PCRC heavy armor vest"
desc = "A heavy kevlar plate carrier belonging to Proxima Centauri Risk Control with webbing attached. This one has a PCRC crest clipped to the chest."
icon_state = "pcrcwebvest_nobadge"
item_state = "pcrcwebvest_nobadge"
icon_badge = "pcrcwebvest_badge"
icon_nobadge = "pcrcwebvest_nobadge"
/obj/item/clothing/suit/storage/vest/heavy/merc
name = "comfortable heavy armor vest"
desc = "A heavy kevlar plate carrier in a fetching tan. Fits pretty well."
icon_state = "mercwebvest"
item_state = "mercwebvest"
armor = list(melee = 60, bullet = 60, laser = 60, energy = 40, bomb = 40, bio = 0, rad = 0)
slowdown = 0

View File

@@ -15,7 +15,7 @@
item_state = "bluetag"
blood_overlay_type = "armor"
body_parts_covered = UPPER_TORSO
allowed = list (/obj/item/weapon/gun/energy/laser/bluetag)
allowed = list (/obj/item/weapon/gun/energy/lasertag/blue)
siemens_coefficient = 3.0
/obj/item/clothing/suit/redtag
@@ -25,7 +25,7 @@
item_state = "redtag"
blood_overlay_type = "armor"
body_parts_covered = UPPER_TORSO
allowed = list (/obj/item/weapon/gun/energy/laser/redtag)
allowed = list (/obj/item/weapon/gun/energy/lasertag/red)
siemens_coefficient = 3.0
/*

View File

@@ -48,4 +48,36 @@
else //in case some goofy admin switches icon states around without switching the icon_open or icon_closed
usr << "You attempt to button-up the velcro on your [src], before promptly realising how silly you are."
return
update_clothing_icon() //so our overlays update
update_clothing_icon() //so our overlays update
//New Vest 4 pocket storage and badge toggles, until suit accessories are a thing.
/obj/item/clothing/suit/storage/vest/heavy/New()
..()
pockets = new/obj/item/weapon/storage/internal(src)
pockets.storage_slots = 4
pockets.max_w_class = 2
pockets.max_combined_w_class = 8
/obj/item/clothing/suit/storage/vest
var/icon_badge
var/icon_nobadge
verb/toggle()
set name ="Adjust Badge"
set category = "Object"
set src in usr
if(!usr.canmove || usr.stat || usr.restrained())
return 0
if(icon_state == icon_badge)
icon_state = icon_nobadge
usr << "You unclip the badge from the vest."
else if(icon_state == icon_nobadge)
icon_state = icon_badge
usr << "You clip the badge to the vest."
else
usr << "You can't find a badge for [src]."
return
update_clothing_icon()

View File

@@ -4,45 +4,40 @@
icon_state = "holster"
item_color = "holster"
slot = "utility"
var/obj/item/weapon/gun/holstered = null
//subtypes can override this to specify what can be holstered
/obj/item/clothing/accessory/holster/proc/can_holster(obj/item/weapon/gun/W)
return W.isHandgun()
var/obj/item/holstered = null
/obj/item/clothing/accessory/holster/proc/holster(obj/item/I, mob/user as mob)
if(holstered)
user << "<span class='warning'>There is already a [holstered] holstered here!</span>"
user << "<span class='warning'>There is already \a [holstered] holstered here!</span>"
return
if (!istype(I, /obj/item/weapon/gun))
user << "<span class='warning'>Only guns can be holstered!</span>"
if (!(I.slot_flags & SLOT_HOLSTER))
user << "<span class='warning'>[I] won't fit in [src]!</span>"
return
var/obj/item/weapon/gun/W = I
if (!can_holster(W))
user << "<span class='warning'>This [W] won't fit in the [src]!</span>"
return
holstered = W
holstered = I
user.drop_from_inventory(holstered)
holstered.loc = src
holstered.add_fingerprint(user)
user.visible_message("<span class='notice'>[user] holsters the [holstered].</span>", "<span class='notice'>You holster the [holstered].</span>")
user.visible_message("<span class='notice'>[user] holsters \the [holstered].</span>", "<span class='notice'>You holster \the [holstered].</span>")
/obj/item/clothing/accessory/holster/proc/unholster(mob/user as mob)
if(!holstered)
return
if(istype(user.get_active_hand(),/obj) && istype(user.get_inactive_hand(),/obj))
user << "<span class='warning'>You need an empty hand to draw the [holstered]!</span>"
user << "<span class='warning'>You need an empty hand to draw \the [holstered]!</span>"
else
if(user.a_intent == "hurt")
usr.visible_message("\red [user] draws the [holstered], ready to shoot!</span>", \
"<span class='warning'>You draw the [holstered], ready to shoot!</span>")
usr.visible_message(
"\red [user] draws \the [holstered], ready to shoot!</span>",
"<span class='warning'>You draw \the [holstered], ready to shoot!</span>"
)
else
user.visible_message("<span class='notice'>[user] draws the [holstered], pointing it at the ground.</span>", \
"<span class='notice'>You draw the [holstered], pointing it at the ground.</span>")
user.visible_message(
"<span class='notice'>[user] draws \the [holstered], pointing it at the ground.</span>",
"<span class='notice'>You draw \the [holstered], pointing it at the ground.</span>"
)
user.put_in_hands(holstered)
holstered.add_fingerprint(user)
holstered = null
@@ -86,6 +81,7 @@
if(!istype(usr, /mob/living)) return
if(usr.stat) return
//can't we just use src here?
var/obj/item/clothing/accessory/holster/H = null
if (istype(src, /obj/item/clothing/accessory/holster))
H = src
@@ -98,22 +94,28 @@
usr << "<span class='warning'>Something is very wrong.</span>"
if(!H.holstered)
if(!istype(usr.get_active_hand(), /obj/item/weapon/gun))
var/obj/item/W = usr.get_active_hand()
if(!istype(W, /obj/item))
usr << "<span class='warning'>You need your gun equiped to holster it.</span>"
return
var/obj/item/weapon/gun/W = usr.get_active_hand()
H.holster(W, usr)
else
H.unholster(usr)
/obj/item/clothing/accessory/holster/armpit
name = "shoulder holster"
name = "armpit holster"
desc = "A worn-out handgun holster. Perfect for concealed carry"
icon_state = "holster"
item_color = "holster"
/obj/item/clothing/accessory/holster/waist
name = "shoulder holster"
name = "waist holster"
desc = "A handgun holster. Made of expensive leather."
icon_state = "holster"
item_color = "holster_low"
item_color = "holster_low"
/obj/item/clothing/accessory/holster/hip
name = "hip holster"
desc = "A handgun holster slung low on the hip, draw pardner!"
icon_state = "holster_hip"
item_color = "holster_hip"

View File

@@ -1340,22 +1340,21 @@
desc = "A stun baton used for incapacitating targets; there seems to be a bunch of tally marks set into the handle."
///// Deckard .44 - Callum Leamas - Roaper
/obj/item/weapon/gun/projectile/detective/fluff/callum_leamas
/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas
name = "Deckard .44"
desc = "A custom built revolver, based off the semi-popular Detective Special model."
icon = 'icons/obj/custom_items.dmi'
icon_state = "leamas-empty"
ammo_type = /obj/item/ammo_magazine/c38/rubber
/obj/item/weapon/gun/projectile/detective/fluff/callum_leamas/update_icon()
/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas/update_icon()
..()
if(loaded.len)
icon_state = "leamas-loaded"
else
icon_state = "leamas-empty"
/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob)
/obj/item/weapon/gun/projectile/revolver/detective/fluff/callum_leamas/load_ammo(var/obj/item/A, mob/user)
if(istype(A, /obj/item/ammo_magazine))
flick("leamas-reloading",src)
..()

View File

@@ -0,0 +1,166 @@
/obj/machinery/atmospherics/pipe
description_info = "This pipe, and all other pipes, can be connected or disconnected by a wrench. The internal pressure of the pipe must \
be below 300 kPa to do this. More pipes can be obtained from the pipe dispenser."
/obj/machinery/atmospherics/pipe/New() //This is needed or else 20+ lines of copypasta to dance around inheritence.
..()
description_info += "<br>Most pipes and atmospheric devices can be connected or disconnected with a wrench. The pipe's pressure must not be too high, \
or if it is a device, it must be turned off first."
//HE pipes
/obj/machinery/atmospherics/pipe/simple/heat_exchanging
description_info = "This radiates heat from the pipe's gas to space, cooling it down."
//Supply/Scrubber pipes
/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/simple/visible/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/simple/hidden/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
//Universal adapters
/obj/machinery/atmospherics/pipe/simple/visible/universal
description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
/obj/machinery/atmospherics/pipe/simple/hidden/universal
description_info = "This allows you to connect 'normal' pipes, red 'scrubber' pipes, and blue 'supply' pipes."
//Three way manifolds
/obj/machinery/atmospherics/pipe/manifold
description_info = "A normal pipe with three ends to connect to."
/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold/visible/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold/hidden/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
//Insulated pipes
/obj/machinery/atmospherics/pipe/simple/insulated
description_info = "This is completely useless, use a normal pipe." //Sorry, but it's true.
//Four way manifolds
/obj/machinery/atmospherics/pipe/manifold4w
description_info = "This is a four-way pipe."
/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
description_info = "This is a special 'supply' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
description_info = "This is a special 'scrubber' pipe, which does not connect to 'normal' pipes. If you want to connect it, use \
a Universal Adapter pipe."
//Endcaps
/obj/machinery/atmospherics/pipe/cap
description_info = "This is a cosmetic attachment, as pipes currently do not spill their contents into the air."
//T-shaped valves
/obj/machinery/atmospherics/tvalve
description_info = "Click this to toggle the mode. The direction with the green light is where the gas will flow."
//Normal valves
/obj/machinery/atmospherics/valve
description_info = "Click this to turn the valve. If red, the pipes on each end are seperated. Otherwise, they are connected."
//TEG ports
/obj/machinery/atmospherics/binary/circulator
description_info = "This generates electricity, depending on the difference in temperature between each side of the machine. The meter in \
the center of the machine gives an indicator of how much elecrtricity is being generated."
//Passive gates
/obj/machinery/atmospherics/binary/passive_gate
description_info = "This is a one-way regulator, allowing gas to flow only at a specific pressure and flow rate. If the light is green, it is flowing."
//Normal pumps (high power one inherits from this)
/obj/machinery/atmospherics/binary/pump
description_info = "This moves gas from one pipe to another. A higher target pressure demands more energy. The side with the red end is the output."
//Vents
/obj/machinery/atmospherics/unary/vent_pump
description_info = "This pumps the contents of the attached pipe out into the atmosphere, if needed. It can be controlled from an Air Alarm."
//Freezers
/obj/machinery/atmospherics/unary/freezer
description_info = "Cools down the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
screwdriver, and then using a crowbar."
//Heaters
/obj/machinery/atmospherics/unary/heater
description_info = "Heats up the gas of the pipe it is connected to. It uses massive amounts of electricity while on. \
It can be upgraded by replacing the capacitors, manipulators, and matter bins. It can be deconstructed by screwing the maintenance panel open with a \
screwdriver, and then using a crowbar."
//Gas injectors
/obj/machinery/atmospherics/unary/outlet_injector
description_info = "Outputs the pipe's gas into the atmosphere, similar to an airvent. It can be controlled by a nearby atmospherics computer. \
A green light on it means it is on."
//Scrubbers
/obj/machinery/atmospherics/unary/vent_scrubber
description_info = "This filters the atmosphere of harmful gas. Filtered gas goes to the pipes connected to it, typically a scrubber pipe. \
It can be controlled from an Air Alarm. It can be configured to drain all air rapidly with a 'panic syphon' from an air alarm."
//Omni filters
/obj/machinery/atmospherics/omni/filter
description_info = "Filters gas from a custom input direction, with up to two filtered outputs and a 'everything else' \
output. The filtered output's arrows glow orange."
//Omni mixers
/obj/machinery/atmospherics/omni/mixer
description_info = "Combines gas from custom input and output directions. The percentage of combined gas can be defined."
//Canisters
/obj/machinery/portable_atmospherics/canister
description_info = "The canister can be connected to a connector port with a wrench. Tanks of gas (the kind you can hold in your hand) \
can be filled by the canister, by using the tank on the canister, increasing the release pressure, then opening the valve until it is full, and then close it. \
*DO NOT* remove the tank until the valve is closed. A gas analyzer can be used to check the contents of the canister."
description_antag = "Canisters can be damaged, spilling their contents into the air, or you can just leave the release valve open."
//Portable pumps
/obj/machinery/portable_atmospherics/powered/pump
description_info = "Invaluable for filling air in a room rapidly after a breach repair. The internal gas container can be filled by \
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the air pump."
//Portable scrubbers
/obj/machinery/portable_atmospherics/powered/scrubber
description_info = "Filters the air, placing harmful gases into the internal gas container. The container can be emptied by \
connecting it to a connector port. The pump can pump the air in (sucking) or out (blowing), at a specific target pressure. The powercell inside can be \
replaced by using a screwdriver, and then adding a new cell. A tank of gas can also be attached to the scrubber. "
//Meters
/obj/machinery/meter
description_info = "Measures the volume and temperature of the pipe under the meter."
//Pipe dispensers
/obj/machinery/pipedispenser
description_info = "This can be moved by using a wrench. You will need to wrench it again when you want to use it. You can put \
excess (atmospheric) pipes into the dispenser, as well. The dispenser requires electricity to function."

View File

@@ -0,0 +1,35 @@
/obj/machinery/power/supermatter
description_info = "When energized by a laser (or something hitting it), it emits radiation and heat. If the heat reaches above 7000 kelvin, it will send an alert and start taking damage. \
After integrity falls to zero percent, it will delaminate, causing a massive explosion, station-wide radiation spikes, and hallucinations. \
Supermatter reacts badly to oxygen in the atmosphere. It'll also heat up really quick if it is in vacuum.<br>\
<br>\
Supermatter cores are extremely dangerous to be close to, and requires protection to handle properly. The protection you will need is:<br>\
Optical meson scanners on your eyes, to prevent hallucinations when looking at the supermatter.<br>\
Radiation helmet and suit, as the supermatter is radioactive.<br>\
<br>\
Touching the supermatter will result in *instant death*, with no corpse left behind! You can drag the supermatter, but anything else will kill you. \
It is advised to obtain a genetic backup before trying to drag it."
description_antag = "Exposing the supermatter to oxygen or vaccum will cause it to start rapidly heating up. Sabotaging the supermatter and making it explode will \
cause a period of lag as the explosion is processed by the server, as well as irradiating the entire station and causing hallucinations to happen. \
Wearing radiation equipment will protect you from most of the delamination effects sans explosion."
/obj/machinery/power/apc
description_info = "An APC (Area Power Controller) regulates and supplies backup power for the area they are in. Their power channels are divided \
out into 'environmental' (Items that manipulate airflow and temperature), 'lighting' (the lights), and 'equipment' (Everything else that consumes power). \
Power consumption and backup power cell charge can be seen from the interface, further controls (turning a specific channel on, off or automatic, \
toggling the APC's ability to charge the backup cell, or toggling power for the entire area via master breaker) first requires the interface to be unlocked \
with an ID with Engineering access or by one of the station's robots or the artificial intelligence."
description_antag = "This can be emagged to unlock it. It will cause the APC to have a blue error screen. \
Wires can be pulsed remotely with a signaler attached to it. A powersink will also drain any APCs connected to the same wire the powersink is on."
/obj/item/inflatable
description_info = "Inflate by using it in your hand. The inflatable barrier will inflate on your tile. To deflate it, use the 'deflate' verb."
/obj/structure/inflatable
description_info = "To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever."
/obj/structure/inflatable/door
description_info = "Click the door to open or close it. It only stops air while closed.<br>\
To remove these safely, use the 'deflate' verb. Hitting these with any objects will probably puncture and break it forever."

View File

@@ -0,0 +1,8 @@
/mob/living/silicon/robot/drone
description_info = "Drones are player-controlled synthetics which are lawed to maintain the station and not \
interact with anyone else, except for other drones. They hold a wide array of tools to build, repair, maintain, and clean. \
They fuction similarly to other synthetics, in that they require recharging regularly, have laws, and are resilient to many hazards, \
such as fire, radiation, vacuum, and more. Ghosts can join the round as a maintenance drone by using the appropriate verb in the 'ghost' tab. \
An inactive drone can be rebooted by swiping an ID card on it with engineering or robotics access."
description_antag = "An Electromagnetic Sequencer can be used to subvert the drone to your cause."

View File

@@ -0,0 +1,24 @@
/obj/item/stack/rods
description_info = "Made from metal sheets. You can build a grille by using it in your hand. \
Clicking on a floor without any tiles will reinforce the floor. You can make reinforced glass by combining rods and normal glass sheets."
/obj/item/stack/sheet/glass
description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets."
/obj/item/stack/sheet/glass/cyborg
description_info = "Use in your hand to build a window. Can be upgraded to reinforced glass by adding metal rods, which are made from metal sheets.<br>\
As a synthetic, you can acquire more sheets of glass by recharging."
/obj/item/stack/sheet/glass/reinforced
description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage."
/obj/item/stack/sheet/glass/reinforced/cyborg
description_info = "Use in your hand to build a window. Reinforced glass is much stronger against damage.<br>\
As a synthetic, you can gain more reinforced glass by recharging."
/obj/item/stack/sheet/metal/cyborg
description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it.<br>\
You can replenish your supply of metal as a synthetic by recharging."
/obj/item/stack/sheet
description_info = "Use in your hand to bring up the recipe menu. If you have enough sheets, click on something on the list to build it."

View File

@@ -0,0 +1,15 @@
/obj/structure/girder
description_info = "Use metal sheets on this to build a normal wall. Adding plasteel instead will make a reinforced wall.<br>\
A false wall can be made by using a crowbar on this girder, and then adding metal or plasteel.<br>\
You can dismantle the grider with a wrench."
/obj/structure/girder/reinforced
description_info = "Add another sheet of plasteel to finish."
/obj/structure/grille
description_info = "A powered and knotted wire underneath this will cause the grille to shock anyone not wearing insulated gloves.<br>\
Wirecutters will turn the grille into metal rods instantly. Grilles are made with metal rods."
/obj/structure/lattice
description_info = "Add a metal floor tile to build a floor on top of the lattice.<br>\
Lattices can be made by applying metal rods to a space tile."

View File

@@ -0,0 +1,3 @@
/turf/simulated/wall
description_info = "You can deconstruct this by welding it, and then wrenching the girder.<br>\
You can build a wall by using metal sheets and making a girder, then adding more metal or plasteel."

View File

@@ -0,0 +1,71 @@
/* This code is responsible for the examine tab. When someone examines something, it copies the examined object's description_info,
description_fluff, and description_antag, and shows it in a new tab.
In this file, some atom and mob stuff is defined here. It is defined here instead of in the normal files, to keep the whole system self-contained.
This means that this file can be unchecked, along with the other examine files, and can be removed entirely with no effort.
*/
/atom/
var/description_info = null //Helpful blue text.
var/description_fluff = null //Green text about the atom's fluff, if any exists.
var/description_antag = null //Malicious red text, for the antags.
/atom/examine(mob/user)
..()
user.description_holders["info"] = get_description_info()
user.description_holders["fluff"] = get_description_fluff()
if(user.mind && user.mind.special_role || isobserver(user)) //Runtime prevention, as ghosts don't have minds.
user.description_holders["antag"] = get_description_antag()
if(name) //This shouldn't be needed but I'm paranoid.
user.description_holders["name"] = "[src.name]" //\icon[src]
user.description_holders["icon"] = "\icon[src]"
if(desc)
user << desc
user.description_holders["desc"] = src.desc
else
user.description_holders["desc"] = null //This is needed, or else if you examine one thing with a desc, then another without, the panel will retain the first examined's desc.
//Override these if you need special behaviour for a specific type.
/atom/proc/get_description_info()
if(description_info)
return description_info
return
/atom/proc/get_description_fluff()
if(description_fluff)
return description_fluff
return
/atom/proc/get_description_antag()
if(description_antag)
return description_antag
return
/mob/
var/description_holders[0]
/mob/Stat()
..()
if(statpanel("Examine"))
stat(null,"[description_holders["icon"]] <font size='5'>[description_holders["name"]]</font>") //The name, written in big letters.
stat(null,"[description_holders["desc"]]") //the default examine text.
if(description_holders["info"])
stat(null,"<font color='#084B8A'><b>[description_holders["info"]]</b></font>") //Blue, informative text.
if(description_holders["fluff"])
stat(null,"<font color='#298A08'><b>[description_holders["fluff"]]</b></font>") //Yellow, fluff-related text.
if(description_holders["antag"])
stat(null,"<font color='#8A0808'><b>[description_holders["antag"]]</b></font>") //Red, malicious antag-related text
/mob/living/get_description_fluff()
if(flavor_text) //Get flavor text for the green text.
return flavor_text
else //No flavor text? Try for hardcoded fluff instead.
return ..()
/mob/living/carbon/human/get_description_fluff()
return print_flavor_text(0)

View File

@@ -182,10 +182,10 @@
visible_message("[src] fades away as it shatters!")
del(src)
/obj/structure/stool/bed/chair/holochair/Del()
/obj/structure/bed/chair/holochair/Del()
..()
/obj/structure/stool/bed/chair/holochair/attackby(obj/item/weapon/W as obj, mob/user as mob)
/obj/structure/bed/chair/holochair/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/wrench))
user << ("<span class='notice'>It's a holochair, you can't dismantle it!</span>")
return

View File

@@ -335,6 +335,14 @@
icon_state = "unathiknife"
attack_verb = list("ripped", "torn", "cut")
/obj/item/weapon/hatchet/tacknife
name = "tactical knife"
desc = "You'd be killing loads of people if this was Medal of Valor: Heroes of Nyx."
icon = 'icons/obj/weapons.dmi'
icon_state = "tacknife"
item_state = "knife"
attack_verb = list("stabbed", "chopped", "cut")
/obj/item/weapon/scythe
icon_state = "scythe0"
name = "scythe"

View File

@@ -208,6 +208,7 @@
return 1
//Attemps to remove an object on a mob. Will not move it to another area or such, just removes from the mob.
//It does call u_equip() though. So it can drop items to the floor but only if src is human.
/mob/proc/remove_from_mob(var/obj/O)
src.u_equip(O)
if (src.client)
@@ -242,16 +243,7 @@
/** BS12's proc to get the item in the active hand. Couldn't find the /tg/ equivalent. **/
/mob/proc/equipped()
if(issilicon(src))
if(isrobot(src))
if(src:module_active)
return src:module_active
else
if (hand)
return l_hand
else
return r_hand
return
return get_active_hand() //TODO: get rid of this proc
/mob/living/carbon/human/proc/equip_if_possible(obj/item/W, slot, del_on_fail = 1) // since byond doesn't seem to have pointers, this seems like the best way to do this :/
//warning: icky code

View File

@@ -341,7 +341,7 @@
/mob/living/carbon/can_use_hands()
if(handcuffed)
return 0
if(buckled && ! istype(buckled, /obj/structure/stool/bed/chair)) // buckling does not restrict hands
if(buckled && ! istype(buckled, /obj/structure/bed/chair)) // buckling does not restrict hands
return 0
return 1

View File

@@ -213,7 +213,7 @@
distance = 1
if (src.stat)
msg += "<span class='warning'>[t_He] [t_is]n't responding to anything around [t_him] and seems to be asleep.</span>\n"
if((stat == 2 || src.health < config.health_threshold_crit) && distance <= 3)
if((stat == 2 || src.losebreath) && distance <= 3)
msg += "<span class='warning'>[t_He] does not appear to be breathing.</span>\n"
if(istype(usr, /mob/living/carbon/human) && !usr.stat && Adjacent(usr))
usr.visible_message("<b>[usr]</b> checks [src]'s pulse.", "You check [src]'s pulse.")
@@ -451,6 +451,7 @@
msg += "\n[t_He] is [pose]"
user << msg
..()
//Helper procedure. Called by /mob/living/carbon/human/examine() and /mob/living/carbon/human/Topic() to determine HUD access to security and medical records.
/proc/hasHUD(mob/M as mob, hudtype)

View File

@@ -696,6 +696,8 @@
number += 2
if(istype(src.head, /obj/item/clothing/head/helmet/space))
number += 2
if(istype(src.head, /obj/item/clothing/head/helmet/space/emergency))
number -= 2
if(istype(src.glasses, /obj/item/clothing/glasses/thermal))
number -= 1
if(istype(src.glasses, /obj/item/clothing/glasses/sunglasses))
@@ -1220,10 +1222,11 @@
/mob/living/carbon/human/can_inject(var/mob/user, var/error_msg, var/target_zone)
. = 1
if(!user)
target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
else if(!target_zone)
target_zone = user.zone_sel.selecting
if(!target_zone)
if(!user)
target_zone = pick("chest","chest","chest","left leg","right leg","left arm", "right arm", "head")
else
target_zone = user.zone_sel.selecting
switch(target_zone)
if("head")
@@ -1236,7 +1239,7 @@
// Might need re-wording.
user << "<span class='alert'>There is no exposed flesh or thin material [target_zone == "head" ? "on their head" : "on their body"] to inject into.</span>"
/mob/living/carbon/human/print_flavor_text()
/mob/living/carbon/human/print_flavor_text(var/shrink = 1)
var/list/equipment = list(src.head,src.wear_mask,src.glasses,src.w_uniform,src.wear_suit,src.gloves,src.shoes)
var/head_exposed = 1
var/face_exposed = 1
@@ -1272,7 +1275,10 @@
if((T == "head" && head_exposed) || (T == "face" && face_exposed) || (T == "eyes" && eyes_exposed) || (T == "torso" && torso_exposed) || (T == "arms" && arms_exposed) || (T == "hands" && hands_exposed) || (T == "legs" && legs_exposed) || (T == "feet" && feet_exposed))
flavor_text += flavor_texts[T]
flavor_text += "\n\n"
return ..()
if(!shrink)
return flavor_text
else
return ..()
/mob/living/carbon/human/getDNA()
if(species.flags & NO_SCAN)

View File

@@ -116,6 +116,7 @@
if(src.grabbed_by.len || src.buckled || !src.canmove || src==H)
accurate = 1 // certain circumstances make it impossible for us to evade punches
rand_damage = 5
// Process evasion and blocking
var/miss_type = 0
@@ -209,7 +210,7 @@
w_uniform.add_fingerprint(M)
var/datum/organ/external/affecting = get_organ(ran_zone(M.zone_sel.selecting))
if (istype(r_hand,/obj/item/weapon/gun) || istype(l_hand,/obj/item/weapon/gun))
if(istype(r_hand,/obj/item/weapon/gun) || istype(l_hand,/obj/item/weapon/gun))
var/obj/item/weapon/gun/W = null
var/chance = 0
@@ -231,9 +232,13 @@
var/randn = rand(1, 100)
if(!(species.flags & NO_SLIP) && randn <= 25)
apply_effect(3, WEAKEN, run_armor_check(affecting, "melee"))
var/armor_check = run_armor_check(affecting, "melee")
apply_effect(3, WEAKEN, armor_check)
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
visible_message("\red <B>[M] has pushed [src]!</B>")
if(armor_check < 2)
visible_message("<span class='danger'>[M] has pushed [src]!</span>")
else
visible_message("<span class='warning'>[M] attempted to push [src]!</span>")
return
var/talked = 0 // BubbleWrap

View File

@@ -38,9 +38,9 @@ emp_act
return -1 // complete projectile permutation
//Shrapnel
if (P.damage_type == BRUTE)
if(P.can_embed())
var/armor = getarmor_organ(organ, "bullet")
if((P.embed && prob(20 + max(P.damage - armor, -10))))
if(prob(20 + max(P.damage - armor, -10)))
var/obj/item/weapon/shard/shrapnel/SP = new()
SP.name = (P.name != "shrapnel")? "[P.name] shrapnel" : "shrapnel"
SP.desc = "[SP.desc] It looks like it was fired from [P.shot_from]."
@@ -304,10 +304,7 @@ emp_act
throw_mode_off()
return
var/dtype = BRUTE
if(istype(O,/obj/item/weapon))
var/obj/item/weapon/W = O
dtype = W.damtype
var/dtype = O.damtype
var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR)
var/zone
@@ -318,11 +315,11 @@ emp_act
zone = ran_zone("chest",75) //Hits a random part of the body, geared towards the chest
//check if we hit
var/miss_chance = 15
if (O.throw_source)
var/distance = get_dist(O.throw_source, loc)
zone = get_zone_with_miss_chance(zone, src, min(15*(distance-2), 0))
else
zone = get_zone_with_miss_chance(zone, src, 15)
miss_chance = max(15*(distance-2), 0)
zone = get_zone_with_miss_chance(zone, src, miss_chance)
if(!zone)
visible_message("\blue \The [O] misses [src] narrowly!")
@@ -370,17 +367,21 @@ emp_act
affecting.embed(I)
// Begin BS12 momentum-transfer code.
if(O.throw_source && speed >= THROWNOBJ_KNOCKBACK_SPEED)
var/obj/item/weapon/W = O
var/momentum = speed/THROWNOBJ_KNOCKBACK_DIVISOR
var/mass = 1.5
if(istype(O, /obj/item))
var/obj/item/I = O
mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
var/momentum = speed*mass
if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
var/dir = get_dir(O.throw_source, src)
visible_message("\red [src] staggers under the impact!","\red You stagger under the impact!")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
if(!O || !src) return
if(!W || !src) return
if(W.loc == src && W.sharp) //Projectile is embedded and suitable for pinning.
if(O.loc == src && O.sharp) //Projectile is embedded and suitable for pinning.
var/turf/T = near_wall(dir,2)
if(T)
@@ -389,6 +390,13 @@ emp_act
src.anchored = 1
src.pinned += O
/mob/living/carbon/human/embed(var/obj/O, var/def_zone=null)
if(!def_zone) ..()
var/datum/organ/external/affecting = get_organ(def_zone)
if(affecting)
affecting.embed(O)
/mob/living/carbon/human/proc/bloody_hands(var/mob/living/source, var/amount = 2)
if (gloves)

View File

@@ -26,7 +26,7 @@
if(wear_suit)
tally += wear_suit.slowdown
if(istype(buckled, /obj/structure/stool/bed/chair/wheelchair))
if(istype(buckled, /obj/structure/bed/chair/wheelchair))
for(var/organ_name in list("l_hand","r_hand","l_arm","r_arm"))
var/datum/organ/external/E = get_organ(organ_name)
if(!E || (E.status & ORGAN_DESTROYED))

View File

@@ -1,3 +1,16 @@
/*
Add fingerprints to items when we put them in our hands.
This saves us from having to call add_fingerprint() any time something is put in a human's hands programmatically.
*/
/mob/living/carbon/human/put_in_l_hand(var/obj/item/W)
. = ..()
if(.) W.add_fingerprint(src)
/mob/living/carbon/human/put_in_r_hand(var/obj/item/W)
. = ..()
if(.) W.add_fingerprint(src)
/mob/living/carbon/human/verb/quick_equip()
set name = "quick-equip"
set hidden = 1
@@ -758,13 +771,7 @@ It can still be worn/put on as normal.
if(slot_to_process)
if(strip_item) //Stripping an item from the mob
var/obj/item/W = strip_item
target.u_equip(W)
if (target.client)
target.client.screen -= W
if (W)
W.loc = target.loc
W.layer = initial(W.layer)
W.dropped(target)
target.remove_from_mob(W)
W.add_fingerprint(source)
if(slot_to_process == slot_l_store) //pockets! Needs to process the other one too. Snowflake code, wooo! It's not like anyone will rewrite this anytime soon. If I'm wrong then... CONGRATULATIONS! ;)
if(target.r_store)

View File

@@ -326,7 +326,6 @@
if(istype(O)) O.add_autopsy_data("Radiation Poisoning", damage)
proc/breathe()
if(reagents.has_reagent("lexorin")) return
if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell)) return
if(species && (species.flags & NO_BREATHE || species.flags & IS_SYNTHETIC)) return
@@ -439,17 +438,15 @@
return
if(!breath || (breath.total_moles == 0) || suiciding)
failed_last_breath = 1
if(suiciding)
adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster
failed_last_breath = 1
oxygen_alert = max(oxygen_alert, 1)
return 0
if(health > config.health_threshold_crit)
adjustOxyLoss(HUMAN_MAX_OXYLOSS)
failed_last_breath = 1
else
adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS)
failed_last_breath = 1
oxygen_alert = max(oxygen_alert, 1)

View File

@@ -209,5 +209,5 @@
if("resin membrane")
new /obj/effect/alien/resin/membrane(loc)
if("resin nest")
new /obj/structure/stool/bed/nest(loc)
new /obj/structure/bed/nest(loc)
return

View File

@@ -64,7 +64,7 @@
target.apply_effects(stutter = attack_damage * 2, agony = attack_damage* 3, blocked = armour)
if("l_leg", "l_foot", "r_leg", "r_foot")
if(!target.lying)
target.visible_message("<span class='warning'>[src] gives way slightly.</span>")
target.visible_message("<span class='warning'>[target] gives way slightly.</span>")
target.apply_effect(attack_damage*3, AGONY, armour)
else if(attack_damage >= 5 && !(target == user) && (stun_chance + attack_damage * 5 >= 100) && armour < 2) // Chance to get the usual throwdown as well (25% standard chance)
if(!target.lying)
@@ -118,22 +118,28 @@
user.visible_message("<span class='danger'>[user] slapped [target] across \his cheek!</span>")
if(3 to 4)
user.visible_message(pick(
80; "<span class='danger'>[user] [pick(attack_verb)] [target] in the head!</span>", //striking someone with a 'closed fist' is called punching them.
20; "<span class='danger'>[user] struck [target] in the head[pick("", " with a closed fist")]!</span>"
40; "<span class='danger'>[user] [pick(attack_verb)] [target] in the head!</span>",
30; "<span class='danger'>[user] struck [target] in the head[pick("", " with a closed fist")]!</span>",
30; "<span class='danger'>[user] threw a hook against [target]'s head!</span>"
))
if(5)
user.visible_message(pick(
10; "<span class='danger'>[user] gave [target] a resounding slap to the face!</span>",
90; "<span class='danger'>[user] smashed \his [pick(attack_noun)] into [target]'s [organ]!</span>"
30; "<span class='danger'>[user] gave [target] a resounding [pick("slap", "punch")] to the face!</span>",
40; "<span class='danger'>[user] smashed \his [pick(attack_noun)] into [target]'s face!</span>",
30; "<span class='danger'>[user] gave a strong blow against [target]'s jaw!</span>"
))
else
// ----- BODY ----- //
switch(attack_damage)
if(1 to 2) user.visible_message("<span class='danger'>[user] slapped [target]'s [organ]!</span>")
if(3 to 4) user.visible_message("<span class='danger'>[user] [pick(attack_verb)] [target] in \his [organ]!</span>")
if(5) user.visible_message("<span class='danger'>[user] smashed \his [pick(attack_noun)] into [target]'s [organ]!</span>")
if(1 to 2) user.visible_message("<span class='danger'>[user] threw a glancing punch at [target]'s [organ]!</span>")
if(1 to 4) user.visible_message("<span class='danger'>[user] [pick(attack_verb)] [target] in \his [organ]!</span>")
if(5)
user.visible_message(pick(
50; "<span class='danger'>[user] smashed \his [pick(attack_noun)] into [target]'s [organ]!</span>",
50; "<span class='danger'>[user] landed a striking [pick(attack_noun)] on [target]'s [organ]!</span>"
))
else
user.visible_message("<span class='danger'>[user] [pick("punched", "threw a punch", "struck", "slapped", "slammed their [pick(attack_noun)] into")] [target]'s [organ]!</span>") //why do we have a separate set of verbs for lying targets?
user.visible_message("<span class='danger'>[user] [pick("punched", "threw a punch against", "struck", "slammed their [pick(attack_noun)] into")] [target]'s [organ]!</span>") //why do we have a separate set of verbs for lying targets?
/datum/unarmed_attack/kick
attack_verb = list("kicked", "kicked", "kicked", "kneed")
@@ -177,7 +183,7 @@
/datum/unarmed_attack/stomp
attack_verb = null
attack_noun = list("kick")
attack_noun = list("stomp")
attack_sound = "swing_hit"
damage = 0
@@ -189,7 +195,7 @@
if(!istype(target))
return 0
if (!user.lying && (target.lying || zone in list("l_foot", "r_foot")))
if (!user.lying && (target.lying || (zone in list("l_foot", "r_foot"))))
if(target.grabbed_by == user && target.lying)
return 0
var/datum/organ/external/E = user.organs_by_name["l_foot"]
@@ -214,6 +220,5 @@
attack_damage = Clamp(attack_damage, 1, 5)
switch(attack_damage)
if(1 to 2) user.visible_message("<span class='danger'>[user] [pick("stepped on", "treaded on")] [target]'s [organ]!</span>") //stepped on conveys the same meaning and is more recognizable as an actual word than "clomped"
if(3 to 4) user.visible_message("<span class='danger'>[pick("[user] stomped on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down onto")] [target]'s [organ]!</span>")
if(1 to 4) user.visible_message("<span class='danger'>[pick("[user] stomped on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down onto")] [target]'s [organ]!</span>")
if(5) user.visible_message("<span class='danger'>[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed \his [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!</span>") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/

View File

@@ -107,28 +107,29 @@ Please contact me on #coderbus IRC. ~Carn x
//Human Overlays Indexes/////////
#define MUTATIONS_LAYER 1
#define DAMAGE_LAYER 2
#define UNIFORM_LAYER 3
#define TAIL_LAYER 4 //bs12 specific. this hack is probably gonna come back to haunt me
#define ID_LAYER 5
#define SHOES_LAYER 6
#define GLOVES_LAYER 7
#define SUIT_LAYER 8
#define GLASSES_LAYER 9
#define BELT_LAYER 10 //Possible make this an overlay of somethign required to wear a belt?
#define SUIT_STORE_LAYER 11
#define BACK_LAYER 12
#define HAIR_LAYER 13 //TODO: make part of head layer?
#define EARS_LAYER 14
#define FACEMASK_LAYER 15
#define HEAD_LAYER 16
#define COLLAR_LAYER 17
#define HANDCUFF_LAYER 18
#define LEGCUFF_LAYER 19
#define L_HAND_LAYER 20
#define R_HAND_LAYER 21
#define FIRE_LAYER 22 //If you're on fire
#define TARGETED_LAYER 23 //BS12: Layer for the target overlay from weapon targeting system
#define TOTAL_LAYERS 23
#define SURGERY_LEVEL 3 //bs12 specific.
#define UNIFORM_LAYER 4
#define TAIL_LAYER 5 //bs12 specific. this hack is probably gonna come back to haunt me
#define ID_LAYER 6
#define SHOES_LAYER 7
#define GLOVES_LAYER 8
#define SUIT_LAYER 9
#define GLASSES_LAYER 10
#define BELT_LAYER 11 //Possible make this an overlay of somethign required to wear a belt?
#define SUIT_STORE_LAYER 12
#define BACK_LAYER 13
#define HAIR_LAYER 14 //TODO: make part of head layer?
#define EARS_LAYER 15
#define FACEMASK_LAYER 16
#define HEAD_LAYER 17
#define COLLAR_LAYER 18
#define HANDCUFF_LAYER 19
#define LEGCUFF_LAYER 20
#define L_HAND_LAYER 21
#define R_HAND_LAYER 22
#define FIRE_LAYER 23 //If you're on fire
#define TARGETED_LAYER 24 //BS12: Layer for the target overlay from weapon targeting system
#define TOTAL_LAYERS 24
//////////////////////////////////
/mob/living/carbon/human
@@ -376,12 +377,11 @@ proc/get_damage_icon_part(damage_state, body_part)
stand_icon.Blend(new/icon('icons/mob/human_face.dmi', "lips_[lip_style]_s"), ICON_OVERLAY)
//Underwear
if(underwear >0 && underwear < 12 && species.flags & HAS_UNDERWEAR)
if(!fat && !skeleton)
stand_icon.Blend(new /icon('icons/mob/human.dmi', "underwear[underwear]_[g]_s"), ICON_OVERLAY)
if(underwear && species.flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', underwear), ICON_OVERLAY)
if(undershirt>0 && undershirt < 5 && species.flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', "undershirt[undershirt]_s"), ICON_OVERLAY)
if(undershirt && species.flags & HAS_UNDERWEAR)
stand_icon.Blend(new /icon('icons/mob/human.dmi', undershirt), ICON_OVERLAY)
if(update_icons)
update_icons()
@@ -510,6 +510,7 @@ proc/get_damage_icon_part(damage_state, body_part)
update_inv_legcuffed(0)
update_inv_pockets(0)
update_fire(0)
update_surgery(0)
UpdateDamageIcon()
update_icons()
//Hud Stuff
@@ -548,16 +549,9 @@ proc/get_damage_icon_part(damage_state, body_part)
overlays_standing[UNIFORM_LAYER] = null
// This really, really seems like it should not be mixed in the middle of display code...
// Automatically drop anything in store / id / belt if you're not wearing a uniform. //CHECK IF NECESARRY
for( var/obj/item/thing in list(r_store, l_store, wear_id, belt) ) //
if(thing) //
u_equip(thing) //
if (client) //
client.screen -= thing //
//
if (thing) //
thing.loc = loc //
thing.dropped(src) //
thing.layer = initial(thing.layer)
for( var/obj/item/thing in list(r_store, l_store, wear_id, belt) )
if(thing)
remove_from_mob(thing)
if(update_icons) update_icons()
/mob/living/carbon/human/update_inv_wear_id(var/update_icons=1)
@@ -724,13 +718,22 @@ proc/get_damage_icon_part(damage_state, body_part)
belt.screen_loc = ui_belt //TODO
var/t_state = belt.item_state
if(!t_state) t_state = belt.icon_state
var/image/standing = image("icon_state" = "[t_state]")
if(belt.icon_override)
overlays_standing[BELT_LAYER] = image("icon" = belt.icon_override, "icon_state" = "[t_state]")
standing.icon = belt.icon_override
else if(belt.sprite_sheets && belt.sprite_sheets[species.name])
overlays_standing[BELT_LAYER] = image("icon" = belt.sprite_sheets[species.name], "icon_state" = "[t_state]")
standing.icon = belt.sprite_sheets[species.name]
else
overlays_standing[BELT_LAYER] = image("icon" = 'icons/mob/belt.dmi', "icon_state" = "[t_state]")
standing.icon = 'icons/mob/belt.dmi'
if(belt.contents.len && istype(belt, /obj/item/weapon/storage/belt))
for(var/obj/item/i in belt.contents)
var/i_state = i.item_state
if(!i_state) i_state = i.icon_state
standing.overlays += image("icon" = 'icons/mob/belt.dmi', "icon_state" = "[i_state]")
overlays_standing[BELT_LAYER] = standing
else
overlays_standing[BELT_LAYER] = null
if(update_icons) update_icons()
@@ -921,6 +924,16 @@ proc/get_damage_icon_part(damage_state, body_part)
if(update_icons) update_icons()
/mob/living/carbon/human/proc/update_surgery(var/update_icons=1)
overlays_standing[SURGERY_LEVEL] = null
var/image/total = new
for(var/datum/organ/external/E in organs)
if(E.open)
var/image/I = image("icon"='icons/mob/surgery.dmi', "icon_state"="[E.name][round(E.open)]", "layer"=-SURGERY_LEVEL)
total.overlays += I
overlays_standing[SURGERY_LEVEL] = total
if(update_icons) update_icons()
// Used mostly for creating head items
/mob/living/carbon/human/proc/generate_head_icon()
//gender no longer matters for the mouth, although there should probably be seperate base head icons.
@@ -959,6 +972,7 @@ proc/get_damage_icon_part(damage_state, body_part)
//Human Overlays Indexes/////////
#undef MUTATIONS_LAYER
#undef DAMAGE_LAYER
#undef SURGERY_LEVEL
#undef UNIFORM_LAYER
#undef TAIL_LAYER
#undef ID_LAYER

View File

@@ -171,7 +171,6 @@
// ++++ROCKDTBEN++++ MOB PROCS //END
/mob/proc/get_contents()
@@ -514,7 +513,7 @@
return
//resisting grabs (as if it helps anyone...)
if ((!( L.stat ) && L.canmove && !( L.restrained() )))
if ((!( L.stat ) && !( L.restrained() )))
var/resisting = 0
for(var/obj/O in L.requests)
L.requests.Remove(O)
@@ -522,23 +521,20 @@
resisting++
for(var/obj/item/weapon/grab/G in usr.grabbed_by)
resisting++
if (G.state == 1)
del(G)
else
if (G.state == 2)
if (prob(25))
for(var/mob/O in viewers(L, null))
O.show_message(text("\red [] has broken free of []'s grip!", L, G.assailant), 1)
switch(G.state)
if(GRAB_PASSIVE)
del(G)
if(GRAB_AGGRESSIVE)
if(prob(60)) //same chance of breaking the grab as disarm
L.visible_message("<span class='warning'>[L] has broken free of [G.assailant]'s grip!</span>")
del(G)
if(GRAB_NECK)
//If the you move when grabbing someone then it's easier for them to break free. Same if the affected mob is immune to stun.
if (((world.time - G.assailant.l_move_time < 20 || !L.stunned) && prob(15)) || prob(3))
L.visible_message("<span class='warning'>[L] has broken free of [G.assailant]'s headlock!</span>")
del(G)
else
if (G.state == 3)
if (prob(5))
for(var/mob/O in viewers(usr, null))
O.show_message(text("\red [] has broken free of []'s headlock!", L, G.assailant), 1)
del(G)
if(resisting)
for(var/mob/O in viewers(usr, null))
O.show_message(text("\red <B>[] resists!</B>", L), 1)
L.visible_message("<span class='danger'>[L] resists!</span>")
//unbuckling yourself

View File

@@ -63,10 +63,10 @@
return
//Armor
var/absorb = run_armor_check(def_zone, P.flag)
var/absorb = run_armor_check(def_zone, P.check_armour)
var/proj_sharp = is_sharp(P)
var/proj_edge = has_edge(P)
if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.flag)))
if ((proj_sharp || proj_edge) && prob(getarmor(def_zone, P.check_armour)))
proj_sharp = 0
proj_edge = 0
@@ -103,16 +103,13 @@
/mob/living/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR)//Standardization and logging -Sieve
if(istype(AM,/obj/))
var/obj/O = AM
var/dtype = BRUTE
if(istype(O,/obj/item/weapon))
var/obj/item/weapon/W = O
dtype = W.damtype
var/dtype = O.damtype
var/throw_damage = O.throwforce*(speed/THROWFORCE_SPEED_DIVISOR)
var/miss_chance = 15
if (O.throw_source)
var/distance = get_dist(O.throw_source, loc)
miss_chance = min(15*(distance-2), 0)
miss_chance = max(15*(distance-2), 0)
if (prob(miss_chance))
visible_message("\blue \The [O] misses [src] narrowly!")
@@ -136,20 +133,23 @@
msg_admin_attack("[src.name] ([src.ckey]) was hit by a [O], thrown by [M.name] ([assailant.ckey]) (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[src.x];Y=[src.y];Z=[src.z]'>JMP</a>)")
// Begin BS12 momentum-transfer code.
if(O.throw_source && speed >= THROWNOBJ_KNOCKBACK_SPEED)
var/obj/item/weapon/W = O
var/momentum = speed/THROWNOBJ_KNOCKBACK_DIVISOR
var/mass = 1.5
if(istype(O, /obj/item))
var/obj/item/I = O
mass = I.w_class/THROWNOBJ_KNOCKBACK_DIVISOR
var/momentum = speed*mass
if(O.throw_source && momentum >= THROWNOBJ_KNOCKBACK_SPEED)
var/dir = get_dir(O.throw_source, src)
visible_message("\red [src] staggers under the impact!","\red You stagger under the impact!")
src.throw_at(get_edge_target_turf(src,dir),1,momentum)
if(!W || !src) return
if(!O || !src) return
if(W.sharp) //Projectile is suitable for pinning.
if(O.sharp) //Projectile is suitable for pinning.
//Handles embedding for non-humans and simple_animals.
O.loc = src
src.embedded += O
embed(O)
var/turf/T = near_wall(dir,2)
@@ -158,7 +158,11 @@
visible_message("<span class='warning'>[src] is pinned to the wall by [O]!</span>","<span class='warning'>You are pinned to the wall by [O]!</span>")
src.anchored = 1
src.pinned += O
src.verbs += /mob/proc/yank_out_object
/mob/living/proc/embed(var/obj/O, var/def_zone=null)
O.loc = src
src.embedded += O
src.verbs += /mob/proc/yank_out_object
//This is called when the mob is thrown into a dense turf
/mob/living/proc/turf_collision(var/turf/T, var/speed)

View File

@@ -16,8 +16,8 @@
if(stat == DEAD || paralysis || weakened || stunned || restrained())
return
if (layer != TURF_LAYER+0.2)
layer = TURF_LAYER+0.2
if (layer != 2.45)
layer = 2.45 //Just above cables with their 2.44
src << text("\blue You are now hiding.")
else
layer = MOB_LAYER

View File

@@ -23,7 +23,10 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/sensor_mode,
/mob/living/silicon/ai/proc/show_laws_verb,
/mob/living/silicon/ai/proc/toggle_acceleration,
/mob/living/silicon/ai/proc/toggle_camera_light
/mob/living/silicon/ai/proc/toggle_camera_light,
/mob/living/silicon/ai/proc/nano_rcon,
/mob/living/silicon/ai/proc/nano_crew_monitor,
/mob/living/silicon/ai/proc/nano_power_monitor
)
//Not sure why this is necessary...
@@ -163,6 +166,8 @@ var/list/ai_verbs_default = list(
hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank")
init_subsystems()
ai_list += src
..()
return
@@ -367,7 +372,7 @@ var/list/ai_verbs_default = list(
if(message_cooldown)
src << "Please allow one minute to pass between announcements."
return
var/input = stripped_input(usr, "Please write a message to announce to the station crew.", "A.I. Announcement")
var/input = input(usr, "Please write a message to announce to the station crew.", "A.I. Announcement")
if(!input)
return

View File

@@ -49,7 +49,7 @@
ai.client.eye = src
//Holopad
if(ai.holo)
ai.holo.move_hologram()
ai.holo.move_hologram(ai)
/mob/aiEye/proc/getLoc()

View File

@@ -0,0 +1,27 @@
var/obj/nano_module/crew_monitor/crew_monitor
var/obj/nano_module/rcon/rcon
var/obj/nano_module/power_monitor/power_monitor
/mob/living/silicon/ai/proc/init_subsystems()
crew_monitor = new(src)
rcon = new(src)
power_monitor = new(src)
/mob/living/silicon/ai/proc/nano_crew_monitor()
set category = "AI Subystems"
set name = "Crew Monitor"
crew_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/nano_power_monitor()
set category = "AI Subystems"
set name = "Power Monitor"
power_monitor.ui_interact(usr)
/mob/living/silicon/ai/proc/nano_rcon()
set category = "AI Subystems"
set name = "RCON"
rcon.ui_interact(usr)

View File

@@ -16,14 +16,6 @@
integrated_light_power = 2
local_transmit = 1
// We need to keep track of a few module items so we don't need to do list operations
// every time we need them. These get set in New() after the module is chosen.
var/obj/item/stack/sheet/metal/cyborg/stack_metal = null
var/obj/item/stack/sheet/wood/cyborg/stack_wood = null
var/obj/item/stack/sheet/glass/cyborg/stack_glass = null
var/obj/item/stack/sheet/mineral/plastic/cyborg/stack_plastic = null
var/obj/item/weapon/matter_decompiler/decompiler = null
//Used for self-mailing.
var/mail_destination = ""
@@ -56,15 +48,6 @@
verbs -= /mob/living/silicon/robot/verb/Namepick
module = new /obj/item/weapon/robot_module/drone(src)
//Grab stacks.
stack_metal = locate(/obj/item/stack/sheet/metal/cyborg) in src.module
stack_wood = locate(/obj/item/stack/sheet/wood/cyborg) in src.module
stack_glass = locate(/obj/item/stack/sheet/glass/cyborg) in src.module
stack_plastic = locate(/obj/item/stack/sheet/mineral/plastic/cyborg) in src.module
//Grab decompiler.
decompiler = locate(/obj/item/weapon/matter_decompiler) in src.module
//Some tidying-up.
flavor_text = "It's a tiny little repair drone. The casing is stamped with an NT logo and the subscript: 'NanoTrasen Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
updateicon()

View File

@@ -2,7 +2,7 @@
/mob/living/silicon/robot/drone/verb/set_mail_tag()
set name = "Set Mail Tag"
set desc = "Tag yourself for delivery through the disposals system."
set category = "Drone"
set category = "Robot Commands"
var/new_tag = input("Select the desired destination.", "Set Mail Tag", null) as null|anything in tagger_locations

View File

@@ -57,7 +57,7 @@
set name = "Drop Item"
set desc = "Release an item from your magnetic gripper."
set category = "Drone"
set category = "Robot Commands"
if(!wrapped)
//There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z
@@ -151,12 +151,10 @@
icon_state = "decompiler"
//Metal, glass, wood, plastic.
var/list/stored_comms = list(
"metal" = 0,
"glass" = 0,
"wood" = 0,
"plastic" = 0
)
var/datum/matter_synth/metal = null
var/datum/matter_synth/glass = null
var/datum/matter_synth/wood = null
var/datum/matter_synth/plastic = null
/obj/item/weapon/matter_decompiler/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
return
@@ -178,10 +176,10 @@
src.loc.visible_message("\red [src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.","\red It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
del(M)
stored_comms["wood"]++
stored_comms["wood"]++
stored_comms["plastic"]++
stored_comms["plastic"]++
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
return
else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
@@ -203,61 +201,66 @@
del(M)
new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
stored_comms["metal"] += 15
stored_comms["glass"] += 15
stored_comms["wood"] += 5
stored_comms["plastic"] += 5
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/item/weapon/cigbutt))
stored_comms["plastic"]++
if(istype(W,/obj/item/weapon/cigbutt))
if(plastic)
plastic.add_charge(500)
else if(istype(W,/obj/effect/spider/spiderling))
stored_comms["wood"]++
stored_comms["wood"]++
stored_comms["plastic"]++
stored_comms["plastic"]++
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
else if(istype(W,/obj/item/weapon/light))
var/obj/item/weapon/light/L = W
if(L.status >= 2) //In before someone changes the inexplicably local defines. ~ Z
stored_comms["metal"]++
stored_comms["glass"]++
if(metal)
metal.add_charge(250)
if(glass)
glass.add_charge(250)
else
continue
else if(istype(W,/obj/effect/decal/remains/robot))
stored_comms["metal"]++
stored_comms["metal"]++
stored_comms["plastic"]++
stored_comms["plastic"]++
stored_comms["glass"]++
if(metal)
metal.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
if(glass)
glass.add_charge(1000)
else if(istype(W,/obj/item/trash))
stored_comms["metal"]++
stored_comms["plastic"]++
stored_comms["plastic"]++
stored_comms["plastic"]++
if(metal)
metal.add_charge(1000)
if(plastic)
plastic.add_charge(3000)
else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot))
stored_comms["metal"]++
stored_comms["metal"]++
stored_comms["glass"]++
stored_comms["glass"]++
if(metal)
metal.add_charge(2000)
if(glass)
glass.add_charge(2000)
else if(istype(W,/obj/item/ammo_casing))
stored_comms["metal"]++
if(metal)
metal.add_charge(1000)
else if(istype(W,/obj/item/weapon/shard/shrapnel))
stored_comms["metal"]++
stored_comms["metal"]++
stored_comms["metal"]++
if(metal)
metal.add_charge(1000)
else if(istype(W,/obj/item/weapon/shard))
stored_comms["glass"]++
stored_comms["glass"]++
stored_comms["glass"]++
if(glass)
glass.add_charge(1000)
else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/grown))
stored_comms["wood"]++
stored_comms["wood"]++
stored_comms["wood"]++
stored_comms["wood"]++
if(wood)
wood.add_charge(4000)
else if(istype(W,/obj/item/pipe))
// This allows drones and engiborgs to clear pipe assemblies from floors.
else
@@ -325,39 +328,3 @@
dat += resources
src << browse(dat, "window=robotmod")
//Putting the decompiler here to avoid doing list checks every tick.
/mob/living/silicon/robot/drone/use_power()
..()
if(!src.has_power || !decompiler)
return
//The decompiler replenishes drone stores from hoovered-up junk each tick.
for(var/type in decompiler.stored_comms)
if(decompiler.stored_comms[type] > 0)
var/obj/item/stack/sheet/stack
switch(type)
if("metal")
if(!stack_metal)
stack_metal = new /obj/item/stack/sheet/metal/cyborg(src.module)
stack_metal.amount = 1
stack = stack_metal
if("glass")
if(!stack_glass)
stack_glass = new /obj/item/stack/sheet/glass/cyborg(src.module)
stack_glass.amount = 1
stack = stack_glass
if("wood")
if(!stack_wood)
stack_wood = new /obj/item/stack/sheet/wood/cyborg(src.module)
stack_wood.amount = 1
stack = stack_wood
if("plastic")
if(!stack_plastic)
stack_plastic = new /obj/item/stack/sheet/mineral/plastic/cyborg(src.module)
stack_plastic.amount = 1
stack = stack_plastic
stack.amount++
decompiler.stored_comms[type]--;

View File

@@ -579,6 +579,9 @@ var/list/robot_verbs_default = list(
show_cell_power()
show_jetpack_pressure()
stat(null, text("Lights: [lights_on ? "ON" : "OFF"]"))
if(module)
for(var/datum/matter_synth/ms in module.synths)
stat("[ms.name]: [ms.energy]/[ms.max_energy]")
/mob/living/silicon/robot/restrained()
return 0

View File

@@ -7,9 +7,9 @@
flags = CONDUCT
var/channels = list()
var/list/modules = list()
var/list/datum/matter_synth/synths = list()
var/obj/item/emag = null
var/obj/item/borg/upgrade/jetpack = null
var/list/stacktypes
/obj/item/weapon/robot_module/emp_act(severity)
if(modules)
@@ -17,40 +17,19 @@
O.emp_act(severity)
if(emag)
emag.emp_act(severity)
if(synths)
for(var/datum/matter_synth/S in synths)
S.emp_act(severity)
..()
return
/obj/item/weapon/robot_module/New()
..()
// Build initial inventory.
if(stacktypes && stacktypes.len)
for(var/stack_type in stacktypes)
var/obj/item/stack/new_stack = new stack_type (src)
new_stack.amount = stacktypes[stack_type]
modules |= new_stack
/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R, var/rate)
/obj/item/weapon/robot_module/proc/respawn_consumable(var/mob/living/silicon/robot/R)
if(!synths || !synths.len)
return
if(!stacktypes || !stacktypes.len) return
for(var/T in stacktypes)
var/obj/item/stack/S
for(var/obj/O in src.modules)
if(O.type == T)
S = O
break
if(!S)
src.modules -= null
S = new T(src)
src.modules |= S
S.amount = 1
if(!istype(S))
continue
if(S && S.amount < stacktypes[T])
S.amount++
for(var/datum/matter_synth/T in synths)
T.add_charge(T.recharge_rate * rate)
/obj/item/weapon/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module
var/list/temp_list = modules
@@ -84,10 +63,6 @@
/obj/item/weapon/robot_module/surgeon
name = "surgeon robot module"
stacktypes = list(
/obj/item/stack/medical/advanced/bruise_pack = 5,
/obj/item/stack/nanopaste = 5
)
/obj/item/weapon/robot_module/surgeon/New()
..()
@@ -104,26 +79,34 @@
src.modules += new /obj/item/weapon/circular_saw(src)
src.modules += new /obj/item/weapon/surgicaldrill(src)
src.modules += new /obj/item/weapon/extinguisher/mini(src)
src.modules += new /obj/item/stack/medical/advanced/bruise_pack(src)
src.modules += new /obj/item/stack/nanopaste(src)
src.emag = new /obj/item/weapon/reagent_containers/spray(src)
src.emag.reagents.add_reagent("pacid", 250)
src.emag.name = "Polyacid spray"
var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(10000)
synths += medicine
var/obj/item/stack/nanopaste/N = new /obj/item/stack/nanopaste(src)
var/obj/item/stack/medical/advanced/bruise_pack/B = new /obj/item/stack/medical/advanced/bruise_pack(src)
N.uses_charge = 1
N.charge_costs = list(1000)
N.synths = list(medicine)
B.uses_charge = 1
B.charge_costs = list(1000)
B.synths = list(medicine)
src.modules += N
src.modules += B
return
/obj/item/weapon/robot_module/surgeon/respawn_consumable(var/mob/living/silicon/robot/R)
/obj/item/weapon/robot_module/surgeon/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
if(src.emag)
var/obj/item/weapon/reagent_containers/spray/PS = src.emag
PS.reagents.add_reagent("pacid", 2)
PS.reagents.add_reagent("pacid", 2 * amount)
..()
/obj/item/weapon/robot_module/crisis
name = "crisis robot module"
stacktypes = list(
/obj/item/stack/medical/ointment = 5,
/obj/item/stack/medical/bruise_pack = 5,
/obj/item/stack/medical/splint = 5
)
/obj/item/weapon/robot_module/crisis/New()
..()
@@ -132,9 +115,6 @@
src.modules += new /obj/item/device/healthanalyzer(src)
src.modules += new /obj/item/device/reagent_scanner/adv(src)
src.modules += new /obj/item/roller_holder(src)
src.modules += new /obj/item/stack/medical/ointment(src)
src.modules += new /obj/item/stack/medical/bruise_pack(src)
src.modules += new /obj/item/stack/medical/splint(src)
src.modules += new /obj/item/weapon/reagent_containers/borghypo/crisis(src)
src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
src.modules += new /obj/item/weapon/reagent_containers/robodropper(src)
@@ -143,9 +123,29 @@
src.emag = new /obj/item/weapon/reagent_containers/spray(src)
src.emag.reagents.add_reagent("pacid", 250)
src.emag.name = "Polyacid spray"
var/datum/matter_synth/medicine = new /datum/matter_synth/medicine(15000)
synths += medicine
var/obj/item/stack/medical/ointment/O = new /obj/item/stack/medical/ointment(src)
var/obj/item/stack/medical/bruise_pack/B = new /obj/item/stack/medical/bruise_pack(src)
var/obj/item/stack/medical/splint/S = new /obj/item/stack/medical/splint(src)
O.uses_charge = 1
O.charge_costs = list(1000)
O.synths = list(medicine)
B.uses_charge = 1
B.charge_costs = list(1000)
B.synths = list(medicine)
S.uses_charge = 1
S.charge_costs = list(1000)
S.synths = list(medicine)
src.modules += O
src.modules += B
src.modules += S
return
/obj/item/weapon/robot_module/crisis/respawn_consumable(var/mob/living/silicon/robot/R)
/obj/item/weapon/robot_module/crisis/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/weapon/reagent_containers/syringe/S = locate() in src.modules
if(S.mode == 2)
@@ -156,20 +156,13 @@
if(src.emag)
var/obj/item/weapon/reagent_containers/spray/PS = src.emag
PS.reagents.add_reagent("pacid", 2)
PS.reagents.add_reagent("pacid", 2 * amount)
..()
/obj/item/weapon/robot_module/construction
name = "construction robot module"
stacktypes = list(
/obj/item/stack/sheet/metal = 50,
/obj/item/stack/sheet/plasteel = 10,
/obj/item/stack/sheet/glass/reinforced = 50,
/obj/item/stack/rods = 50
)
/obj/item/weapon/robot_module/construction/New()
..()
src.modules += new /obj/item/device/flash(src)
@@ -182,18 +175,32 @@
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
src.modules += new /obj/item/device/pipe_painter(src)
var/datum/matter_synth/metal = new /datum/matter_synth/metal()
var/datum/matter_synth/plasteel = new /datum/matter_synth/plasteel()
var/datum/matter_synth/glass = new /datum/matter_synth/glass()
synths += metal
synths += plasteel
synths += glass
var/obj/item/stack/sheet/metal/cyborg/M = new /obj/item/stack/sheet/metal/cyborg(src)
M.synths = list(metal)
src.modules += M
var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src)
R.synths = list(metal)
src.modules += R
var/obj/item/stack/sheet/plasteel/cyborg/S = new /obj/item/stack/sheet/plasteel/cyborg(src)
S.synths = list(metal)
src.modules += S
var/obj/item/stack/sheet/glass/reinforced/cyborg/RG = new /obj/item/stack/sheet/glass/reinforced/cyborg(src)
RG.synths = list(metal, glass)
src.modules += R
/obj/item/weapon/robot_module/engineering
name = "engineering robot module"
stacktypes = list(
/obj/item/stack/sheet/metal = 50,
/obj/item/stack/sheet/glass = 50,
/obj/item/stack/sheet/glass/reinforced = 50,
/obj/item/stack/cable_coil/robot = 50,
/obj/item/stack/rods = 15,
/obj/item/stack/tile/plasteel = 15
)
/obj/item/weapon/robot_module/engineering/New()
..()
src.modules += new /obj/item/device/flash(src)
@@ -209,9 +216,45 @@
src.modules += new /obj/item/device/analyzer(src)
src.modules += new /obj/item/taperoll/engineering(src)
src.modules += new /obj/item/weapon/gripper(src)
src.modules += new /obj/item/weapon/matter_decompiler(src)
src.modules += new /obj/item/device/pipe_painter(src)
src.emag = new /obj/item/borg/stun(src)
var/datum/matter_synth/metal = new /datum/matter_synth/metal(40000)
var/datum/matter_synth/glass = new /datum/matter_synth/glass(40000)
var/datum/matter_synth/wire = new /datum/matter_synth/wire()
synths += metal
synths += glass
synths += wire
var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src)
MD.metal = metal
MD.glass = glass
src.modules += MD
var/obj/item/stack/sheet/metal/cyborg/M = new /obj/item/stack/sheet/metal/cyborg(src)
M.synths = list(metal)
src.modules += M
var/obj/item/stack/sheet/glass/cyborg/G = new /obj/item/stack/sheet/glass/cyborg(src)
G.synths = list(glass)
src.modules += G
var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src)
R.synths = list(metal)
src.modules += R
var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src)
C.synths = list(wire)
src.modules += C
var/obj/item/stack/tile/plasteel/cyborg/S = new /obj/item/stack/tile/plasteel/cyborg(src)
S.synths = list(metal)
src.modules += S
var/obj/item/stack/sheet/glass/reinforced/cyborg/RG = new /obj/item/stack/sheet/glass/reinforced/cyborg(src)
RG.synths = list(metal, glass)
src.modules += RG
return
/obj/item/weapon/robot_module/security
@@ -223,12 +266,12 @@
src.modules += new /obj/item/borg/sight/hud/sec(src)
src.modules += new /obj/item/weapon/handcuffs/cyborg(src)
src.modules += new /obj/item/weapon/melee/baton/robot(src)
src.modules += new /obj/item/weapon/gun/energy/taser/cyborg(src)
src.modules += new /obj/item/weapon/gun/energy/taser/mounted/cyborg(src)
src.modules += new /obj/item/taperoll/police(src)
src.emag = new /obj/item/weapon/gun/energy/laser/cyborg(src)
src.emag = new /obj/item/weapon/gun/energy/laser/mounted(src)
return
/obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R)
/obj/item/weapon/robot_module/security/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/device/flash/F = locate() in src.modules
if(F.broken)
F.broken = 0
@@ -236,9 +279,9 @@
F.icon_state = "flash"
else if(F.times_used)
F.times_used--
var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in src.modules
var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in src.modules
if(T.power_supply.charge < T.power_supply.maxcharge)
T.power_supply.give(T.charge_cost)
T.power_supply.give(T.charge_cost * amount)
T.update_icon()
else
T.charge_tick = 0
@@ -258,12 +301,12 @@
src.emag.name = "Lube spray"
return
/obj/item/weapon/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/R)
/obj/item/weapon/robot_module/janitor/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/device/lightreplacer/LR = locate() in src.modules
LR.Charge(R)
LR.Charge(R, amount)
if(src.emag)
var/obj/item/weapon/reagent_containers/spray/S = src.emag
S.reagents.add_reagent("lube", 2)
S.reagents.add_reagent("lube", 2 * amount)
/obj/item/weapon/robot_module/butler
name = "service robot module"
@@ -327,12 +370,12 @@
R.add_language("Tradeband", 1)
R.add_language("Gutter", 1)
/obj/item/weapon/robot_module/butler/respawn_consumable(var/mob/living/silicon/robot/R)
/obj/item/weapon/robot_module/butler/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/weapon/reagent_containers/food/condiment/enzyme/E = locate() in src.modules
E.reagents.add_reagent("enzyme", 2)
E.reagents.add_reagent("enzyme", 2 * amount)
if(src.emag)
var/obj/item/weapon/reagent_containers/food/drinks/cans/beer/B = src.emag
B.reagents.add_reagent("beer2", 2)
B.reagents.add_reagent("beer2", 2 * amount)
/obj/item/weapon/robot_module/miner
name = "miner robot module"
@@ -383,26 +426,15 @@
..()
src.modules += new /obj/item/device/flash(src)
src.modules += new /obj/item/borg/sight/thermal(src)
src.modules += new /obj/item/weapon/gun/energy/laser/cyborg(src)
src.modules += new /obj/item/weapon/gun/energy/laser/mounted(src)
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
src.modules += new /obj/item/borg/combat/shield(src)
src.modules += new /obj/item/borg/combat/mobility(src)
src.emag = new /obj/item/weapon/gun/energy/lasercannon/cyborg(src)
src.emag = new /obj/item/weapon/gun/energy/lasercannon/mounted(src)
return
/obj/item/weapon/robot_module/drone
name = "drone module"
stacktypes = list(
/obj/item/stack/sheet/wood = 1,
/obj/item/stack/sheet/mineral/plastic = 1,
/obj/item/stack/sheet/glass/reinforced = 5,
/obj/item/stack/tile/wood = 5,
/obj/item/stack/rods = 15,
/obj/item/stack/tile/plasteel = 15,
/obj/item/stack/sheet/metal = 20,
/obj/item/stack/sheet/glass = 20,
/obj/item/stack/cable_coil/robot = 30
)
/obj/item/weapon/robot_module/drone/New()
..()
@@ -414,20 +446,73 @@
src.modules += new /obj/item/device/multitool(src)
src.modules += new /obj/item/device/lightreplacer(src)
src.modules += new /obj/item/weapon/gripper(src)
src.modules += new /obj/item/weapon/matter_decompiler(src)
src.modules += new /obj/item/weapon/reagent_containers/spray/cleaner/drone(src)
src.emag = new /obj/item/weapon/pickaxe/plasmacutter(src)
src.emag.name = "Plasma Cutter"
var/datum/matter_synth/metal = new /datum/matter_synth/metal(25000)
var/datum/matter_synth/glass = new /datum/matter_synth/glass(25000)
var/datum/matter_synth/wood = new /datum/matter_synth/wood(2000)
var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(1000)
var/datum/matter_synth/wire = new /datum/matter_synth/wire(30)
synths += metal
synths += glass
synths += wood
synths += plastic
synths += wire
var/obj/item/weapon/matter_decompiler/MD = new /obj/item/weapon/matter_decompiler(src)
MD.metal = metal
MD.glass = glass
MD.wood = wood
MD.plastic = plastic
src.modules += MD
var/obj/item/stack/sheet/metal/cyborg/M = new /obj/item/stack/sheet/metal/cyborg(src)
M.synths = list(metal)
src.modules += M
var/obj/item/stack/sheet/glass/cyborg/G = new /obj/item/stack/sheet/glass/cyborg(src)
G.synths = list(glass)
src.modules += G
var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src)
R.synths = list(metal)
src.modules += R
var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src)
C.synths = list(wire)
src.modules += C
var/obj/item/stack/tile/plasteel/cyborg/S = new /obj/item/stack/tile/plasteel/cyborg(src)
S.synths = list(metal)
src.modules += S
var/obj/item/stack/sheet/glass/reinforced/cyborg/RG = new /obj/item/stack/sheet/glass/reinforced/cyborg(src)
RG.synths = list(metal, glass)
src.modules += RG
var/obj/item/stack/tile/wood/cyborg/WT = new /obj/item/stack/tile/wood/cyborg(src)
WT.synths = list(wood)
src.modules += WT
var/obj/item/stack/sheet/wood/cyborg/W = new /obj/item/stack/sheet/wood/cyborg(src)
W.synths = list(wood)
src.modules += W
var/obj/item/stack/sheet/mineral/plastic/cyborg/P = new /obj/item/stack/sheet/mineral/plastic/cyborg(src)
P.synths = list(plastic)
src.modules += P
/obj/item/weapon/robot_module/drone/add_languages(var/mob/living/silicon/robot/R)
return //not much ROM to spare in that tiny microprocessor!
/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R)
/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/weapon/reagent_containers/spray/cleaner/C = locate() in src.modules
C.reagents.add_reagent("cleaner", 3)
C.reagents.add_reagent("cleaner", 3 * amount)
var/obj/item/device/lightreplacer/LR = locate() in src.modules
LR.Charge(R)
LR.Charge(R, amount)
..()
return

View File

@@ -108,7 +108,7 @@
usr << "There's no mounting point for the module!"
return 0
var/obj/item/weapon/gun/energy/taser/cyborg/T = locate() in R.module
var/obj/item/weapon/gun/energy/taser/mounted/cyborg/T = locate() in R.module
if(!T)
T = locate() in R.module.contents
if(!T)

View File

@@ -159,7 +159,7 @@
return
var/obj/machinery/hologram/holopad/T = src.holo
if(T && T.hologram && T.master == src)//If there is a hologram and its master is the user.
if(T && T.masters[src])//If there is a hologram and its master is the user.
//Human-like, sorta, heard by those who understand humans.
var/rendered_a
@@ -198,7 +198,7 @@
return
var/obj/machinery/hologram/holopad/T = src.holo
if(T && T.hologram && T.master == src)
if(T && T.masters[src])
var/rendered = "<span class='game say'><span class='name'>[name]</span> <span class='message'>[message]</span></span>"
src << "<i><span class='game say'>Holopad action relayed, <span class='name'>[real_name]</span> <span class='message'>[message]</span></span></i>"
@@ -211,7 +211,7 @@
/mob/living/silicon/ai/emote(var/act, var/type, var/message)
var/obj/machinery/hologram/holopad/T = src.holo
if(T && T.hologram && T.master == src) //Is the AI using a holopad?
if(T && T.masters[src]) //Is the AI using a holopad?
src.holopad_emote(message)
else //Emote normally, then.
..()

View File

@@ -38,7 +38,7 @@
icon_state = "russianranged"
icon_living = "russianranged"
corpse = /obj/effect/landmark/mobcorpse/russian/ranged
weapon1 = /obj/item/weapon/gun/projectile/mateba
weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba
ranged = 1
projectiletype = /obj/item/projectile/bullet
projectilesound = 'sound/weapons/Gunshot.ogg'

View File

@@ -183,7 +183,7 @@ var/list/slot_equipment_priority = list( \
if(!istype(W)) return 0
for(var/slot in slot_equipment_priority)
if(equip_to_slot_if_possible(W, slot, 0, 1, 1)) //del_on_fail = 0; disable_warning = 0; redraw_mob = 1
if(equip_to_slot_if_possible(W, slot, del_on_fail=0, disable_warning=1, redraw_mob=1))
return 1
return 0
@@ -837,6 +837,7 @@ note dizziness decrements automatically in the mob's Life() proc.
// facing verbs
/mob/proc/canface()
if(!canmove) return 0
@@ -868,7 +869,7 @@ note dizziness decrements automatically in the mob's Life() proc.
else if( stat || weakened || paralysis || resting || sleeping || (status_flags & FAKEDEATH))
lying = 1
canmove = 0
else if( stunned )
else if(stunned)
canmove = 0
else if(captured)
anchored = 1
@@ -885,6 +886,11 @@ note dizziness decrements automatically in the mob's Life() proc.
else
density = 1
for(var/obj/item/weapon/grab/G in grabbed_by)
if(G.state >= GRAB_AGGRESSIVE)
canmove = 0
break
//Temporarily moved here from the various life() procs
//I'm fixing stuff incrementally so this will likely find a better home.
//It just makes sense for now. ~Carn

View File

@@ -121,7 +121,7 @@
var/m_int = null//Living
var/m_intent = "run"//Living
var/lastKnownIP = null
var/obj/structure/stool/bed/buckled = null//Living
var/obj/structure/bed/buckled = null//Living
var/obj/item/l_hand = null//Living
var/obj/item/r_hand = null//Living
var/obj/item/weapon/back = null//Human/Monkey
@@ -223,3 +223,5 @@
var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
var/list/active_genes=list()

View File

@@ -35,6 +35,10 @@
hud.name = "reinforce grab"
hud.master = src
/obj/item/weapon/grab/Del()
//make sure the grabbed_by list doesn't fill up with nulls
if(affecting) affecting.grabbed_by -= src
..()
//Used by throw code to hand over the mob, instead of throwing the grab. The grab is then deleted by the throw code.
/obj/item/weapon/grab/proc/throw()
@@ -67,6 +71,7 @@
if(state <= GRAB_AGGRESSIVE)
allow_upgrade = 1
//disallow upgrading if we're grabbing more than one person
if((assailant.l_hand && assailant.l_hand != src && istype(assailant.l_hand, /obj/item/weapon/grab)))
var/obj/item/weapon/grab/G = assailant.l_hand
if(G.affecting != affecting)
@@ -76,31 +81,29 @@
if(G.affecting != affecting)
allow_upgrade = 0
if(state == GRAB_AGGRESSIVE)
var/h = affecting.hand
affecting.hand = 0
affecting.drop_item()
affecting.hand = 1
affecting.drop_item()
affecting.hand = h
affecting.drop_l_hand()
affecting.drop_r_hand()
//disallow upgrading past aggressive if we're being grabbed aggressively
for(var/obj/item/weapon/grab/G in affecting.grabbed_by)
if(G == src) continue
if(G.state == GRAB_AGGRESSIVE)
if(G.state >= GRAB_AGGRESSIVE)
allow_upgrade = 0
if(allow_upgrade)
hud.icon_state = "reinforce"
else
hud.icon_state = "!reinforce"
else
if(!affecting.buckled)
affecting.loc = assailant.loc
else if(!affecting.buckled)
affecting.loc = assailant.loc
if(state >= GRAB_NECK)
affecting.Stun(5) //It will hamper your voice, being choked and all.
affecting.Stun(1)
if(isliving(affecting))
var/mob/living/L = affecting
L.adjustOxyLoss(1)
if(state >= GRAB_KILL)
//affecting.apply_effect(STUTTER, 5) //would do this, but affecting isn't declared as mob/living for some stupid reason.
affecting.stuttering = max(affecting.stuttering, 5) //It will hamper your voice, being choked and all.
affecting.Weaken(5) //Should keep you down unless you get help.
affecting.losebreath = min(affecting.losebreath + 2, 3)
@@ -126,48 +129,46 @@
assailant.visible_message("<span class='warning'>[assailant] has grabbed [affecting] aggressively (now hands)!</span>")
state = GRAB_AGGRESSIVE
icon_state = "grabbed1"
else
if(state < GRAB_NECK)
if(isslime(affecting))
assailant << "<span class='notice'>You squeeze [affecting], but nothing interesting happens.</span>"
else if(state < GRAB_NECK)
if(isslime(affecting))
assailant << "<span class='notice'>You squeeze [affecting], but nothing interesting happens.</span>"
return
assailant.visible_message("<span class='warning'>[assailant] has reinforced \his grip on [affecting] (now neck)!</span>")
state = GRAB_NECK
icon_state = "grabbed+1"
if(!affecting.buckled)
affecting.loc = assailant.loc
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their neck grabbed by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Grabbed the neck of [affecting.name] ([affecting.ckey])</font>"
msg_admin_attack("[key_name(assailant)] grabbed the neck of [key_name(affecting)]")
hud.icon_state = "disarm/kill"
hud.name = "disarm/kill"
else if(state < GRAB_UPGRADING)
assailant.visible_message("<span class='danger'>[assailant] starts to tighten \his grip on [affecting]'s neck!</span>")
hud.icon_state = "disarm/kill1"
state = GRAB_UPGRADING
if(do_after(assailant, UPGRADE_KILL_TIMER))
if(state == GRAB_KILL)
return
if(!affecting)
del(src)
return
if(!assailant.canmove || assailant.lying)
del(src)
return
state = GRAB_KILL
assailant.visible_message("<span class='danger'>[assailant] has tightened \his grip on [affecting]'s neck!</span>")
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has been strangled (kill intent) by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Strangled (kill intent) [affecting.name] ([affecting.ckey])</font>"
msg_admin_attack("[key_name(assailant)] strangled (kill intent) [key_name(affecting)]")
assailant.visible_message("<span class='warning'>[assailant] has reinforced \his grip on [affecting] (now neck)!</span>")
state = GRAB_NECK
icon_state = "grabbed+1"
if(!affecting.buckled)
affecting.loc = assailant.loc
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their neck grabbed by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Grabbed the neck of [affecting.name] ([affecting.ckey])</font>"
msg_admin_attack("[key_name(assailant)] grabbed the neck of [key_name(affecting)]")
hud.icon_state = "disarm/kill"
hud.name = "disarm/kill"
assailant.next_move = world.time + 10
affecting.losebreath += 1
else
if(state < GRAB_UPGRADING)
assailant.visible_message("<span class='danger'>[assailant] starts to tighten \his grip on [affecting]'s neck!</span>")
hud.icon_state = "disarm/kill1"
state = GRAB_UPGRADING
if(do_after(assailant, UPGRADE_KILL_TIMER))
if(state == GRAB_KILL)
return
if(!affecting)
del(src)
return
if(!assailant.canmove || assailant.lying)
del(src)
return
state = GRAB_KILL
assailant.visible_message("<span class='danger'>[assailant] has tightened \his grip on [affecting]'s neck!</span>")
affecting.attack_log += "\[[time_stamp()]\] <font color='orange'>Has been strangled (kill intent) by [assailant.name] ([assailant.ckey])</font>"
assailant.attack_log += "\[[time_stamp()]\] <font color='red'>Strangled (kill intent) [affecting.name] ([affecting.ckey])</font>"
msg_admin_attack("[key_name(assailant)] strangled (kill intent) [key_name(affecting)]")
assailant.next_move = world.time + 10
affecting.losebreath += 1
else
assailant.visible_message("<span class='warning'>[assailant] was unable to tighten \his grip on [affecting]'s neck!</span>")
hud.icon_state = "disarm/kill"
state = GRAB_NECK
assailant.visible_message("<span class='warning'>[assailant] was unable to tighten \his grip on [affecting]'s neck!</span>")
hud.icon_state = "disarm/kill"
state = GRAB_NECK
//This is used to make sure the victim hasn't managed to yackety sax away before using the grab.

View File

@@ -80,6 +80,18 @@
return 1
return 0
/mob/proc/isSilicon()
return 0
/mob/living/silicon/isSilicon()
return 1
/mob/proc/isAI()
return 0
/mob/living/silicon/ai/isAI()
return 1
/proc/ispAI(A)
if(istype(A, /mob/living/silicon/pai))
return 1

View File

@@ -284,9 +284,9 @@
if(mob.pulledby || mob.buckled) // Wheelchair driving!
if(istype(mob.loc, /turf/space))
return // No wheelchair driving in space
if(istype(mob.pulledby, /obj/structure/stool/bed/chair/wheelchair))
if(istype(mob.pulledby, /obj/structure/bed/chair/wheelchair))
return mob.pulledby.relaymove(mob, direct)
else if(istype(mob.buckled, /obj/structure/stool/bed/chair/wheelchair))
else if(istype(mob.buckled, /obj/structure/bed/chair/wheelchair))
if(ishuman(mob.buckled))
var/mob/living/carbon/human/driver = mob.buckled
var/datum/organ/external/l_hand = driver.get_organ("l_hand")
@@ -351,30 +351,13 @@
///Process_Grab()
///Called by client/Move()
///Checks to see if you are being grabbed and if so attemps to break it
///Checks to see if you are grabbing anything and if moving will affect your grab.
/client/proc/Process_Grab()
if(locate(/obj/item/weapon/grab, locate(/obj/item/weapon/grab, mob.grabbed_by.len)))
var/list/grabbing = list()
if(istype(mob.l_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = mob.l_hand
grabbing += G.affecting
if(istype(mob.r_hand, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = mob.r_hand
grabbing += G.affecting
for(var/obj/item/weapon/grab/G in mob.grabbed_by)
if((G.state == 1)&&(!grabbing.Find(G.assailant))) del(G)
if(G.state == 2)
move_delay = world.time + 10
if(!prob(25)) return 1
mob.visible_message("\red [mob] has broken free of [G.assailant]'s grip!")
del(G)
if(G.state == 3)
move_delay = world.time + 10
if(!prob(5)) return 1
mob.visible_message("\red [mob] has broken free of [G.assailant]'s headlock!")
del(G)
return 0
for(var/obj/item/weapon/grab/G in list(mob.l_hand, mob.r_hand))
if(G.state == GRAB_KILL) //no wandering across the station/asteroid while choking someone
mob.visible_message("<span class='warning'>[mob] lost \his tight grip on [G.affecting]'s neck!</span>")
G.hud.icon_state = "disarm/kill"
G.state = GRAB_NECK
///Process_Incorpmove
///Called by client/Move()

View File

@@ -352,7 +352,7 @@
character.lastarea = get_area(loc)
// Moving wheelchair if they have one
if(character.buckled && istype(character.buckled, /obj/structure/stool/bed/chair/wheelchair))
if(character.buckled && istype(character.buckled, /obj/structure/bed/chair/wheelchair))
character.buckled.loc = character.loc
character.buckled.set_dir(character.dir)

View File

@@ -240,12 +240,12 @@ datum/preferences
eyes_s.Blend(facial_s, ICON_OVERLAY)
var/icon/underwear_s = null
if(underwear > 0 && underwear < 7 && current_species.flags & HAS_UNDERWEAR)
underwear_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = "underwear[underwear]_[g]_s")
if(underwear && current_species.flags & HAS_UNDERWEAR)
underwear_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = underwear)
var/icon/undershirt_s = null
if(undershirt > 0 && undershirt < 5 && current_species.flags & HAS_UNDERWEAR)
undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = "undershirt[undershirt]_s")
if(undershirt && current_species.flags & HAS_UNDERWEAR)
undershirt_s = new/icon("icon" = 'icons/mob/human.dmi', "icon_state" = undershirt)
var/icon/clothes_s = null
if(job_civilian_low & ASSISTANT)//This gives the preview icon clothes depending on which job(if any) is set to 'high'

View File

@@ -0,0 +1,88 @@
/obj/nano_module/crew_monitor
name = "Crew monitor"
var/list/tracked = new
/obj/nano_module/crew_monitor/Topic(href, href_list)
if(..()) return
var/turf/T = get_turf(src)
if (!T || !(T.z in config.player_levels))
usr << "<span class='warning'>Unable to establish a connection<span>: You're too far away from the station!"
return 0
if(href_list["close"] )
var/mob/user = usr
var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
usr.unset_machine()
ui.close()
return 0
if(href_list["update"])
src.updateDialog()
return 1
/obj/nano_module/crew_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
user.set_machine(src)
src.scan()
var/data[0]
var/turf/T = get_turf(src)
var/list/crewmembers = list()
for(var/obj/item/clothing/under/C in src.tracked)
var/turf/pos = get_turf(C)
if((C) && (C.has_sensor) && (pos) && (T && pos.z == T.z) && (C.sensor_mode != SUIT_SENSOR_OFF))
if(istype(C.loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = C.loc
if(H.w_uniform != C)
continue
var/list/crewmemberData = list("dead"=0, "oxy"=-1, "tox"=-1, "fire"=-1, "brute"=-1, "area"="", "x"=-1, "y"=-1)
crewmemberData["sensor_type"] = C.sensor_mode
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
crewmemberData["dead"] = H.stat > 1
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
crewmemberData["brute"] = round(H.getBruteLoss(), 1)
if(C.sensor_mode >= SUIT_SENSOR_TRACKING)
var/area/A = get_area(H)
crewmemberData["area"] = sanitize(A.name)
crewmemberData["x"] = pos.x
crewmemberData["y"] = pos.y
crewmembers[++crewmembers.len] = crewmemberData
crewmembers = sortByKey(crewmembers, "name")
data["crewmembers"] = crewmembers
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "crew_monitor.tmpl", "Crew Monitoring Computer", 900, 800)
// adding a template with the key "mapContent" enables the map ui functionality
ui.add_template("mapContent", "crew_monitor_map_content.tmpl")
// adding a template with the key "mapHeader" replaces the map header content
ui.add_template("mapHeader", "crew_monitor_map_header.tmpl")
ui.set_initial_data(data)
ui.open()
// should make the UI auto-update; doesn't seem to?
ui.set_auto_update(1)
/obj/nano_module/crew_monitor/proc/scan()
for(var/mob/living/carbon/human/H in mob_list)
if(istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/C = H.w_uniform
if (C.has_sensor)
tracked |= C
return 1

View File

@@ -0,0 +1,58 @@
/obj/nano_module/power_monitor
name = "Power monitor"
var/list/grid_sensors
var/active_sensor = null //name_tag of the currently selected sensor
/obj/nano_module/power_monitor/New()
..()
refresh_sensors()
/obj/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/list/data = list()
var/list/sensors = list()
// Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading.
var/obj/machinery/power/sensor/focus = null
// Build list of data from sensor readings.
for(var/obj/machinery/power/sensor/S in grid_sensors)
sensors.Add(list(list(
"name" = S.name_tag,
"alarm" = S.check_grid_warning()
)))
if(S.name_tag == active_sensor)
focus = S
data["all_sensors"] = sensors
if(focus)
data["focus"] = focus.return_reading_data()
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
// Proc: refresh_sensors()
// Parameters: None
// Description: Refreshes list of active sensors kept on this computer.
/obj/nano_module/power_monitor/proc/refresh_sensors()
grid_sensors = list()
var/turf/T = get_turf(src)
for(var/obj/machinery/power/sensor/S in machines)
if((T && S.loc.z == T.z) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels.
if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
else
grid_sensors += S
// Proc: Topic()
// Parameters: 2 (href, href_list - allows us to process UI clicks)
// Description: Allows us to process UI clicks, which are relayed in form of hrefs.
/obj/nano_module/power_monitor/Topic(href, href_list)
if(..())
return
if( href_list["clear"] )
active_sensor = null
else if( href_list["setsensor"] )
active_sensor = href_list["setsensor"]

View File

@@ -0,0 +1,116 @@
/obj/nano_module/rcon
name = "RCON interface"
var/list/known_SMESs = null
var/list/known_breakers = null
// Allows you to hide specific parts of the UI
var/hide_SMES = 0
var/hide_SMES_details = 0
var/hide_breakers = 0
/obj/nano_module/rcon/ui_interact(mob/user, ui_key = "rcon", datum/nanoui/ui=null, force_open=1)
FindDevices() // Update our devices list
var/data[0]
// SMES DATA (simplified view)
var/list/smeslist[0]
for(var/obj/machinery/power/smes/buildable/SMES in known_SMESs)
smeslist.Add(list(list(
"charge" = round(SMES.Percentage()),
"input_set" = SMES.input_attempt,
"input_val" = round(SMES.input_level),
"output_set" = SMES.output_attempt,
"output_val" = round(SMES.output_level),
"output_load" = round(SMES.output_used),
"RCON_tag" = SMES.RCon_tag
)))
data["smes_info"] = sortByKey(smeslist, "RCON_tag")
// BREAKER DATA (simplified view)
var/list/breakerlist[0]
for(var/obj/machinery/power/breakerbox/BR in known_breakers)
breakerlist.Add(list(list(
"RCON_tag" = BR.RCon_tag,
"enabled" = BR.on
)))
data["breaker_info"] = breakerlist
data["hide_smes"] = hide_SMES
data["hide_smes_details"] = hide_SMES_details
data["hide_breakers"] = hide_breakers
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "rcon.tmpl", "RCON Console", 600, 400)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
// Proc: Topic()
// Parameters: 2 (href, href_list - allows us to process UI clicks)
// Description: Allows us to process UI clicks, which are relayed in form of hrefs.
/obj/nano_module/rcon/Topic(href, href_list)
if(..())
return
if(href_list["smes_in_toggle"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_toggle"])
if(SMES)
SMES.toggle_input()
if(href_list["smes_out_toggle"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_toggle"])
if(SMES)
SMES.toggle_output()
if(href_list["smes_in_set"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_in_set"])
if(SMES)
var/inputset = input(usr, "Enter new input level (0-[SMES.input_level_max])", "SMES Input Power Control") as num
SMES.set_input(inputset)
if(href_list["smes_out_set"])
var/obj/machinery/power/smes/buildable/SMES = GetSMESByTag(href_list["smes_out_set"])
if(SMES)
var/outputset = input(usr, "Enter new output level (0-[SMES.output_level_max])", "SMES Input Power Control") as num
SMES.set_output(outputset)
if(href_list["toggle_breaker"])
var/obj/machinery/power/breakerbox/toggle = null
for(var/obj/machinery/power/breakerbox/breaker in known_breakers)
if(breaker.RCon_tag == href_list["toggle_breaker"])
toggle = breaker
if(toggle)
if(toggle.update_locked)
usr << "The breaker box was recently toggled. Please wait before toggling it again."
else
toggle.auto_toggle()
if(href_list["hide_smes"])
hide_SMES = !hide_SMES
if(href_list["hide_smes_details"])
hide_SMES_details = !hide_SMES_details
if(href_list["hide_breakers"])
hide_breakers = !hide_breakers
// Proc: GetSMESByTag()
// Parameters: 1 (tag - RCON tag of SMES we want to look up)
// Description: Looks up and returns SMES which has matching RCON tag
/obj/nano_module/rcon/proc/GetSMESByTag(var/tag)
if(!tag)
return
for(var/obj/machinery/power/smes/buildable/S in known_SMESs)
if(S.RCon_tag == tag)
return S
// Proc: FindDevices()
// Parameters: None
// Description: Refreshes local list of known devices.
/obj/nano_module/rcon/proc/FindDevices()
known_SMESs = new /list()
for(var/obj/machinery/power/smes/buildable/SMES in machines)
if(SMES.RCon_tag && (SMES.RCon_tag != "NO_TAG") && SMES.RCon)
known_SMESs.Add(SMES)
known_breakers = new /list()
for(var/obj/machinery/power/breakerbox/breaker in machines)
if(breaker.RCon_tag != "NO_TAG")
known_breakers.Add(breaker)

View File

@@ -1,5 +1,5 @@
// This file contains all Nano procs/definitions for external classes/objects
// This file contains all Nano procs/definitions for external classes/objects
/**
* Called when a Nano UI window is closed
* This is how Nano handles closed windows
@@ -15,7 +15,7 @@
if (istype(ui))
ui.close()
if(ui.ref)
var/href = "close=1"
src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's Topic() proc via client.Topic()
@@ -31,14 +31,14 @@
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
* @param force_open boolean Force the UI to (re)open, even if it's already open
*
* @return nothing
*/
/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/nano_ui/master_ui = null, var/datum/topic_state/custom_state = null)
return
// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
/mob/var/list/open_uis = list()

View File

@@ -0,0 +1,127 @@
/atom/movable/proc/nano_host()
return src
/obj/nano_module/nano_host()
return loc
/atom/movable/proc/CanUseTopic(var/mob/user, href_list, var/datum/topic_state/custom_state)
return user.can_use_topic(nano_host(), custom_state)
/mob/proc/can_use_topic(var/mob/user, var/datum/topic_state/custom_state)
return STATUS_CLOSE // By default no mob can do anything with NanoUI
/mob/dead/observer/can_use_topic()
if(check_rights(R_ADMIN, 0))
return STATUS_INTERACTIVE // Admins are more equal
return STATUS_UPDATE // Ghosts can view updates
/mob/living/silicon/pai/can_use_topic(var/src_object)
if(src_object == src && !stat)
return STATUS_INTERACTIVE
else
return ..()
/mob/living/silicon/robot/can_use_topic(var/src_object, var/datum/topic_state/custom_state)
if(stat || !client)
return STATUS_CLOSE
if(lockcharge || stunned || weakened)
return STATUS_DISABLED
// robots can interact with things they can see within their view range
if(!(custom_state.flags & NANO_IGNORE_DISTANCE) && (src_object in view(src)))
return STATUS_INTERACTIVE // interactive (green visibility)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
/mob/living/silicon/robot/syndicate/can_use_topic(var/src_object)
. = ..()
if(. != STATUS_INTERACTIVE)
return
if(z in config.admin_levels) // Syndicate borgs can interact with everything on the admin level
return STATUS_INTERACTIVE
if(istype(get_area(src), /area/syndicate_station)) // If elsewhere, they can interact with everything on the syndicate shuttle
return STATUS_INTERACTIVE
if(istype(src_object, /obj/machinery)) // Otherwise they can only interact with emagged machinery
var/obj/machinery/Machine = src_object
if(Machine.emagged)
return STATUS_INTERACTIVE
return STATUS_UPDATE
/mob/living/silicon/ai/can_use_topic(var/src_object)
if(!client || check_unable(1))
return STATUS_CLOSE
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in config.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))
return STATUS_INTERACTIVE
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
//apc_override is needed here because AIs use their own APC when powerless
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
return apc_override ? STATUS_INTERACTIVE : STATUS_CLOSE
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/proc/shared_living_nano_interaction(var/src_object)
if (src.stat != CONSCIOUS)
return STATUS_CLOSE // no updates, close the interface
else if (restrained() || lying || stat || stunned || weakened)
return STATUS_UPDATE // update only (orange visibility)
return STATUS_INTERACTIVE
//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI.
/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user)
return user.shared_living_nano_distance(src_object)
/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object)
if(!isturf(src_object.loc))
if(src_object.loc == src) // Item in the inventory
return STATUS_INTERACTIVE
if(src.contents.Find(src_object.loc)) // A hidden uplink inside an item
return STATUS_INTERACTIVE
if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates
return STATUS_CLOSE
var/dist = get_dist(src_object, src)
if (dist <= 1)
return STATUS_INTERACTIVE // interactive (green visibility)
else if (dist <= 2)
return STATUS_UPDATE // update only (orange visibility)
else if (dist <= 4)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
return STATUS_CLOSE
/mob/living/can_use_topic(var/src_object, var/datum/topic_state/custom_state)
. = shared_living_nano_interaction(src_object)
if(. == STATUS_INTERACTIVE && !(custom_state.flags & NANO_IGNORE_DISTANCE))
if(loc)
. = loc.contents_nano_distance(src_object, src)
else
. = shared_living_nano_distance(src_object)
if(STATUS_INTERACTIVE)
return STATUS_UPDATE
/mob/living/carbon/human/can_use_topic(var/src_object, var/datum/topic_state/custom_state)
. = shared_living_nano_interaction(src_object)
if(. == STATUS_INTERACTIVE && !(custom_state.flags & NANO_IGNORE_DISTANCE))
. = shared_living_nano_distance(src_object)
if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction.
return STATUS_INTERACTIVE
/var/global/datum/topic_state/default_state = new()
/datum/topic_state
var/flags = 0
/datum/topic_state/proc/href_list(var/mob/user)
return list()

View File

@@ -1,249 +1,250 @@
// This is the window/UI manager for Nano UI
// There should only ever be one (global) instance of nanomanger
/datum/nanomanager
// a list of current open /nanoui UIs, grouped by src_object and ui_key
var/open_uis[0]
// a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
/**
* Create a new nanomanager instance.
* This proc generates a list of assets which are to be sent to each client on connect
*
* @return /nanomanager new nanomanager object
*/
/datum/nanomanager/New()
var/list/nano_asset_dirs = list(\
"nano/css/",\
"nano/images/",\
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
*
* @param user /mob The mob who opened/owns the ui
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
* @param ui /datum/nanoui An existing instance of the ui (can be null)
* @param data list The data to be passed to the ui, if it exists
* @param force_open boolean The ui is being forced to (re)open, so close ui if it exists (instead of updating)
*
* @return /nanoui Returns the found ui, for null if none exists
*/
/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data, var/force_open = 0)
if (isnull(ui)) // no ui has been passed, so we'll search for one
{
ui = get_open_ui(user, src_object, ui_key)
}
if (!isnull(ui))
// The UI is already open
if (!force_open)
ui.push_data(data)
return ui
else
//testing("nanomanager/try_update_ui mob [user.name] [src_object:name] [ui_key] [force_open] - forcing opening of ui")
ui.close()
return null
/**
* Get an open /nanoui ui for the current user, src_object and ui_key
*
* @param user /mob The mob who opened/owns the ui
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
*
* @return /nanoui Returns the found ui, or null if none exists
*/
/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open")
return null
else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object")
return null
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if (ui.user == user)
return ui
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found")
return null
/**
* Update all /nanoui uis attached to src_object
*
* @param src_object /obj|/mob The obj or mob which the uis are attached to
*
* @return int The number of uis updated
*/
/datum/nanomanager/proc/update_uis(src_object)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0
var/update_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user)
ui.process(1)
update_count++
return update_count
/**
* Update /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
* @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional)
*
* @return int The number of uis updated
*/
/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
return 0 // has no open uis
var/update_count = 0
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.process(1)
update_count++
return update_count
/**
* Close /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
* @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional)
*
* @return int The number of uis closed
*/
/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/close_user_uis mob [user.name] has no open uis")
return 0 // has no open uis
var/close_count = 0
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.close()
close_count++
//testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis")
return close_count
/**
* Add a /nanoui ui to the list of open uis
* This is called by the /nanoui open() proc
*
* @param ui /nanoui The ui to add
*
* @return nothing
*/
/datum/nanomanager/proc/ui_opened(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
open_uis[src_object_key] = list(ui.ui_key = list())
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
open_uis[src_object_key][ui.ui_key] = list();
ui.user.open_uis.Add(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Add(ui)
processing_uis.Add(ui)
//testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
/**
* Remove a /nanoui ui from the list of open uis
* This is called by the /nanoui close() proc
*
* @param ui /nanoui The ui to remove
*
* @return int 0 if no ui was removed, 1 if removed successfully
*/
/datum/nanomanager/proc/ui_closed(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0 // wasn't open
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
return 0 // wasn't open
processing_uis.Remove(ui)
ui.user.open_uis.Remove(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Remove(ui)
//testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
return 1
/**
* This is called on user logout
* Closes/clears all uis attached to the user's /mob
*
* @param user /mob The user's mob
*
* @return nothing
*/
//
/datum/nanomanager/proc/user_logout(var/mob/user)
//testing("nanomanager/user_logout user [user.name]")
return close_user_uis(user)
/**
* This is called when a player transfers from one mob to another
* Transfers all open UIs to the new mob
*
* @param oldMob /mob The user's old mob
* @param newMob /mob The user's new mob
*
* @return nothing
*/
/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
//testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]")
if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/user_transferred mob [oldMob.name] has no open uis")
return 0 // has no open uis
if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list))
newMob.open_uis = list()
for (var/datum/nanoui/ui in oldMob.open_uis)
ui.user = newMob
newMob.open_uis.Add(ui)
oldMob.open_uis.Cut()
return 1 // success
/**
* Sends all nano assets to the client
* This is called on user login
*
* @param client /client The user's client
*
* @return nothing
*/
/datum/nanomanager/proc/send_resources(client)
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client
// This is the window/UI manager for Nano UI
// There should only ever be one (global) instance of nanomanger
/datum/nanomanager
// a list of current open /nanoui UIs, grouped by src_object and ui_key
var/open_uis[0]
// a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
/**
* Create a new nanomanager instance.
* This proc generates a list of assets which are to be sent to each client on connect
*
* @return /nanomanager new nanomanager object
*/
/datum/nanomanager/New()
var/list/nano_asset_dirs = list(\
"nano/css/",\
"nano/images/",\
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
*
* @param user /mob The mob who opened/owns the ui
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
* @param ui /datum/nanoui An existing instance of the ui (can be null)
* @param data list The data to be passed to the ui, if it exists
* @param force_open boolean The ui is being forced to (re)open, so close ui if it exists (instead of updating)
*
* @return /nanoui Returns the found ui, for null if none exists
*/
/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data, var/force_open = 0)
if (isnull(ui)) // no ui has been passed, so we'll search for one
{
ui = get_open_ui(user, src_object, ui_key)
}
if (!isnull(ui))
// The UI is already open
if (!force_open)
ui.push_data(data)
return ui
else
//testing("nanomanager/try_update_ui mob [user.name] [src_object:name] [ui_key] [force_open] - forcing opening of ui")
ui.close()
return null
/**
* Get an open /nanoui ui for the current user, src_object and ui_key
*
* @param user /mob The mob who opened/owns the ui
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
*
* @return /nanoui Returns the found ui, or null if none exists
*/
/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open")
return null
else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - there are no uis open for this object")
return null
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if (ui.user == user)
return ui
//testing("nanomanager/get_open_ui mob [user.name] [src_object:name] [ui_key] - ui not found")
return null
/**
* Update all /nanoui uis attached to src_object
*
* @param src_object /obj|/mob The obj or mob which the uis are attached to
*
* @return int The number of uis updated
*/
/datum/nanomanager/proc/update_uis(src_object)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0
var/update_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.nano_host())
ui.process(1)
update_count++
return update_count
/**
* Update /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
* @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional)
*
* @return int The number of uis updated
*/
/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
return 0 // has no open uis
var/update_count = 0
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.process(1)
update_count++
return update_count
/**
* Close /nanoui uis belonging to user
*
* @param user /mob The mob who owns the uis
* @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
* @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional)
*
* @return int The number of uis closed
*/
/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/close_user_uis mob [user.name] has no open uis")
return 0 // has no open uis
var/close_count = 0
for (var/datum/nanoui/ui in user.open_uis)
if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.close()
close_count++
//testing("nanomanager/close_user_uis mob [user.name] closed [open_uis.len] of [close_count] uis")
return close_count
/**
* Add a /nanoui ui to the list of open uis
* This is called by the /nanoui open() proc
*
* @param ui /nanoui The ui to add
*
* @return nothing
*/
/datum/nanomanager/proc/ui_opened(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
open_uis[src_object_key] = list(ui.ui_key = list())
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
open_uis[src_object_key][ui.ui_key] = list();
ui.user.open_uis.Add(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Add(ui)
processing_uis.Add(ui)
//testing("nanomanager/ui_opened mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
/**
* Remove a /nanoui ui from the list of open uis
* This is called by the /nanoui close() proc
*
* @param ui /nanoui The ui to remove
*
* @return int 0 if no ui was removed, 1 if removed successfully
*/
/datum/nanomanager/proc/ui_closed(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0 // wasn't open
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
return 0 // wasn't open
processing_uis.Remove(ui)
if(ui.user) // Sanity check in case a user has been deleted (say a blown up borg watching the alarm interface)
ui.user.open_uis.Remove(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Remove(ui)
//testing("nanomanager/ui_closed mob [ui.user.name] [ui.src_object:name] [ui.ui_key] - user.open_uis [ui.user.open_uis.len] | uis [uis.len] | processing_uis [processing_uis.len]")
return 1
/**
* This is called on user logout
* Closes/clears all uis attached to the user's /mob
*
* @param user /mob The user's mob
*
* @return nothing
*/
//
/datum/nanomanager/proc/user_logout(var/mob/user)
//testing("nanomanager/user_logout user [user.name]")
return close_user_uis(user)
/**
* This is called when a player transfers from one mob to another
* Transfers all open UIs to the new mob
*
* @param oldMob /mob The user's old mob
* @param newMob /mob The user's new mob
*
* @return nothing
*/
/datum/nanomanager/proc/user_transferred(var/mob/oldMob, var/mob/newMob)
//testing("nanomanager/user_transferred from mob [oldMob.name] to mob [newMob.name]")
if (isnull(oldMob.open_uis) || !istype(oldMob.open_uis, /list) || open_uis.len == 0)
//testing("nanomanager/user_transferred mob [oldMob.name] has no open uis")
return 0 // has no open uis
if (isnull(newMob.open_uis) || !istype(newMob.open_uis, /list))
newMob.open_uis = list()
for (var/datum/nanoui/ui in oldMob.open_uis)
ui.user = newMob
newMob.open_uis.Add(ui)
oldMob.open_uis.Cut()
return 1 // success
/**
* Sends all nano assets to the client
* This is called on user login
*
* @param client /client The user's client
*
* @return nothing
*/
/datum/nanomanager/proc/send_resources(client)
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client

View File

@@ -52,6 +52,11 @@ nanoui is used to open and update nano browser uis
// the current status/visibility of the ui
var/status = STATUS_INTERACTIVE
// Relationship between a master interface and its children. Used in update_status
var/datum/nanoui/master_ui
var/list/datum/nanoui/children = list()
var/datum/topic_state/custom_state = null
var/cached_data = null
/**
@@ -68,17 +73,22 @@ nanoui is used to open and update nano browser uis
*
* @return /nanoui new nanoui object
*/
/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate_filename, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null, var/datum/nanoui/master_ui = null, var/datum/topic_state/custom_state = null)
user = nuser
src_object = nsrc_object
ui_key = nui_key
window_id = "[ui_key]\ref[src_object]"
src.master_ui = master_ui
if(master_ui)
master_ui.children += src
src.custom_state = custom_state ? custom_state : new/datum/topic_state()
// add the passed template filename as the "main" template, this is required
add_template("main", ntemplate_filename)
if (ntitle)
title = ntitle
title = sanitize(ntitle)
if (nwidth)
width = nwidth
if (nheight)
@@ -132,116 +142,14 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/update_status(var/push_update = 0)
var/status = user.can_interact_with_interface(src_object)
if(status == STATUS_CLOSE)
var/atom/movable/host = src_object.nano_host()
var/new_status = host.CanUseTopic(user, list(), custom_state)
if(master_ui)
new_status = min(new_status, master_ui.status)
if(new_status == STATUS_CLOSE)
close()
else
set_status(status, push_update)
/*
Procs called by update_status()
*/
/mob/living/silicon/pai/can_interact_with_interface(src_object)
if(src_object == src && !stat)
return STATUS_INTERACTIVE
else
return ..()
/mob/proc/can_interact_with_interface(var/src_object)
return STATUS_CLOSE // By default no mob can do anything with NanoUI
/mob/dead/observer/can_interact_with_interface()
if(check_rights(R_ADMIN, 0))
return STATUS_INTERACTIVE // Admins are more equal
return STATUS_UPDATE // Ghosts can view updates
/mob/living/silicon/robot/can_interact_with_interface(var/src_object)
if(stat || !client)
return STATUS_CLOSE
if(lockcharge || stunned || weakened)
return STATUS_DISABLED
if (src_object in view(client.view, src)) // robots can see and interact with things they can see within their view range
return STATUS_INTERACTIVE // interactive (green visibility)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
/mob/living/silicon/robot/syndicate/can_interact_with_interface(var/src_object)
. = ..()
if(. != STATUS_INTERACTIVE)
return
if(z in config.admin_levels) // Syndicate borgs can interact with everything on the admin level
return STATUS_INTERACTIVE
if(istype(get_area(src), /area/syndicate_station)) // If elsewhere, they can interact with everything on the syndicate shuttle
return STATUS_INTERACTIVE
if(istype(src_object, /obj/machinery)) // Otherwise they can only interact with emagged machinery
var/obj/machinery/Machine = src_object
if(Machine.emagged)
return STATUS_INTERACTIVE
return STATUS_UPDATE
/mob/living/silicon/ai/can_interact_with_interface(var/src_object)
if(stat || !client)
return STATUS_CLOSE
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in config.player_levels)))
return STATUS_CLOSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))
return STATUS_INTERACTIVE
// If we're installed in a chassi, rather than transfered to an inteliCard or other container, then check if we have camera view
if(is_in_chassis())
//stop AIs from leaving windows open and using then after they lose vision
//apc_override is needed here because AIs use their own APC when powerless
if(cameranet && !cameranet.checkTurfVis(get_turf(src_object)))
return apc_override ? STATUS_INTERACTIVE : STATUS_CLOSE
return STATUS_INTERACTIVE
return STATUS_CLOSE
/mob/living/proc/shared_living_nano_interaction(var/src_object)
if (src.stat != CONSCIOUS)
return STATUS_CLOSE // no updates, close the interface
else if (restrained() || lying || stat || stunned || weakened)
return STATUS_UPDATE // update only (orange visibility)
return STATUS_INTERACTIVE
/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object)
if(!isturf(src_object.loc))
if(src_object.loc == src) // Item in the inventory
return STATUS_INTERACTIVE
if(src.contents.Find(src_object.loc)) // A hidden uplink inside an item
return STATUS_INTERACTIVE
if (!(src_object in view(4, src))) // If the src object is not in visable, disable updates
return STATUS_CLOSE
var/dist = get_dist(src_object, src)
if (dist <= 1)
return STATUS_INTERACTIVE // interactive (green visibility)
else if (dist <= 2)
return STATUS_UPDATE // update only (orange visibility)
else if (dist <= 4)
return STATUS_DISABLED // no updates, completely disabled (red visibility)
return STATUS_CLOSE
/mob/living/can_interact_with_interface(var/src_object, var/be_close = 1)
. = shared_living_nano_interaction(src_object)
if(. == STATUS_INTERACTIVE && be_close)
. = shared_living_nano_distance(src_object)
if(STATUS_INTERACTIVE)
return STATUS_UPDATE
/mob/living/carbon/human/can_interact_with_interface(var/src_object, var/be_close = 1)
. = shared_living_nano_interaction(src_object)
if(. == STATUS_INTERACTIVE && be_close)
. = shared_living_nano_distance(src_object)
if(. == STATUS_UPDATE && (TK in mutations)) // If we have telekinesis and remain close enough, allow interaction.
return STATUS_INTERACTIVE
set_status(new_status, push_update)
/**
* Set the ui to auto update (every master_controller tick)
@@ -484,7 +392,6 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/open()
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
@@ -504,6 +411,8 @@ nanoui is used to open and update nano browser uis
is_auto_updating = 0
nanomanager.ui_closed(src)
user << browse(null, "window=[window_id]")
for(var/datum/nanoui/child in children)
child.close()
/**
* Set the UI window to call the nanoclose verb when the window is closed
@@ -568,7 +477,7 @@ nanoui is used to open and update nano browser uis
set_map_z_level(text2num(href_list["mapZLevel"]))
map_update = 1
if ((src_object && src_object.Topic(href, href_list)) || map_update)
if ((src_object && src_object.Topic(href, href_list, 0, custom_state)) || map_update)
nanomanager.update_uis(src_object) // update all UIs attached to src_object
/**
@@ -595,5 +504,4 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/update(var/force_open = 0)
src_object.ui_interact(user, ui_key, src, force_open)
src_object.ui_interact(user, ui_key, src, force_open, master_ui, custom_state)

View File

@@ -112,7 +112,7 @@
stance_damage = 0
// Buckled to a bed/chair. Stance damage is forced to 0 since they're sitting on something solid
if (istype(buckled, /obj/structure/stool/bed))
if (istype(buckled, /obj/structure/bed))
return
for (var/organ in list("l_leg","l_foot","r_leg","r_foot"))

View File

@@ -159,7 +159,7 @@
//If limb took enough damage, try to cut or tear it off
if(body_part != UPPER_TORSO && body_part != LOWER_TORSO) //as hilarious as it is, getting hit on the chest too much shouldn't effectively gib you.
if(config.limbs_can_break && brute_dam >= max_damage * config.organ_health_multiplier)
if( (edge && prob(5 * brute)) || (brute > 20 && prob(2 * brute)) )
if( (edge && prob(5 * brute)) || (brute > 20 && prob(brute)) )
droplimb(1)
return
@@ -596,14 +596,11 @@ Note that amputating the affected organ does in fact remove the infection from t
update_damages()
var/obj/organ //Dropped limb object
var/list/dropped_items
switch(body_part)
if(HEAD)
organ= new /obj/item/weapon/organ/head(owner.loc, owner)
owner.u_equip(owner.glasses)
owner.u_equip(owner.head)
owner.u_equip(owner.l_ear)
owner.u_equip(owner.r_ear)
owner.u_equip(owner.wear_mask)
organ = new /obj/item/weapon/organ/head(owner.loc, owner)
dropped_items = list(owner.glasses, owner.head, owner.l_ear, owner.r_ear, owner.wear_mask)
if(ARM_RIGHT)
if(status & ORGAN_ROBOT)
organ = new /obj/item/robot_parts/r_arm(owner.loc)
@@ -627,19 +624,22 @@ Note that amputating the affected organ does in fact remove the infection from t
if(HAND_RIGHT)
if(!(status & ORGAN_ROBOT))
organ= new /obj/item/weapon/organ/r_hand(owner.loc, owner)
owner.u_equip(owner.gloves)
dropped_items = list(owner.gloves) //should probably make it so that you can still wear gloves if you have one hand
if(HAND_LEFT)
if(!(status & ORGAN_ROBOT))
organ= new /obj/item/weapon/organ/l_hand(owner.loc, owner)
owner.u_equip(owner.gloves)
dropped_items = list(owner.gloves)
if(FOOT_RIGHT)
if(!(status & ORGAN_ROBOT))
organ= new /obj/item/weapon/organ/r_foot/(owner.loc, owner)
owner.u_equip(owner.shoes)
dropped_items = list(owner.shoes)
if(FOOT_LEFT)
if(!(status & ORGAN_ROBOT))
organ = new /obj/item/weapon/organ/l_foot(owner.loc, owner)
owner.u_equip(owner.shoes)
dropped_items = list(owner.shoes)
if(dropped_items)
for(var/obj/O in dropped_items)
owner.remove_from_mob(O)
destspawn = 1
//Robotic limbs explode if sabotaged.

View File

@@ -86,7 +86,7 @@ var/global/photo_count = 0
icon = 'icons/obj/items.dmi'
icon_state = "album"
item_state = "briefcase"
can_hold = list("/obj/item/weapon/photo",)
can_hold = list(/obj/item/weapon/photo)
/obj/item/weapon/storage/photo_album/MouseDrop(obj/over_object as obj)

View File

@@ -127,7 +127,7 @@
/obj/machinery/power/am_control_unit/bullet_act(var/obj/item/projectile/Proj)
if(Proj.flag != "bullet")
if(Proj.check_armour != "bullet")
stability -= Proj.force
return 0

View File

@@ -117,7 +117,7 @@ proc/cardinalrange(var/center)
/obj/machinery/am_shielding/bullet_act(var/obj/item/projectile/Proj)
if(Proj.flag != "bullet")
if(Proj.check_armour != "bullet")
stability -= Proj.force/2
return 0

View File

@@ -482,8 +482,17 @@ obj/structure/cable/proc/cableColor(var/colorC)
item_state = "coil"
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
/obj/item/stack/cable_coil/cyborg
name = "cable coil synthesizer"
desc = "A device that makes cable."
gender = NEUTER
matter = null
uses_charge = 1
charge_costs = list(1)
stacktype = /obj/item/stack/cable_coil
/obj/item/stack/cable_coil/suicide_act(mob/user)
if(locate(/obj/structure/stool) in user.loc)
if(locate(/obj/item/weapon/stool) in user.loc)
user.visible_message("<span class='suicide'>[user] is making a noose with the [src.name]! It looks like \he's trying to commit suicide.</span>")
else
user.visible_message("<span class='suicide'>[user] is strangling \himself with the [src.name]! It looks like \he's trying to commit suicide.</span>")
@@ -576,7 +585,7 @@ obj/structure/cable/proc/cableColor(var/colorC)
usr << "\blue You cannot do that."
..()
/obj/item/stack/cable_coil/robot/verb/set_colour()
/obj/item/stack/cable_coil/cyborg/verb/set_colour()
set name = "Change Colour"
set category = "Object"
@@ -606,26 +615,26 @@ obj/structure/cable/proc/cableColor(var/colorC)
// - Cable coil : merge cables
/obj/item/stack/cable_coil/attackby(obj/item/weapon/W, mob/user)
..()
if( istype(W, /obj/item/weapon/wirecutters) && src.amount > 1)
src.amount--
if( istype(W, /obj/item/weapon/wirecutters) && src.get_amount() > 1)
src.use(1)
new/obj/item/stack/cable_coil(user.loc, 1,color)
user << "You cut a piece off the cable coil."
src.update_icon()
return
else if(istype(W, /obj/item/stack/cable_coil))
var/obj/item/stack/cable_coil/C = W
if(C.amount >= MAXCOIL)
if(C.get_amount() >= get_max_amount())
user << "The coil is too long, you cannot add any more cable to it."
return
if( (C.amount + src.amount <= MAXCOIL) )
if( (C.get_amount() + src.get_amount() <= get_max_amount()) )
user << "You join the cable coils together."
C.give(src.amount) // give it cable
src.use(src.amount) // make sure this one cleans up right
C.give(src.get_amount()) // give it cable
src.use(src.get_amount()) // make sure this one cleans up right
return
else
var/amt = MAXCOIL - C.amount
var/amt = get_max_amount() - C.get_amount()
user << "You transfer [amt] length\s of cable from one coil to the other."
C.give(amt)
src.use(amt)

View File

@@ -128,7 +128,7 @@
rigged = 1 //broken batterys are dangerous
/obj/item/weapon/cell/emp_act(severity)
charge -= 1000 / severity
charge -= maxcharge / severity
if (charge < 0)
charge = 0
if(reliability != 100 && prob(50/severity))

View File

@@ -1,4 +1,3 @@
/obj/machinery/power/generator
name = "thermoelectric generator"
desc = "It's a high efficiency thermoelectric generator."
@@ -9,15 +8,24 @@
use_power = 1
idle_power_usage = 100 //Watts, I hope. Just enough to do the computer and display things.
var/max_power = 500000
var/thermal_efficiency = 0.65
var/obj/machinery/atmospherics/binary/circulator/circ1
var/obj/machinery/atmospherics/binary/circulator/circ2
var/lastgen = 0
var/lastgenlev = -1
var/last_circ1_gen = 0
var/last_circ2_gen = 0
var/last_thermal_gen = 0
var/stored_energy = 0
var/lastgen1 = 0
var/lastgen2 = 0
var/effective_gen = 0
var/lastgenlev = 0
/obj/machinery/power/generator/New()
..()
desc = initial(desc) + " Rated for [round(max_power/1000)] kW."
spawn(1)
reconnect()
@@ -31,11 +39,11 @@
circ2 = null
if(src.loc && anchored)
if(src.dir & (EAST|WEST))
circ1 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,EAST)
circ2 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,WEST)
circ1 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,WEST)
circ2 = locate(/obj/machinery/atmospherics/binary/circulator) in get_step(src,EAST)
if(circ1 && circ2)
if(circ1.dir != SOUTH || circ2.dir != NORTH)
if(circ1.dir != NORTH || circ2.dir != SOUTH)
circ1 = null
circ2 = null
@@ -58,13 +66,19 @@
/obj/machinery/power/generator/process()
if(!circ1 || !circ2 || !anchored || stat & (BROKEN|NOPOWER))
stored_energy = 0
return
updateDialog()
var/datum/gas_mixture/air1 = circ1.return_transfer_air()
var/datum/gas_mixture/air2 = circ2.return_transfer_air()
lastgen = 0
lastgen2 = lastgen1
lastgen1 = 0
last_thermal_gen = 0
last_circ1_gen = 0
last_circ2_gen = 0
if(air1 && air2)
var/air1_heat_capacity = air1.heat_capacity()
@@ -72,10 +86,9 @@
var/delta_temperature = abs(air2.temperature - air1.temperature)
if(delta_temperature > 0 && air1_heat_capacity > 0 && air2_heat_capacity > 0)
var/efficiency = 0.65
var/energy_transfer = delta_temperature*air2_heat_capacity*air1_heat_capacity/(air2_heat_capacity+air1_heat_capacity)
var/heat = energy_transfer*(1-efficiency)
lastgen = energy_transfer*efficiency*0.05
var/heat = energy_transfer*(1-thermal_efficiency)
last_thermal_gen = energy_transfer*thermal_efficiency
if(air2.temperature > air1.temperature)
air2.temperature = air2.temperature - energy_transfer/air2_heat_capacity
@@ -96,19 +109,29 @@
if(circ2.network2)
circ2.network2.update = 1
// update icon overlays and power usage only if displayed level has changed
if(lastgen > 250000 && prob(10))
//Exceeding maximum power leads to some power loss
if(effective_gen > max_power && prob(5))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
lastgen *= 0.5
var/genlev = max(0, min( round(11*lastgen / 250000), 11))
if(lastgen > 100 && genlev == 0)
stored_energy *= 0.5
//Power
last_circ1_gen = circ1.return_stored_energy()
last_circ2_gen = circ2.return_stored_energy()
stored_energy += last_thermal_gen + last_circ1_gen + last_circ2_gen
lastgen1 = stored_energy*0.4 //smoothened power generation to prevent slingshotting as pressure is equalized, then restored by pumps
stored_energy -= lastgen1
effective_gen = (lastgen1 + lastgen2) / 2
// update icon overlays and power usage only if displayed level has changed
var/genlev = max(0, min( round(11*effective_gen / max_power), 11))
if(effective_gen > 100 && genlev == 0)
genlev = 1
if(genlev != lastgenlev)
lastgenlev = genlev
updateicon()
add_avail(lastgen)
add_avail(effective_gen)
/obj/machinery/power/generator/attack_ai(mob/user)
if(stat & (BROKEN|NOPOWER)) return
@@ -116,8 +139,11 @@
/obj/machinery/power/generator/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/wrench))
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
anchored = !anchored
user << "\blue You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor."
user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \
"You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \
"You hear a ratchet")
use_power = anchored
reconnect()
else
@@ -137,20 +163,33 @@
user.set_machine(src)
var/t = "<PRE><B>Thermo-Electric Generator</B><HR>"
var/t = "<PRE><B>Thermoelectric Generator</B><HR>"
t += "Total Output: [round(effective_gen/1000)] kW<HR>"
t += "Thermal Output: [round(last_thermal_gen/1000)] kW<BR>"
t += " <BR>"
var/vertical = 0
if (dir == NORTH || dir == SOUTH)
vertical = 1
if(circ1 && circ2)
t += "Output : [round(lastgen)] W<BR><BR>"
t += "<B>Primary Circulator (top or right)</B><BR>"
t += "<B>Primary Circulator ([vertical ? "top" : "left"])</B><BR>"
t += "Turbine Output: [round(last_circ1_gen/1000)] kW<BR>"
t += "Flow Capacity: [round(circ1.volume_capacity_used*100)]%<BR>"
t += " <BR>"
t += "Inlet Pressure: [round(circ1.air1.return_pressure(), 0.1)] kPa<BR>"
t += "Inlet Temperature: [round(circ1.air1.temperature, 0.1)] K<BR>"
t += " <BR>"
t += "Outlet Pressure: [round(circ1.air2.return_pressure(), 0.1)] kPa<BR>"
t += "Outlet Temperature: [round(circ1.air2.temperature, 0.1)] K<BR>"
t += "<B>Secondary Circulator (bottom or left)</B><BR>"
t += " <BR>"
t += "<B>Secondary Circulator ([vertical ? "bottom" : "right"])</B><BR>"
t += "Turbine Output: [round(last_circ2_gen/1000)] kW<BR>"
t += "Flow Capacity: [round(circ2.volume_capacity_used*100)]%<BR>"
t += " <BR>"
t += "Inlet Pressure: [round(circ2.air1.return_pressure(), 0.1)] kPa<BR>"
t += "Inlet Temperature: [round(circ2.air1.temperature, 0.1)] K<BR>"
t += " <BR>"
t += "Outlet Pressure: [round(circ2.air2.return_pressure(), 0.1)] kPa<BR>"
t += "Outlet Temperature: [round(circ2.air2.temperature, 0.1)] K<BR>"
@@ -158,11 +197,11 @@
t += "Unable to connect to circulators.<br>"
t += "Ensure both are in position and wrenched into place."
t += "<BR>"
t += " <BR>"
t += "<HR>"
t += "<A href='?src=\ref[src]'>Refresh</A> <A href='?src=\ref[src];close=1'>Close</A>"
user << browse(t, "window=teg;size=460x300")
user << browse(t, "window=teg;size=400x500")
onclose(user, "teg")
return 1
@@ -201,4 +240,4 @@
if (usr.stat || usr.restrained() || anchored)
return
src.set_dir(turn(src.dir, -90))
src.set_dir(turn(src.dir, -90))

View File

@@ -42,7 +42,7 @@
name = "collector [mysize] OFF"
/obj/effect/rust_particle_catcher/bullet_act(var/obj/item/projectile/Proj)
if(Proj.flag != "bullet" && parent)
if(Proj.check_armour != "bullet" && parent)
parent.AddEnergy(Proj.damage * 20, 0, 1)
update_icon()
return 0

View File

@@ -16,12 +16,11 @@
density = 1
anchored = 1.0
circuit = /obj/item/weapon/circuitboard/powermonitor
var/list/grid_sensors
var/alerting = 0
var/active_sensor = null //name_tag of the currently selected sensor
use_power = 1
idle_power_usage = 300
active_power_usage = 300
var/obj/nano_module/power_monitor/power_monitor
// Proc: process()
// Parameters: None
@@ -53,19 +52,7 @@
/obj/machinery/computer/power_monitor/New()
..()
spawn(50)
refresh_sensors()
// Proc: refresh_sensors()
// Parameters: None
// Description: Refreshes list of active sensors kept on this computer.
/obj/machinery/computer/power_monitor/proc/refresh_sensors()
grid_sensors = list()
for(var/obj/machinery/power/sensor/S in machines)
if((S.loc.z == src.loc.z) || (S.long_range)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels.
if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
else
grid_sensors += S
power_monitor = new(src)
// Proc: attack_hand()
// Parameters: None
@@ -77,50 +64,18 @@
return
ui_interact(user)
// Proc: Topic()
// Parameters: 2 (href, href_list - allows us to process UI clicks)
// Description: Allows us to process UI clicks, which are relayed in form of hrefs.
/obj/machinery/computer/power_monitor/Topic(href, href_list)
..()
if( href_list["clear"] )
active_sensor = null
else if( href_list["setsensor"] )
active_sensor = href_list["setsensor"]
// Proc: ui_interact()
// Parameters: 4 (standard NanoUI parameters)
// Description: Uses dark magic to operate the NanoUI of this computer.
/obj/machinery/computer/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
power_monitor.ui_interact(user, ui_key, ui, force_open)
// Proc: check_warnings()
// Parameters: None
// Description: Verifies if any warnings were registered by connected sensors.
/obj/machinery/computer/power_monitor/proc/check_warnings()
for(var/obj/machinery/power/sensor/S in grid_sensors)
for(var/obj/machinery/power/sensor/S in power_monitor.grid_sensors)
if(S.check_grid_warning())
return 1
return 0
// Proc: ui_interact()
// Parameters: 4 (standard NanoUI parameters)
// Description: Uses dark magic to operate the NanoUI of this computer.
/obj/machinery/computer/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/list/data = list()
var/list/sensors = list()
// Focus: If it remains null if no sensor is selected and UI will display sensor list, otherwise it will display sensor reading.
var/obj/machinery/power/sensor/focus = null
// Build list of data from sensor readings.
for(var/obj/machinery/power/sensor/S in grid_sensors)
sensors.Add(list(list(
"name" = S.name_tag,
"alarm" = S.check_grid_warning()
)))
if(S.name_tag == active_sensor)
focus = S
data["all_sensors"] = sensors
if(focus)
data["focus"] = focus.return_reading_data()
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 500)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)

View File

@@ -318,14 +318,14 @@
// Parameters: None
// Description: Switches the input on/off depending on previous setting
/obj/machinery/power/smes/buildable/proc/toggle_input()
input_attempt = !input_attempt
inputting(!input_attempt)
update_icon()
// Proc: toggle_output()
// Parameters: None
// Description: Switches the output on/off depending on previous setting
/obj/machinery/power/smes/buildable/proc/toggle_output()
output_attempt = !output_attempt
outputting(!output_attempt)
update_icon()
// Proc: set_input()

View File

@@ -6,73 +6,159 @@
flags = CONDUCT
slot_flags = SLOT_BELT
throwforce = 1
w_class = 1.0
w_class = 1
var/caliber = "" //Which kind of guns it can be loaded into
var/projectile_type //The bullet type to create when New() is called
var/obj/item/projectile/BB = null //The loaded bullet
var/obj/item/projectile/BB = null //The loaded bullet - make it so that the projectiles are created only when needed?
var/spent_icon = null
/obj/item/ammo_casing/New()
..()
if(ispath(projectile_type))
BB = new projectile_type(src)
pixel_x = rand(-10, 10)
pixel_y = rand(-10, 10)
New()
..()
if(ispath(projectile_type))
BB = new projectile_type(src)
pixel_x = rand(-10.0, 10)
pixel_y = rand(-10.0, 10)
set_dir(pick(cardinal))
//removes the projectile from the ammo casing
/obj/item/ammo_casing/proc/expend()
. = BB
BB = null
set_dir(pick(cardinal)) //spin spent casings
update_icon()
/obj/item/ammo_casing/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/screwdriver))
if(BB)
if(initial(BB.name) == "bullet")
var/tmp_label = ""
var/label_text = sanitize(copytext(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 1, MAX_NAME_LEN))
if(length(label_text) > 20)
user << "\red The inscription can be at most 20 characters long."
else
if(label_text == "")
user << "\blue You scratch the inscription off of [initial(BB)]."
BB.name = initial(BB.name)
else
user << "\blue You inscribe \"[label_text]\" into \the [initial(BB.name)]."
BB.name = "[initial(BB.name)] \"[label_text]\""
else
user << "\blue You can only inscribe a metal bullet." //because inscribing beanbags is silly
else
if(!BB)
user << "\blue There is no bullet in the casing to inscribe anything into."
return
var/tmp_label = ""
var/label_text = sanitize(copytext(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label), 1, MAX_NAME_LEN))
if(length(label_text) > 20)
user << "\red The inscription can be at most 20 characters long."
else if(!label_text)
user << "\blue You scratch the inscription off of [initial(BB)]."
BB.name = initial(BB.name)
else
user << "\blue You inscribe \"[label_text]\" into \the [initial(BB.name)]."
BB.name = "[initial(BB.name)] (\"[label_text]\")"
/obj/item/ammo_casing/update_icon()
if(spent_icon && !BB)
icon_state = spent_icon
/obj/item/ammo_casing/examine(mob/user)
..()
if (!BB)
user << "This one is spent."
//Boxes of ammo
//Gun loading types
#define SINGLE_CASING 1 //The gun only accepts ammo_casings. ammo_magazines should never have this as their mag_type.
#define SPEEDLOADER 2 //Transfers casings from the mag to the gun when used.
#define MAGAZINE 4 //The magazine item itself goes inside the gun
//An item that holds casings and can be used to put them inside guns
/obj/item/ammo_magazine
name = "ammo box (.357)"
desc = "A box of ammo"
name = "magazine"
desc = "A magazine for some kind of gun."
icon_state = "357"
icon = 'icons/obj/ammo.dmi'
flags = CONDUCT
slot_flags = SLOT_BELT
item_state = "syringe_kit"
matter = list("metal" = 50000)
throwforce = 2
w_class = 2.0
matter = list("metal" = 500)
throwforce = 5
w_class = 2
throw_speed = 4
throw_range = 10
var/list/stored_ammo = list()
var/ammo_type = "/obj/item/ammo_casing"
var/mag_type = SPEEDLOADER //ammo_magazines can only be used with compatible guns. This is not a bitflag, the load_method var on guns is.
var/caliber = "357"
var/max_ammo = 7
var/ammo_type = /obj/item/ammo_casing //ammo type that is initially loaded
var/initial_ammo = null
var/multiple_sprites = 0
//because BYOND doesn't support numbers as keys in associative lists
var/list/icon_keys = list() //keys
var/list/ammo_states = list() //values
/obj/item/ammo_magazine/New()
if(multiple_sprites)
initialize_magazine_icondata(src)
New()
for(var/i = 1, i <= max_ammo, i++)
if(isnull(initial_ammo))
initial_ammo = max_ammo
if(initial_ammo)
for(var/i in 1 to initial_ammo)
stored_ammo += new ammo_type(src)
update_icon()
/obj/item/ammo_magazine/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/ammo_casing))
var/obj/item/ammo_casing/C = W
if(C.caliber != caliber)
user << "<span class='warning'>[C] does not fit into [src].</span>"
return
if(stored_ammo.len >= max_ammo)
user << "<span class='warning'>[src] is full!</span>"
return
user.remove_from_mob(C)
C.loc = src
stored_ammo.Insert(1, C) //add to the head of the list
update_icon()
/obj/item/ammo_magazine/attack_self(mob/user)
if(!stored_ammo.len)
user << "<span class='notice'>[src] is already empty!</span>"
return
user << "<span class='notice'>You empty [src].</span>"
for(var/obj/item/ammo_casing/C in stored_ammo)
C.loc = user.loc
C.set_dir(pick(cardinal))
stored_ammo.Cut()
update_icon()
if(multiple_sprites)
icon_state = "[initial(icon_state)]-[stored_ammo.len]"
desc = "There are [stored_ammo.len] shell\s left!"
/obj/item/ammo_magazine/update_icon()
if(multiple_sprites)
//find the lowest key greater than or equal to stored_ammo.len
var/new_state = null
for(var/idx in 1 to icon_keys.len)
var/ammo_count = icon_keys[idx]
if (ammo_count >= stored_ammo.len)
new_state = ammo_states[idx]
break
icon_state = (new_state)? new_state : initial(icon_state)
/obj/item/ammo_magazine/examine(mob/user)
..()
user << "There [(stored_ammo.len > 1)? "are" : "is"] [stored_ammo.len] round\s left!"
//magazine icon state caching
/var/global/list/magazine_icondata_keys = list()
/var/global/list/magazine_icondata_states = list()
/proc/initialize_magazine_icondata(var/obj/item/ammo_magazine/M)
var/typestr = "[M.type]"
if(!(typestr in magazine_icondata_keys) || !(typestr in magazine_icondata_states))
magazine_icondata_cache_add(M)
M.icon_keys = magazine_icondata_keys[typestr]
M.ammo_states = magazine_icondata_states[typestr]
/proc/magazine_icondata_cache_add(var/obj/item/ammo_magazine/M)
var/list/icon_keys = list()
var/list/ammo_states = list()
var/list/states = icon_states(M.icon)
for(var/i = 0, i <= M.max_ammo, i++)
var/ammo_state = "[M.icon_state]-[i]"
if(ammo_state in states)
icon_keys += i
ammo_states += ammo_state
magazine_icondata_keys["[M.type]"] = icon_keys
magazine_icondata_states["[M.type]"] = ammo_states

View File

@@ -1,45 +1,188 @@
/obj/item/ammo_magazine/a357
name = "ammo box (.357)"
desc = "A box of .357 ammo"
icon_state = "357"
ammo_type = "/obj/item/ammo_casing/a357"
//name = "ammo box (.357)"
//desc = "A box of .357 ammo"
//icon_state = "357"
name = "speed loader (.357)"
icon_state = "T38"
caliber = "357"
ammo_type = /obj/item/ammo_casing/a357
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/c38
name = "speed loader (.38)"
icon_state = "38"
ammo_type = "/obj/item/ammo_casing/c38"
caliber = "38"
ammo_type = /obj/item/ammo_casing/c38
max_ammo = 6
multiple_sprites = 1
/obj/item/ammo_magazine/c38/rubber
name = "speed loader (.38 rubber)"
ammo_type = /obj/item/ammo_casing/c38r
/obj/item/ammo_magazine/c45m
name = "magazine (.45)"
icon_state = "45"
ammo_type = "/obj/item/ammo_casing/c45"
mag_type = MAGAZINE
ammo_type = /obj/item/ammo_casing/c45
caliber = ".45"
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/c45/empty
max_ammo = 0
/obj/item/ammo_magazine/c45m/empty
initial_ammo = 0
/obj/item/ammo_magazine/c45r
/obj/item/ammo_magazine/c45m/rubber
name = "magazine (.45 rubber)"
icon_state = "45"
ammo_type = "/obj/item/ammo_casing/c45r"
max_ammo = 7
multiple_sprites = 1
ammo_type = /obj/item/ammo_casing/c45r
/obj/item/ammo_magazine/c45f
/obj/item/ammo_magazine/c45m/flash
name = "magazine (.45 flash)"
icon_state = "45"
ammo_type = "/obj/item/ammo_casing/c45f"
/obj/item/ammo_magazine/mc9mm
name = "magazine (9mm)"
icon_state = "9x19p"
origin_tech = "combat=2"
mag_type = MAGAZINE
caliber = "9mm"
ammo_type = /obj/item/ammo_casing/c9mm
max_ammo = 10
multiple_sprites = 1
/obj/item/ammo_magazine/mc9mm/empty
initial_ammo = 0
/obj/item/ammo_magazine/mc9mm/flash
ammo_type = /obj/item/ammo_casing/c9mmf
/obj/item/ammo_magazine/c9mm
name = "ammunition Box (9mm)"
icon_state = "9mm"
origin_tech = "combat=2"
caliber = "9mm"
ammo_type = /obj/item/ammo_casing/c9mm
max_ammo = 30
/obj/item/ammo_magazine/c9mm/empty
initial_ammo = 0
/obj/item/ammo_magazine/mc9mmt
name = "top mounted magazine (9mm)"
icon_state = "9mmt"
mag_type = MAGAZINE
ammo_type = /obj/item/ammo_casing/c9mm
caliber = "9mm"
max_ammo = 20
multiple_sprites = 1
/obj/item/ammo_magazine/mc9mmt/empty
initial_ammo = 0
/obj/item/ammo_magazine/mc9mmt/rubber
name = "top mounted magazine (9mm rubber)"
ammo_type = /obj/item/ammo_casing/c9mmr
/obj/item/ammo_magazine/c45
name = "ammunition Box (.45)"
icon_state = "9mm"
origin_tech = "combat=2"
caliber = ".45"
ammo_type = /obj/item/ammo_casing/c45
max_ammo = 30
/obj/item/ammo_magazine/c9mm/empty
initial_ammo = 0
/obj/item/ammo_magazine/a12mm
name = "magazine (12mm)"
icon_state = "12mm"
origin_tech = "combat=2"
mag_type = MAGAZINE
caliber = "12mm"
ammo_type = "/obj/item/ammo_casing/a12mm"
max_ammo = 20
multiple_sprites = 1
/obj/item/ammo_magazine/a12mm/empty
initial_ammo = 0
/obj/item/ammo_magazine/a556
name = "magazine (5.56)"
icon_state = "5.56"
origin_tech = "combat=2"
mag_type = MAGAZINE
caliber = "a556"
ammo_type = /obj/item/ammo_casing/a556
max_ammo = 10
multiple_sprites = 1
/obj/item/ammo_magazine/a556/empty
initial_ammo = 0
/obj/item/ammo_magazine/a50
name = "magazine (.50)"
icon_state = "50ae"
origin_tech = "combat=2"
mag_type = MAGAZINE
caliber = ".50"
ammo_type = /obj/item/ammo_casing/a50
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/c45r/empty
max_ammo = 0
/obj/item/ammo_magazine/a50/empty
initial_ammo = 0
/obj/item/ammo_magazine/a75
name = "ammo magazine (20mm)"
icon_state = "75"
mag_type = MAGAZINE
caliber = "75"
ammo_type = /obj/item/ammo_casing/a75
multiple_sprites = 1
max_ammo = 4
/obj/item/ammo_magazine/a75/empty
initial_ammo = 0
/obj/item/ammo_magazine/a762
name = "magazine box (7.62mm)"
icon_state = "a762"
origin_tech = "combat=2"
mag_type = MAGAZINE
caliber = "a762"
ammo_type = /obj/item/ammo_casing/a762
max_ammo = 50
multiple_sprites = 1
/obj/item/ammo_magazine/a762/empty
initial_ammo = 0
/obj/item/ammo_magazine/c762
name = "magazine (7.62mm)"
icon_state = "c762"
mag_type = MAGAZINE
caliber = "a762"
ammo_type = /obj/item/ammo_casing/a762
max_ammo = 20
multiple_sprites = 1
/obj/item/ammo_magazine/chameleon
name = "magazine (.45)"
icon_state = "45"
mag_type = MAGAZINE
caliber = ".45"
ammo_type = /obj/item/ammo_casing/chameleon
max_ammo = 7
multiple_sprites = 1
matter = list()
/obj/item/ammo_magazine/chameleon/empty
initial_ammo = 0
/*
//unused garbage
/obj/item/ammo_magazine/a418
name = "ammo box (.418)"
@@ -48,116 +191,10 @@
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/a666
name = "ammo box (.666)"
icon_state = "666"
ammo_type = "/obj/item/ammo_casing/a666"
max_ammo = 4
multiple_sprites = 1
/obj/item/ammo_magazine/mc9mm
name = "magazine (9mm)"
icon_state = "9x19p"
origin_tech = "combat=2"
ammo_type = "/obj/item/ammo_casing/c9mm"
max_ammo = 10
multiple_sprites = 1
/obj/item/ammo_magazine/mc9mm/empty/New()
..()
stored_ammo = list()
update_icon()
/obj/item/ammo_magazine/c9mm
name = "Ammunition Box (9mm)"
icon_state = "9mm"
origin_tech = "combat=2"
ammo_type = "/obj/item/ammo_casing/c9mm"
max_ammo = 30
/obj/item/ammo_magazine/c45
name = "Ammunition Box (.45)"
icon_state = "9mm"
origin_tech = "combat=2"
ammo_type = "/obj/item/ammo_casing/c45"
max_ammo = 30
/obj/item/ammo_magazine/a12mm
name = "magazine (12mm)"
icon_state = "12mm"
origin_tech = "combat=2"
ammo_type = "/obj/item/ammo_casing/a12mm"
max_ammo = 20
multiple_sprites = 1
/obj/item/ammo_magazine/a12mm/empty
name = "magazine (12mm)"
icon_state = "12mm"
ammo_type = "/obj/item/ammo_casing/12mm"
max_ammo = 0
/obj/item/ammo_magazine/a50
name = "magazine (.50)"
icon_state = "50ae"
origin_tech = "combat=2"
ammo_type = "/obj/item/ammo_casing/a50"
max_ammo = 7
multiple_sprites = 1
/obj/item/ammo_magazine/a50/empty
name = "magazine (.50)"
icon_state = "50ae"
ammo_type = "/obj/item/ammo_casing/a50"
max_ammo = 0
/obj/item/ammo_magazine/a75
name = "ammo magazine (.75)"
icon_state = "75"
ammo_type = "/obj/item/ammo_casing/a75"
multiple_sprites = 1
max_ammo = 8
/obj/item/ammo_magazine/a75/empty
name = "ammo magazine (.75)"
icon_state = "75"
ammo_type = "/obj/item/ammo_casing/a75"
max_ammo = 0
/obj/item/ammo_magazine/a762
name = "magazine (a762)"
icon_state = "a762"
origin_tech = "combat=2"
ammo_type = "/obj/item/ammo_casing/a762"
max_ammo = 50
multiple_sprites = 1
/obj/item/ammo_magazine/a762/empty
name = "magazine (a762)"
icon_state = "a762"
ammo_type = "/obj/item/ammo_casing/a762"
max_ammo = 0
multiple_sprites = 1
/obj/item/ammo_magazine/chameleon
name = "magazine (.45)"
icon_state = "45"
ammo_type = "/obj/item/ammo_casing/chameleon"
max_ammo = 7
multiple_sprites = 1
matter = list()
/obj/item/ammo_magazine/chameleon/empty
name = "magazine (.45)"
icon_state = "45"
ammo_type = "/obj/item/ammo_casing/chameleon"
max_ammo = 0
multiple_sprites = 1
matter = list()
*/

View File

@@ -16,6 +16,11 @@
/obj/item/ammo_casing/c38
desc = "A .38 bullet casing."
caliber = "38"
projectile_type = /obj/item/projectile/bullet/pistol
/obj/item/ammo_casing/c38r
desc = "A .38 rubber bullet casing."
caliber = "38"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
/obj/item/ammo_casing/c9mm
@@ -23,6 +28,17 @@
caliber = "9mm"
projectile_type = /obj/item/projectile/bullet/pistol
/obj/item/ammo_casing/c9mmf
desc = "A 9mm flash shell casing."
caliber = "9mm"
projectile_type = /obj/item/projectile/energy/flash
/obj/item/ammo_casing/c9mmr
desc = "A 9mm rubber bullet casing."
caliber = "9mm"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
/obj/item/ammo_casing/c45
desc = "A .45 bullet casing."
caliber = ".45"
@@ -73,38 +89,46 @@
projectile_type = /obj/item/projectile/bullet/shotgun/beanbag
matter = list("metal" = 500)
//Can stun in one hit if aimed at the head, but
//is blocked by clothing that stops tasers and is vulnerable to EMP
/obj/item/ammo_casing/shotgun/stunshell
name = "stun shell"
desc = "A 12 gauge taser cartridge."
icon_state = "stunshell"
spent_icon = "stunshell-spent"
projectile_type = /obj/item/projectile/energy/electrode/stunshot
matter = list("metal" = 1250, "glass" = 1250)
/obj/item/ammo_casing/shotgun/stunshell/emp_act(severity)
if(prob(100/severity)) BB = null
update_icon()
//Does not stun, only blinds, but has area of effect.
/obj/item/ammo_casing/shotgun/flash
name = "flash shell"
desc = "A flash shell used to provide illumination."
desc = "A chemical shell used to signal distress or provide illumination."
icon_state = "fshell"
projectile_type = /obj/item/projectile/energy/flash/flare
matter = list("metal" = 250, "glass" = 250)
/obj/item/ammo_casing/shotgun/dart
name = "shotgun dart"
desc = "A dart for use in shotguns."
icon_state = "dart"
projectile_type = /obj/item/projectile/energy/dart
matter = list("metal" = 12500)
/obj/item/ammo_casing/a762
desc = "A 7.62mm bullet casing."
caliber = "a762"
projectile_type = /obj/item/projectile/bullet/rifle/a762
/obj/item/ammo_casing/a145
name = "\improper AP shell casing"
desc = "A 14.5mm AP shell."
icon_state = "slshell"
name = "shell casing"
desc = "A 14.5mm shell."
icon_state = "lcasing"
spent_icon = "lcasing-spent"
caliber = "14.5mm"
projectile_type = /obj/item/projectile/bullet/rifle/a145
/obj/item/ammo_casing/a556
desc = "A 5.56mm bullet casing."
caliber = "a556"
projectile_type = /obj/item/projectile/bullet/rifle/a556
/obj/item/ammo_casing/rocket
name = "rocket shell"
desc = "A high explosive designed to be fired from a launcher."
@@ -118,6 +142,7 @@
projectile_type = /obj/item/projectile/bullet/chameleon
caliber = ".45"
/*
/obj/item/ammo_casing/a418
desc = "A .418 bullet casing."
caliber = "357"
@@ -126,4 +151,5 @@
/obj/item/ammo_casing/a666
desc = "A .666 bullet casing."
caliber = "357"
projectile_type = /obj/item/projectile/bullet/cyanideround
projectile_type = /obj/item/projectile/bullet/cyanideround
*/

View File

@@ -1,3 +1,4 @@
//Parent gun type. Guns are weapons that can be aimed at mobs and act over a distance
/obj/item/weapon/gun
name = "gun"
desc = "Its a gun. It's pretty terrible, though."
@@ -5,59 +6,88 @@
icon_state = "detective"
item_state = "gun"
flags = CONDUCT
slot_flags = SLOT_BELT
slot_flags = SLOT_BELT|SLOT_HOLSTER
matter = list("metal" = 2000)
w_class = 3.0
w_class = 3
throwforce = 5
throw_speed = 4
throw_range = 5
force = 5.0
force = 5
origin_tech = "combat=1"
attack_verb = list("struck", "hit", "bashed")
zoomdevicename = "scope"
var/fire_delay = 6
var/fire_sound = 'sound/weapons/Gunshot.ogg'
var/obj/item/projectile/in_chamber = null
var/caliber = ""
var/fire_sound_text = "gunshot"
var/recoil = 0 //screen shake
var/silenced = 0
var/recoil = 0
var/ejectshell = 1
var/clumsy_check = 1
var/tmp/list/mob/living/target //List of who yer targeting.
var/tmp/lock_time = -100
var/tmp/mouthshoot = 0 ///To stop people from suiciding twice... >.>
var/automatic = 0 //Used to determine if you can target multiple people.
var/accuracy = 0 //accuracy is measured in tiles. +1 accuracy means that everything is effectively one tile closer for the purpose of miss chance, -1 means the opposite. launchers are not supported, at the moment.
var/scoped_accuracy = null
var/last_fired = 0
//aiming system stuff
var/keep_aim = 1 //1 for keep shooting until aim is lowered
//0 for one bullet after tarrget moves and aim is lowered
var/multi_aim = 0 //Used to determine if you can target multiple people.
var/tmp/list/mob/living/aim_targets //List of who yer targeting.
var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person.
var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them.
var/firerate = 0 //0 for keep shooting until aim is lowered
// 1 for one bullet after tarrget moves and aim is lowered
var/fire_delay = 6
var/last_fired = 0
var/tmp/lock_time = -100
proc/ready_to_fire()
if(world.time >= last_fired + fire_delay)
last_fired = world.time
return 1
else
return 0
/obj/item/weapon/gun/New()
..()
if(isnull(scoped_accuracy))
scoped_accuracy = accuracy
proc/load_into_chamber()
//Returns 1 if the gun is able to be fired
/obj/item/weapon/gun/proc/ready_to_fire()
if(world.time >= last_fired + fire_delay)
last_fired = world.time
return 1
else
return 0
proc/special_check(var/mob/M) //Placeholder for any special checks, like detective's revolver.
return 1
//Checks whether a given mob can use the gun
//Any checks that shouldn't result in handle_click_empty() being called if they fail should go here.
//Otherwise, if you want handle_click_empty() to be called, check in consume_next_projectile() and return null there.
/obj/item/weapon/gun/proc/special_check(var/mob/user)
if(!istype(user, /mob/living))
return 0
if(!user.IsAdvancedToolUser())
return 0
var/mob/living/M = user
if(HULK in M.mutations)
M << "<span class='danger'>Your fingers are much too large for the trigger guard!</span>"
return 0
if((CLUMSY in M.mutations) && prob(40)) //Clumsy handling
var/obj/P = consume_next_projectile()
if(P)
if(process_projectile(P, user, user, pick("l_foot", "r_foot")))
handle_post_fire(user, user)
user.visible_message(
"<span class='danger'>[user] shoots \himself in the foot with \the [src]!</span>",
"<span class='danger'>You shoot yourself in the foot with \the [src]!</span>"
)
M.drop_item()
else
handle_click_empty(user)
return 0
return 1
emp_act(severity)
for(var/obj/O in contents)
O.emp_act(severity)
/obj/item/weapon/gun/afterattack(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, flag, params)
if(flag) return //It's adjacent, is the user, or is on the user's person
if(istype(target, /obj/machinery/recharger) && istype(src, /obj/item/weapon/gun/energy)) return//Shouldnt flag take care of this?
/obj/item/weapon/gun/emp_act(severity)
for(var/obj/O in contents)
O.emp_act(severity)
/obj/item/weapon/gun/afterattack(atom/A, mob/living/user, adjacent, params)
if(adjacent) return //A is adjacent, is the user, or is on the user's person
//decide whether to aim or shoot normally
var/aiming = 0
if(user && user.client && !(A in target))
if(user && user.client && !(A in aim_targets))
var/client/C = user.client
//If help intent is on and we have clicked on an eligible target, switch to aim mode automatically
if(user.a_intent == "help" && isliving(A) && !C.gun_mode)
@@ -72,30 +102,16 @@
else
Fire(A,user,params) //Otherwise, fire normally.
/obj/item/weapon/gun/proc/isHandgun()
return 1
/obj/item/weapon/gun/attack(atom/A, mob/living/user, def_zone)
if (A == user && user.zone_sel.selecting == "mouth" && !mouthshoot)
handle_suicide(user)
else if(user.a_intent == "hurt") //point blank shooting
Fire(A, user, pointblank=1)
else
return ..() //Pistolwhippin'
/obj/item/weapon/gun/proc/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)//TODO: go over this
//Exclude lasertag guns from the CLUMSY check.
if(!user) return
if(clumsy_check)
if(istype(user, /mob/living))
var/mob/living/M = user
if ((CLUMSY in M.mutations) && prob(50))
M << "<span class='danger'>[src] blows up in your face.</span>"
M.take_organ_damage(0,20)
M.drop_item()
del(src)
return
if (!user.IsAdvancedToolUser())
return
if(istype(user, /mob/living))
var/mob/living/M = user
if (HULK in M.mutations)
M << "<span class='danger'>Your fingers are much too large for the trigger guard!</span>"
return
/obj/item/weapon/gun/proc/Fire(atom/target, mob/living/user, params, pointblank=0, reflex=0)
if(!user || !target) return
add_fingerprint(user)
@@ -107,22 +123,68 @@
user << "<span class='warning'>[src] is not ready to fire again!"
return
if(!load_into_chamber()) //CHECK
return click_empty(user)
if(!in_chamber)
var/obj/projectile = consume_next_projectile(user)
if(!projectile)
handle_click_empty(user)
return
user.next_move = world.time + 4
if(process_projectile(projectile, user, target, user.zone_sel.selecting, params, pointblank, reflex))
handle_post_fire(user, target, pointblank, reflex)
update_icon()
if(user.hand)
user.update_inv_l_hand()
else
user.update_inv_r_hand()
//obtains the next projectile to fire
/obj/item/weapon/gun/proc/consume_next_projectile()
return null
//used by aiming code
/obj/item/weapon/gun/proc/can_hit(atom/target as mob, var/mob/living/user as mob)
if(!special_check(user))
return 2
//just assume we can shoot through glass and stuff. No big deal, the player can just choose to not target someone
//on the other side of a window if it makes a difference. Or if they run behind a window, too bad.
return check_trajectory(target, user)
//called if there was no projectile to shoot
/obj/item/weapon/gun/proc/handle_click_empty(mob/user)
if (user)
user.visible_message("*click click*", "<span class='danger'>*click*</span>")
else
src.visible_message("*click click*")
playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1)
//called after successfully firing
/obj/item/weapon/gun/proc/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0)
if(silenced)
playsound(user, fire_sound, 10, 1)
else
playsound(user, fire_sound, 50, 1)
user.visible_message("<span class='warning'>[user] fires [src][reflex ? " by reflex":""]!</span>", \
"<span class='warning'>You fire [src][reflex ? "by reflex":""]!</span>", \
"You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!")
user.next_move = world.time + 4
user.visible_message(
"<span class='danger'>[user] fires [src][pointblank ? " point blank at [target]":""][reflex ? " by reflex":""]!</span>",
"<span class='warning'>You fire [src][reflex ? "by reflex":""]!</span>",
"You hear a [fire_sound_text]!"
)
if(recoil)
spawn()
shake_camera(user, recoil+1, recoil)
update_icon()
//does the actual shooting
/obj/item/weapon/gun/proc/process_projectile(obj/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0)
if(!istype(projectile, /obj/item/projectile))
return 0 //default behaviour only applies to true projectiles
var/obj/item/projectile/P = projectile
//shooting while in shock
var/x_offset = 0
var/y_offset = 0
if(istype(user, /mob/living/carbon))
@@ -134,101 +196,72 @@
y_offset = rand(-1,1)
x_offset = rand(-1,1)
var/p_x
var/p_y
//Point blank bonus
if(pointblank) P.damage *= 1.3
//TODO: accuracy modifiers
if(params)
var/list/mouse_control = params2list(params)
if(mouse_control["icon-x"])
p_x = text2num(mouse_control["icon-x"])
if(mouse_control["icon-y"])
p_y = text2num(mouse_control["icon-y"])
P.set_clickpoint(params)
return !P.launch(target, user, src, target_zone, x_offset, y_offset)
//Suicide handling.
/obj/item/weapon/gun/var/mouthshoot = 0 //To stop people from suiciding twice... >.>
/obj/item/weapon/gun/proc/handle_suicide(mob/living/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/M = user
if(in_chamber)
var/fail = in_chamber.launch(
target = target,
user = user,
launcher = src,
target_zone = user.zone_sel.selecting,
x_offset = x_offset,
y_offset = y_offset,
px = p_x,
py = p_y
)
if(fail) return
if(recoil)
spawn()
shake_camera(user, recoil + 1, recoil)
sleep(1)
in_chamber = null
update_icon()
if(user.hand)
user.update_inv_l_hand()
else
user.update_inv_r_hand()
/obj/item/weapon/gun/proc/can_fire()
return load_into_chamber()
/obj/item/weapon/gun/proc/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
return in_chamber.check_fire(target,user)
/obj/item/weapon/gun/proc/click_empty(mob/user = null)
if (user)
user.visible_message("*click click*", "\red <b>*click*</b>")
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
else
src.visible_message("*click click*")
playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1)
/obj/item/weapon/gun/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
//Suicide handling.
if (M == user && user.zone_sel.selecting == "mouth" && !mouthshoot)
mouthshoot = 1
M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...")
if(!do_after(user, 40))
M.visible_message("\blue [user] decided life was worth living")
mouthshoot = 0
return
if (load_into_chamber())
user.visible_message("<span class = 'warning'>[user] pulls the trigger.</span>")
if(silenced)
playsound(user, fire_sound, 10, 1)
else
playsound(user, fire_sound, 50, 1)
if(istype(in_chamber, /obj/item/projectile/beam/lastertag))
user.show_message("<span class = 'warning'>You feel rather silly, trying to commit suicide with a toy.</span>")
mouthshoot = 0
return
in_chamber.on_hit(M)
if (in_chamber.damage_type != HALLOSS)
user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1)
user.death()
else
user << "<span class = 'notice'>Ow...</span>"
user.apply_effect(110,AGONY,0)
del(in_chamber)
mouthshoot = 0
return
mouthshoot = 1
M.visible_message("\red [user] sticks their gun in their mouth, ready to pull the trigger...")
if(!do_after(user, 40))
M.visible_message("\blue [user] decided life was worth living")
mouthshoot = 0
return
var/obj/item/projectile/in_chamber = consume_next_projectile()
if (istype(in_chamber))
user.visible_message("<span class = 'warning'>[user] pulls the trigger.</span>")
if(silenced)
playsound(user, fire_sound, 10, 1)
else
click_empty(user)
playsound(user, fire_sound, 50, 1)
if(istype(in_chamber, /obj/item/projectile/beam/lastertag))
user.show_message("<span class = 'warning'>You feel rather silly, trying to commit suicide with a toy.</span>")
mouthshoot = 0
return
if (load_into_chamber())
//Point blank shooting if on harm intent or target we were targeting.
if(user.a_intent == "hurt")
user.visible_message("\red <b> \The [user] fires \the [src] point blank at [M]!</b>")
if(istype(in_chamber)) in_chamber.damage *= 1.3
Fire(M,user)
return
else if(target && M in target)
Fire(M,user) ///Otherwise, shoot!
return
in_chamber.on_hit(M)
if (in_chamber.damage_type != HALLOSS)
user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1)
user.death()
else
user << "<span class = 'notice'>Ow...</span>"
user.apply_effect(110,AGONY,0)
del(in_chamber)
mouthshoot = 0
return
else
return ..() //Pistolwhippin'
handle_click_empty(user)
mouthshoot = 0
return
/obj/item/weapon/gun/proc/toggle_scope(var/zoom_amount=2.0)
//looking through a scope limits your periphereal vision
//still, increase the view size by a tiny amount so that sniping isn't too restricted to NSEW
var/zoom_offset = round(world.view * zoom_amount)
var/view_size = round(world.view + zoom_amount)
var/scoped_accuracy_mod = zoom_offset
zoom(zoom_offset, view_size)
if(zoom)
accuracy = scoped_accuracy + scoped_accuracy_mod
if(recoil)
recoil = round(recoil*zoom_amount+1) //recoil is worse when looking through a scope
//make sure accuracy and recoil are reset regardless of how the item is unzoomed.
/obj/item/weapon/gun/zoom()
..()
if(!zoom)
accuracy = initial(accuracy)
recoil = initial(recoil)

View File

@@ -1,6 +1,6 @@
//Vox pinning weapon.
/obj/item/weapon/gun/launcher/spikethrower
name = "Vox spike thrower"
name = "vox spike thrower"
desc = "A vicious alien projectile weapon. Parts of it quiver gelatinously, as though the thing is insectile and alive."
var/last_regen = 0
@@ -24,7 +24,6 @@
..()
/obj/item/weapon/gun/launcher/spikethrower/process()
if(spikes < max_spikes && world.time > last_regen + spike_gen_time)
spikes++
last_regen = world.time
@@ -32,35 +31,26 @@
/obj/item/weapon/gun/launcher/spikethrower/examine(mob/user)
..(user)
user << "It has [spikes] [spikes == 1 ? "spike" : "spikes"] remaining."
user << "It has [spikes] spike\s remaining."
/obj/item/weapon/gun/launcher/spikethrower/update_icon()
icon_state = "spikethrower[spikes]"
/obj/item/weapon/gun/launcher/spikethrower/emp_act(severity)
return
/obj/item/weapon/gun/launcher/spikethrower/special_check(user)
if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.species && H.species.name != "Vox" && H.species.name != "Vox Armalis")
user << "\red \The [src] does not respond to you!"
user << "<span class='warning'>\The [src] does not respond to you!</span>"
return 0
return 1
return ..()
/obj/item/weapon/gun/launcher/spikethrower/update_release_force()
return
/obj/item/weapon/gun/launcher/spikethrower/load_into_chamber()
if(in_chamber) return 1
if(spikes < 1) return 0
/obj/item/weapon/gun/launcher/spikethrower/consume_next_projectile()
if(spikes < 1) return null
spikes--
in_chamber = new /obj/item/weapon/spike(src)
return 1
/obj/item/weapon/gun/launcher/spikethrower/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
if(..()) update_icon()
return new /obj/item/weapon/spike(src)
//This gun only functions for armalis. The on-sprite is too huge to render properly on other sprites.
/obj/item/weapon/gun/energy/noisecannon
@@ -74,7 +64,7 @@
force = 10
projectile_type = /obj/item/projectile/energy/sonic
cell_type = "/obj/item/weapon/cell/super"
cell_type = /obj/item/weapon/cell/super
fire_delay = 40
fire_sound = 'sound/effects/basscannon.ogg'
@@ -91,13 +81,9 @@
if(H.species.name == "Vox Armalis")
..()
return
user << "\red \The [src] is far too large for you to pick up."
user << "<span class='warning'>\The [src] is far too large for you to pick up.</span>"
return
/obj/item/weapon/gun/energy/noisecannon/load_into_chamber() //Does not have ammo.
in_chamber = new projectile_type(src)
return 1
/obj/item/weapon/gun/energy/noisecannon/update_icon()
return
@@ -108,7 +94,7 @@
icon_state = "particle"
damage = 60
damage_type = BRUTE
flag = "bullet"
check_armour = "bullet"
pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE
embed = 0

View File

@@ -3,39 +3,78 @@
desc = "A basic energy-based gun."
icon_state = "energy"
fire_sound = 'sound/weapons/Taser.ogg'
fire_sound_text = "laser blast"
var/obj/item/weapon/cell/power_supply //What type of power cell this uses
var/charge_cost = 100 //How much energy is needed to fire.
var/cell_type = "/obj/item/weapon/cell"
var/cell_type = /obj/item/weapon/cell
var/projectile_type = /obj/item/projectile/beam/practice
var/modifystate
var/charge_meter = 1 //if set, the icon state will be chosen based on the current charge
//self-recharging
var/self_recharge = 0 //if set, the weapon will recharge itself
var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically
var/recharge_time = 4
var/charge_tick = 0
emp_act(severity)
power_supply.use(round(power_supply.maxcharge / severity))
update_icon()
..()
New()
..()
if(cell_type)
power_supply = new cell_type(src)
else
power_supply = new(src)
power_supply.give(power_supply.maxcharge)
return
load_into_chamber()
if(in_chamber) return 1
if(!power_supply) return 0
if(!power_supply.use(charge_cost)) return 0
if(!ispath(projectile_type)) return 0
in_chamber = new projectile_type(src)
return 1
/obj/item/weapon/gun/energy/emp_act(severity)
..()
update_icon()
/obj/item/weapon/gun/energy/New()
..()
if(cell_type)
power_supply = new cell_type(src)
power_supply.give(power_supply.maxcharge)
if(self_recharge)
processing_objects.Add(src)
/obj/item/weapon/gun/energy/Del()
if(self_recharge)
processing_objects.Remove(src)
..()
/obj/item/weapon/gun/energy/process()
if(self_recharge) //Every [recharge_time] ticks, recharge a shot for the cyborg
charge_tick++
if(charge_tick < recharge_time) return 0
charge_tick = 0
if(!power_supply || power_supply.charge >= power_supply.maxcharge)
return 0 // check if we actually need to recharge
if(use_external_power)
var/obj/item/weapon/cell/external = get_external_power_supply()
if(!external || !external.use(charge_cost)) //Take power from the borg...
return 0
power_supply.give(charge_cost) //... to recharge the shot
update_icon()
return 1
/obj/item/weapon/gun/energy/consume_next_projectile()
if(!power_supply) return null
if(!ispath(projectile_type)) return null
if(!power_supply.use(charge_cost)) return null
return new projectile_type(src)
/obj/item/weapon/gun/energy/proc/get_external_power_supply()
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
return R.cell
if(istype(src.loc, /obj/item/rig_module))
var/obj/item/rig_module/module = src.loc
if(module.holder && module.holder.wearer)
var/mob/living/carbon/human/H = module.holder.wearer
if(istype(H) && H.back)
var/obj/item/weapon/rig/suit = H.back
if(istype(suit))
return suit.cell
return null
/obj/item/weapon/gun/energy/update_icon()
if(charge_meter)
var/ratio = power_supply.charge / power_supply.maxcharge
ratio = round(ratio, 0.25) * 100
if(modifystate)

View File

@@ -1,92 +1,58 @@
/obj/item/weapon/gun/energy/laser
name = "laser carbine"
desc = "A basic weapon designed to kill with concentrated energy bolts."
desc = "A common laser weapon, designed to kill with concentrated energy blasts."
icon_state = "laser"
item_state = "laser"
fire_sound = 'sound/weapons/Laser.ogg'
w_class = 3.0
slot_flags = SLOT_BELT|SLOT_BACK
w_class = 3
force = 10 //it has a stock, might as well give some kind of perk over the egun
matter = list("metal" = 2000)
origin_tech = "combat=3;magnets=2"
projectile_type = /obj/item/projectile/beam
charge_cost = 75
fire_delay = 1
/obj/item/weapon/gun/energy/laser/mounted
self_recharge = 1
use_external_power = 1
/obj/item/weapon/gun/energy/laser/practice
name = "practice laser gun"
desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice."
projectile_type = /obj/item/projectile/beam/practice
clumsy_check = 0
obj/item/weapon/gun/energy/laser/retro
name = "retro laser"
icon_state = "retro"
desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws."
/obj/item/weapon/gun/energy/laser/captain
/obj/item/weapon/gun/energy/captain
name = "antique laser gun"
icon_state = "caplaser"
desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding."
force = 10
force = 5
slot_flags = SLOT_BELT
origin_tech = null
var/charge_tick = 0
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(100)
update_icon()
return 1
/obj/item/weapon/gun/energy/laser/cyborg/load_into_chamber()
if(in_chamber)
return 1
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
if(R && R.cell)
R.cell.use(100)
in_chamber = new/obj/item/projectile/beam(src)
return 1
return 0
self_recharge = 1
/obj/item/weapon/gun/energy/lasercannon
name = "laser cannon"
desc = "With the L.A.S.E.R. cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
desc = "With the laser cannon, the lasing medium is enclosed in a tube lined with uranium-235 and subjected to high neutron flux in a nuclear reactor core. This incredible technology may help YOU achieve high excitation rates with small laser volumes!"
icon_state = "lasercannon"
item_state = "laser"
fire_sound = 'sound/weapons/lasercannonfire.ogg'
origin_tech = "combat=4;materials=3;powerstorage=3"
projectile_type = "/obj/item/projectile/beam/heavylaser"
slot_flags = SLOT_BELT|SLOT_BACK
projectile_type = /obj/item/projectile/beam/heavylaser
charge_cost = 250
fire_delay = 20
isHandgun()
return 0
/obj/item/weapon/gun/energy/lasercannon/cyborg/load_into_chamber()
if(in_chamber)
return 1
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
if(R && R.cell)
R.cell.use(250)
in_chamber = new/obj/item/projectile/beam/heavylaser(src)
return 1
return 0
/obj/item/weapon/gun/energy/lasercannon/mounted
self_recharge = 1
use_external_power = 1
recharge_time = 25
/obj/item/weapon/gun/energy/xray
name = "xray laser gun"
@@ -94,80 +60,58 @@ obj/item/weapon/gun/energy/laser/retro
icon_state = "xray"
fire_sound = 'sound/weapons/laser3.ogg'
origin_tech = "combat=5;materials=3;magnets=2;syndicate=2"
projectile_type = "/obj/item/projectile/beam/xray"
projectile_type = /obj/item/projectile/beam/xray
charge_cost = 50
/obj/item/weapon/gun/energy/sniperrifle
name = "\improper L.W.A.P. sniper rifle"
desc = "A high-power laser rifle fitted with a SMART aiming-system scope."
icon_state = "sniper"
item_state = "laser"
fire_sound = 'sound/weapons/marauder.ogg'
origin_tech = "combat=6;materials=5;powerstorage=4"
projectile_type = /obj/item/projectile/beam/sniper
slot_flags = SLOT_BACK
charge_cost = 250
fire_delay = 35
force = 10
w_class = 4
accuracy = -3 //shooting at the hip
scoped_accuracy = 0
/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
set category = "Object"
set name = "Use Scope"
set popup_menu = 1
toggle_scope(2.0)
////////Laser Tag////////////////////
/obj/item/weapon/gun/energy/laser/bluetag
/obj/item/weapon/gun/energy/lasertag
name = "laser tag gun"
item_state = "laser"
desc = "Standard issue weapon of the Imperial Guard"
origin_tech = "combat=1;magnets=2"
self_recharge = 1
matter = list("metal" = 2000)
fire_sound = 'sound/weapons/Laser.ogg'
projectile_type = /obj/item/projectile/beam/lastertag/blue
var/required_vest
/obj/item/weapon/gun/energy/lasertag/special_check(var/mob/living/carbon/human/M)
if(ishuman(M))
if(!istype(M.wear_suit, required_vest))
M << "<span class='warning'>You need to be wearing your laser tag vest!</span>"
return 0
return ..()
/obj/item/weapon/gun/energy/lasertag/blue
icon_state = "bluetag"
desc = "Standard issue weapon of the Imperial Guard"
projectile_type = "/obj/item/projectile/beam/lastertag/blue"
origin_tech = "combat=1;magnets=2"
clumsy_check = 0
var/charge_tick = 0
projectile_type = /obj/item/projectile/beam/lastertag/blue
required_vest = /obj/item/clothing/suit/bluetag
special_check(var/mob/living/carbon/human/M)
if(ishuman(M))
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag))
return 1
M << "\red You need to be wearing your laser tag vest!"
return 0
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(100)
update_icon()
return 1
/obj/item/weapon/gun/energy/laser/redtag
name = "laser tag gun"
/obj/item/weapon/gun/energy/lasertag/red
icon_state = "redtag"
desc = "Standard issue weapon of the Imperial Guard"
projectile_type = "/obj/item/projectile/beam/lastertag/red"
origin_tech = "combat=1;magnets=2"
clumsy_check = 0
var/charge_tick = 0
special_check(var/mob/living/carbon/human/M)
if(ishuman(M))
if(istype(M.wear_suit, /obj/item/clothing/suit/redtag))
return 1
M << "\red You need to be wearing your laser tag vest!"
return 0
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(100)
update_icon()
return 1
projectile_type = /obj/item/projectile/beam/lastertag/red
required_vest = /obj/item/clothing/suit/redtag

View File

@@ -1,6 +1,6 @@
/obj/item/weapon/gun/energy/gun
name = "energy gun"
desc = "A basic energy-based gun with two settings: Stun and kill."
desc = "An energy-based gun with two settings: Stun and kill."
icon_state = "energystun100"
item_state = null //so the human update icon uses the icon_state instead.
fire_sound = 'sound/weapons/Taser.ogg'
@@ -12,118 +12,108 @@
var/mode = 0 //0 = stun, 1 = kill
/obj/item/weapon/gun/energy/gun/attack_self(mob/living/user as mob)
switch(mode)
if(0)
mode = 1
charge_cost = 100
fire_sound = 'sound/weapons/Laser.ogg'
user << "<span class='warning'>[src.name] is now set to kill.</span>"
projectile_type = /obj/item/projectile/beam
modifystate = "energykill"
if(1)
mode = 0
charge_cost = 100
fire_sound = 'sound/weapons/Taser.ogg'
user << "<span class='warning'>[src.name] is now set to stun.</span>"
projectile_type = /obj/item/projectile/beam/stun
modifystate = "energystun"
update_icon()
if(user.l_hand == src)
user.update_inv_l_hand()
else
user.update_inv_r_hand()
attack_self(mob/living/user as mob)
switch(mode)
if(0)
mode = 1
charge_cost = 100
fire_sound = 'sound/weapons/Laser.ogg'
user << "\red [src.name] is now set to kill."
projectile_type = /obj/item/projectile/beam
modifystate = "energykill"
if(1)
mode = 0
charge_cost = 100
fire_sound = 'sound/weapons/Taser.ogg'
user << "\red [src.name] is now set to stun."
projectile_type = /obj/item/projectile/beam/stun
modifystate = "energystun"
update_icon()
if(user.l_hand == src)
user.update_inv_l_hand()
else
user.update_inv_r_hand()
/obj/item/weapon/gun/energy/gun/mounted
self_recharge = 1
use_external_power = 1
/obj/item/weapon/gun/energy/gun/nuclear
name = "advanced energy gun"
desc = "An energy gun with an experimental miniaturized reactor."
icon_state = "nucgun"
origin_tech = "combat=3;materials=5;powerstorage=3"
origin_tech = "combat=3;materials=5;powerstorage=3"
slot_flags = SLOT_BELT
force = 8 //looks heavier than a pistol
self_recharge = 1
var/lightfail = 0
var/charge_tick = 0
New()
..()
processing_objects.Add(src)
//override for failcheck behaviour
/obj/item/weapon/gun/energy/gun/nuclear/process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
if((power_supply.charge / power_supply.maxcharge) != 1)
if(!failcheck()) return 0
power_supply.give(charge_cost)
update_icon()
return 1
Del()
/obj/item/weapon/gun/energy/gun/nuclear/proc/failcheck()
lightfail = 0
if (prob(src.reliability)) return 1 //No failure
if (prob(src.reliability))
for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it
if (src in M.contents)
M << "<span class='warning'>Your gun feels pleasantly warm for a moment.</span>"
else
M << "<span class='warning'>You feel a warm sensation.</span>"
M.apply_effect(rand(3,120), IRRADIATE)
lightfail = 1
else
for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES
if (src in M.contents)
M << "<span class='danger'>Your gun's reactor overloads!</span>"
M << "<span class='warning'>You feel a wave of heat wash over you.</span>"
M.apply_effect(300, IRRADIATE)
crit_fail = 1 //break the gun so it stops recharging
processing_objects.Remove(src)
..()
update_icon()
return 0
process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
if((power_supply.charge / power_supply.maxcharge) != 1)
if(!failcheck()) return 0
power_supply.give(100)
update_icon()
return 1
/obj/item/weapon/gun/energy/gun/nuclear/proc/update_charge()
if (crit_fail)
overlays += "nucgun-whee"
return
var/ratio = power_supply.charge / power_supply.maxcharge
ratio = round(ratio, 0.25) * 100
overlays += "nucgun-[ratio]"
/obj/item/weapon/gun/energy/gun/nuclear/proc/update_reactor()
if(crit_fail)
overlays += "nucgun-crit"
return
if(lightfail)
overlays += "nucgun-medium"
else if ((power_supply.charge/power_supply.maxcharge) <= 0.5)
overlays += "nucgun-light"
else
overlays += "nucgun-clean"
proc
failcheck()
lightfail = 0
if (prob(src.reliability)) return 1 //No failure
if (prob(src.reliability))
for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it
if (src in M.contents)
M << "\red Your gun feels pleasantly warm for a moment."
else
M << "\red You feel a warm sensation."
M.apply_effect(rand(3,120), IRRADIATE)
lightfail = 1
else
for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES
if (src in M.contents)
M << "\red Your gun's reactor overloads!"
M << "\red You feel a wave of heat wash over you."
M.apply_effect(300, IRRADIATE)
crit_fail = 1 //break the gun so it stops recharging
processing_objects.Remove(src)
update_icon()
return 0
/obj/item/weapon/gun/energy/gun/nuclear/proc/update_mode()
if (mode == 0)
overlays += "nucgun-stun"
else if (mode == 1)
overlays += "nucgun-kill"
/obj/item/weapon/gun/energy/gun/nuclear/emp_act(severity)
..()
reliability -= round(15/severity)
update_charge()
if (crit_fail)
overlays += "nucgun-whee"
return
var/ratio = power_supply.charge / power_supply.maxcharge
ratio = round(ratio, 0.25) * 100
overlays += "nucgun-[ratio]"
update_reactor()
if(crit_fail)
overlays += "nucgun-crit"
return
if(lightfail)
overlays += "nucgun-medium"
else if ((power_supply.charge/power_supply.maxcharge) <= 0.5)
overlays += "nucgun-light"
else
overlays += "nucgun-clean"
update_mode()
if (mode == 0)
overlays += "nucgun-stun"
else if (mode == 1)
overlays += "nucgun-kill"
emp_act(severity)
..()
reliability -= round(15/severity)
update_icon()
overlays.Cut()
update_charge()
update_reactor()
update_mode()
/obj/item/weapon/gun/energy/gun/nuclear/update_icon()
overlays.Cut()
update_charge()
update_reactor()
update_mode()

View File

@@ -1,70 +1,57 @@
/obj/item/weapon/gun/energy/pulse_rifle
name = "pulse rifle"
desc = "A heavy-duty, pulse-based energy weapon, preferred by front-line combat personnel."
desc = "A weapon that uses advanced pulse-based beam generation technology to emit powerful laser blasts. Because of its complexity and cost, it is rarely seen in use except by specialists."
icon_state = "pulse"
item_state = null //so the human update icon uses the icon_state instead.
slot_flags = SLOT_BELT|SLOT_BACK
force = 10
fire_sound = 'sound/weapons/pulse.ogg'
charge_cost = 200
projectile_type = /obj/item/projectile/beam/pulse
cell_type = "/obj/item/weapon/cell/super"
cell_type = /obj/item/weapon/cell/super
var/mode = 2
fire_delay = 25
attack_self(mob/living/user as mob)
switch(mode)
if(2)
mode = 0
charge_cost = 100
fire_sound = 'sound/weapons/Taser.ogg'
user << "\red \The [src] is now set to stun."
projectile_type = /obj/item/projectile/beam/stun
if(0)
mode = 1
charge_cost = 100
fire_sound = 'sound/weapons/Laser.ogg'
user << "\red \The [src] is now set to kill."
projectile_type = /obj/item/projectile/beam
if(1)
mode = 2
charge_cost = 200
fire_sound = 'sound/weapons/pulse.ogg'
user << "\red \The [name] is now set to DESTROY."
projectile_type = /obj/item/projectile/beam/pulse
return
isHandgun()
return 0
/obj/item/weapon/gun/energy/pulse_rifle/cyborg/load_into_chamber()
if(in_chamber)
return 1
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
if(R && R.cell)
R.cell.use(charge_cost)
in_chamber = new/obj/item/projectile/beam(src)
return 1
return 0
/obj/item/weapon/gun/energy/pulse_rifle/attack_self(mob/living/user as mob)
switch(mode)
if(2)
mode = 0
charge_cost = 100
fire_sound = 'sound/weapons/Taser.ogg'
user << "<span class='warning'>[src.name] is now set to stun.</span>"
projectile_type = /obj/item/projectile/beam/stun
if(0)
mode = 1
charge_cost = 100
fire_sound = 'sound/weapons/Laser.ogg'
user << "<span class='warning'>[src.name] is now set to kill.</span>"
projectile_type = /obj/item/projectile/beam
if(1)
mode = 2
charge_cost = 200
fire_sound = 'sound/weapons/pulse.ogg'
user << "<span class='warning'>[src.name] is now set to DESTROY.</span>"
projectile_type = /obj/item/projectile/beam/pulse
/obj/item/weapon/gun/energy/pulse_rifle/mounted
self_recharge = 1
use_external_power = 1
/obj/item/weapon/gun/energy/pulse_rifle/destroyer
name = "pulse destroyer"
desc = "A heavy-duty, pulse-based energy weapon."
cell_type = "/obj/item/weapon/cell/infinite"
desc = "A heavy-duty, pulse-based energy weapon. Because of its complexity and cost, it is rarely seen in use except by specialists."
cell_type = /obj/item/weapon/cell/infinite
fire_delay = 10
attack_self(mob/living/user as mob)
user << "\red \The [src] has three settings, and they are all DESTROY."
/obj/item/weapon/gun/energy/pulse_rifle/destroyer/attack_self(mob/living/user as mob)
user << "<span class='warning'>[src.name] has three settings, and they are all DESTROY.</span>"
//WHY?
/obj/item/weapon/gun/energy/pulse_rifle/M1911
name = "\improper M1911-P"
desc = "It's not the size of the gun, it's the size of the hole it puts through people."
slot_flags = SLOT_BELT|SLOT_HOLSTER
icon_state = "m1911-p"
cell_type = "/obj/item/weapon/cell/infinite"
cell_type = /obj/item/weapon/cell/infinite
fire_delay = 10
isHandgun()
return 1

View File

@@ -5,17 +5,16 @@
fire_sound = 'sound/weapons/Laser.ogg'
origin_tech = "combat=2;magnets=4"
w_class = 4.0
force = 10
flags = CONDUCT
slot_flags = SLOT_BACK
charge_cost = 100
projectile_type = "/obj/item/projectile/ion"
projectile_type = /obj/item/projectile/ion
/obj/item/weapon/gun/energy/ionrifle/emp_act(severity)
if(severity <= 2)
power_supply.use(round(power_supply.maxcharge / severity))
update_icon()
else
return
if(severity > 2)
return //so it doesn't EMP itself, I guess
..()
/obj/item/weapon/gun/energy/decloner
name = "biological demolecularisor"
@@ -24,9 +23,89 @@
fire_sound = 'sound/weapons/pulse3.ogg'
origin_tech = "combat=5;materials=4;powerstorage=3"
charge_cost = 100
projectile_type = "/obj/item/projectile/energy/declone"
projectile_type = /obj/item/projectile/energy/declone
obj/item/weapon/gun/energy/staff
/obj/item/weapon/gun/energy/floragun
name = "floral somatoray"
desc = "A tool that discharges controlled radiation which induces mutation in plant cells."
icon_state = "floramut100"
item_state = "obj/item/gun.dmi"
fire_sound = 'sound/effects/stealthoff.ogg'
charge_cost = 100
projectile_type = /obj/item/projectile/energy/floramut
origin_tech = "materials=2;biotech=3;powerstorage=3"
modifystate = "floramut"
self_recharge = 1
var/mode = 0 //0 = mutate, 1 = yield boost
/obj/item/weapon/gun/energy/floragun/attack_self(mob/living/user as mob)
switch(mode)
if(0)
mode = 1
charge_cost = 100
user << "<span class='warning'>The [src.name] is now set to increase yield.</span>"
projectile_type = /obj/item/projectile/energy/florayield
modifystate = "florayield"
if(1)
mode = 0
charge_cost = 100
user << "<span class='warning'>The [src.name] is now set to induce mutations.</span>"
projectile_type = /obj/item/projectile/energy/floramut
modifystate = "floramut"
update_icon()
return
/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, adjacent_flag)
//allow shooting into adjacent hydrotrays regardless of intent
if(adjacent_flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics))
user.visible_message("<span class='danger'>\The [user] fires \the [src] into \the [target]!</span>")
Fire(target,user)
return
..()
/obj/item/weapon/gun/energy/meteorgun
name = "meteor gun"
desc = "For the love of god, make sure you're aiming this the right way!"
icon_state = "riotgun"
item_state = "c20r"
slot_flags = SLOT_BELT|SLOT_BACK
w_class = 4
projectile_type = /obj/item/projectile/meteor
charge_cost = 100
cell_type = /obj/item/weapon/cell/potato
self_recharge = 1
recharge_time = 5 //Time it takes for shots to recharge (in ticks)
charge_meter = 0
/obj/item/weapon/gun/energy/meteorgun/pen
name = "meteor pen"
desc = "The pen is mightier than the sword."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "pen"
item_state = "pen"
w_class = 1
slot_flags = SLOT_BELT
/obj/item/weapon/gun/energy/mindflayer
name = "mind flayer"
desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon."
icon_state = "xray"
projectile_type = /obj/item/projectile/beam/mindflayer
fire_sound = 'sound/weapons/Laser.ogg'
/obj/item/weapon/gun/energy/toxgun
name = "phoron pistol"
desc = "A specialized firearm designed to fire lethal bolts of phoron."
icon_state = "toxgun"
fire_sound = 'sound/effects/stealthoff.ogg'
w_class = 3.0
origin_tech = "combat=5;phorontech=4"
projectile_type = /obj/item/projectile/energy/phoron
/* Staves */
/obj/item/weapon/gun/energy/staff
name = "staff of change"
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself"
icon = 'icons/obj/gun.dmi'
@@ -37,209 +116,51 @@ obj/item/weapon/gun/energy/staff
slot_flags = SLOT_BACK
w_class = 4.0
charge_cost = 200
projectile_type = "/obj/item/projectile/change"
projectile_type = /obj/item/projectile/change
origin_tech = null
clumsy_check = 0
var/charge_tick = 0
self_recharge = 1
charge_meter = 0
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(200)
return 1
update_icon()
return
click_empty(mob/user = null)
if (user)
user.visible_message("*fizzle*", "\red <b>*fizzle*</b>")
else
src.visible_message("*fizzle*")
playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1)
/obj/item/weapon/gun/energy/staff/handle_click_empty(mob/user = null)
if (user)
user.visible_message("*fizzle*", "<span class='danger'>*fizzle*</span>")
else
src.visible_message("*fizzle*")
playsound(src.loc, 'sound/effects/sparks1.ogg', 100, 1)
/obj/item/weapon/gun/energy/staff/animate
name = "staff of animation"
desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines."
projectile_type = "/obj/item/projectile/animate"
projectile_type = /obj/item/projectile/animate
charge_cost = 100
/obj/item/weapon/gun/energy/floragun
name = "floral somatoray"
desc = "A tool that discharges controlled radiation which induces mutation in plant cells."
icon_state = "floramut100"
item_state = "obj/item/gun.dmi"
fire_sound = 'sound/effects/stealthoff.ogg'
charge_cost = 100
projectile_type = "/obj/item/projectile/energy/floramut"
origin_tech = "materials=2;biotech=3;powerstorage=3"
modifystate = "floramut"
var/charge_tick = 0
var/mode = 0 //0 = mutate, 1 = yield boost
/obj/item/weapon/gun/energy/floragun/New()
..()
processing_objects.Add(src)
/obj/item/weapon/gun/energy/floragun/Del()
processing_objects.Remove(src)
..()
/obj/item/weapon/gun/energy/floragun/process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(100)
update_icon()
return 1
/obj/item/weapon/gun/energy/floragun/attack_self(mob/living/user as mob)
switch(mode)
if(0)
mode = 1
charge_cost = 100
user << "\red The [src.name] is now set to increase yield."
projectile_type = "/obj/item/projectile/energy/florayield"
modifystate = "florayield"
if(1)
mode = 0
charge_cost = 100
user << "\red The [src.name] is now set to induce mutations."
projectile_type = "/obj/item/projectile/energy/floramut"
modifystate = "floramut"
update_icon()
return
/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, flag)
if(flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics))
var/obj/machinery/portable_atmospherics/hydroponics/tray = target
if(load_into_chamber())
user.visible_message("\red <b> \The [user] fires \the [src] into \the [tray]!</b>")
Fire(target,user)
return
..()
/obj/item/weapon/gun/energy/meteorgun
name = "meteor gun"
desc = "For the love of god, make sure you're aiming this the right way!"
icon_state = "riotgun"
item_state = "c20r"
w_class = 4
projectile_type = "/obj/item/projectile/meteor"
charge_cost = 100
cell_type = "/obj/item/weapon/cell/potato"
clumsy_check = 0 //Admin spawn only, might as well let clowns use it.
var/charge_tick = 0
var/recharge_time = 5 //Time it takes for shots to recharge (in ticks)
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process()
charge_tick++
if(charge_tick < recharge_time) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(100)
update_icon()
return
/obj/item/weapon/gun/energy/meteorgun/pen
name = "meteor pen"
desc = "The pen is mightier than the sword."
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "pen"
item_state = "pen"
w_class = 1
/obj/item/weapon/gun/energy/mindflayer
name = "mind flayer"
desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon."
icon_state = "xray"
projectile_type = "/obj/item/projectile/beam/mindflayer"
fire_sound = 'sound/weapons/Laser.ogg'
obj/item/weapon/gun/energy/staff/focus
name = "mental focus"
desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out."
icon = 'icons/obj/wizard.dmi'
icon_state = "focus"
item_state = "focus"
projectile_type = "/obj/item/projectile/forcebolt"
slot_flags = SLOT_BACK
projectile_type = /obj/item/projectile/forcebolt
/*
attack_self(mob/living/user as mob)
if(projectile_type == "/obj/item/projectile/forcebolt")
charge_cost = 200
user << "\red The [src.name] will now strike a small area."
user << "<span class='warning'>The [src.name] will now strike a small area.</span>"
projectile_type = "/obj/item/projectile/forcebolt/strong"
else
charge_cost = 100
user << "\red The [src.name] will now strike only a single person."
user << "<span class='warning'>The [src.name] will now strike only a single person.</span>"
projectile_type = "/obj/item/projectile/forcebolt"
*/
/obj/item/weapon/gun/energy/toxgun
name = "phoron pistol"
desc = "A specialized firearm designed to fire lethal bolts of phoron."
icon_state = "toxgun"
fire_sound = 'sound/effects/stealthoff.ogg'
w_class = 3.0
origin_tech = "combat=5;phorontech=4"
projectile_type = "/obj/item/projectile/energy/phoron"
/obj/item/weapon/gun/energy/sniperrifle
name = "\improper L.W.A.P. sniper rifle"
desc = "A rifle constructed of lightweight materials, fitted with a SMART aiming-system scope."
icon = 'icons/obj/gun.dmi'
icon_state = "sniper"
fire_sound = 'sound/weapons/marauder.ogg'
origin_tech = "combat=6;materials=5;powerstorage=4"
projectile_type = "/obj/item/projectile/beam/sniper"
slot_flags = SLOT_BACK
charge_cost = 250
fire_delay = 35
w_class = 4.0
zoomdevicename = "scope"
/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
set category = "Object"
set name = "Use Scope"
set popup_menu = 1
zoom()
/* Adminbus guns */
// Serves as a target spotter for the Icarus.
/obj/item/weapon/gun/energy/icarus
name = "rubber ducky"
desc = "It's a cute rubber duck. With an evil gleam in it's eye."
projectile_type = "/obj/item/projectile/icarus/pointdefense"
projectile_type = /obj/item/projectile/icarus/pointdefense
icon = 'icons/obj/watercloset.dmi'
icon_state = "rubberducky"
item_state = "rubberducky"
@@ -247,11 +168,11 @@ obj/item/weapon/gun/energy/staff/focus
silenced = 1
/obj/item/weapon/gun/energy/icarus/attack_self(mob/living/user as mob)
if(projectile_type == "/obj/item/projectile/icarus/pointdefense")
projectile_type = "/obj/item/projectile/icarus/guns"
if(projectile_type == /obj/item/projectile/icarus/pointdefense)
projectile_type = /obj/item/projectile/icarus/guns
user << "You inform the Icarus to switch to the main guns."
else
projectile_type = "/obj/item/projectile/icarus/pointdefense"
projectile_type = /obj/item/projectile/icarus/pointdefense
user << "You inform the Icarus to switch to the point-defense lasers."
. = ..()
@@ -281,5 +202,5 @@ obj/item/weapon/gun/energy/staff/focus
var/type = input(user,"What projectile type?","Projectile", null) as null|anything in typesof(/obj/item/projectile)
if(!type)
return ..()
projectile_type = type
. = ..()

View File

@@ -6,50 +6,26 @@
fire_sound = 'sound/weapons/Taser.ogg'
charge_cost = 100
projectile_type = /obj/item/projectile/beam/stun
cell_type = "/obj/item/weapon/cell/crap"
cell_type = /obj/item/weapon/cell/crap
/obj/item/weapon/gun/energy/taser/cyborg
cell_type = "/obj/item/weapon/cell/secborg"
var/charge_tick = 0
var/recharge_time = 10 //Time it takes for shots to recharge (in ticks)
/obj/item/weapon/gun/energy/taser/mounted
self_recharge = 1
use_external_power = 1
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process() //Every [recharge_time] ticks, recharge a shot for the cyborg
charge_tick++
if(charge_tick < recharge_time) return 0
charge_tick = 0
if(!power_supply) return 0 //sanity
if(power_supply.charge >= power_supply.maxcharge) return 0 // check if we actually need to recharge
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
if(R && R.cell)
R.cell.use(charge_cost) //Take power from the borg...
power_supply.give(charge_cost) //... to recharge the shot
update_icon()
return 1
/obj/item/weapon/gun/energy/taser/mounted/cyborg
cell_type = /obj/item/weapon/cell/secborg
recharge_time = 10 //Time it takes for shots to recharge (in ticks)
/obj/item/weapon/gun/energy/stunrevolver
name = "stun revolver"
desc = "A high-tech revolver that fires stun cartridges. The stun cartridges can be recharged using a conventional energy weapon recharger."
icon_state = "stunrevolver"
fire_sound = 'sound/weapons/Taser.ogg'
fire_sound = 'sound/weapons/Gunshot.ogg'
origin_tech = "combat=3;materials=3;powerstorage=2"
charge_cost = 125
projectile_type = /obj/item/projectile/beam/stun
cell_type = "/obj/item/weapon/cell"
projectile_type = /obj/item/projectile/energy/electrode/stunshot
cell_type = /obj/item/weapon/cell
/obj/item/weapon/gun/energy/crossbow
@@ -60,43 +36,22 @@
item_state = "crossbow"
matter = list("metal" = 2000)
origin_tech = "combat=2;magnets=2;syndicate=5"
slot_flags = SLOT_BELT
silenced = 1
fire_sound = 'sound/weapons/Genhit.ogg'
projectile_type = /obj/item/projectile/energy/bolt
cell_type = "/obj/item/weapon/cell/crap"
var/charge_tick = 0
New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
process()
charge_tick++
if(charge_tick < 4) return 0
charge_tick = 0
if(!power_supply) return 0
power_supply.give(100)
return 1
update_icon()
return
cell_type = /obj/item/weapon/cell/crap
self_recharge = 1
charge_meter = 0
/obj/item/weapon/gun/energy/crossbow/ninja
name = "energy dart thrower"
projectile_type = /obj/item/projectile/energy/dart
/obj/item/weapon/gun/energy/crossbow/largecrossbow
name = "Energy Crossbow"
name = "energy crossbow"
desc = "A weapon favored by mercenary infiltration teams."
w_class = 4.0
w_class = 4
force = 10
matter = list("metal" = 200000)
projectile_type = /obj/item/projectile/energy/bolt/large

View File

@@ -7,74 +7,73 @@
var/current_temperature = T20C
charge_cost = 100
origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2"
slot_flags = SLOT_BELT|SLOT_BACK
projectile_type = "/obj/item/projectile/temp"
cell_type = "/obj/item/weapon/cell/crap"
projectile_type = /obj/item/projectile/temp
cell_type = /obj/item/weapon/cell/crap
New()
..()
processing_objects.Add(src)
/obj/item/weapon/gun/energy/temperature/New()
..()
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
/obj/item/weapon/gun/energy/temperature/Del()
processing_objects.Remove(src)
..()
attack_self(mob/living/user as mob)
user.set_machine(src)
var/temp_text = ""
if(temperature > (T0C - 50))
temp_text = "<FONT color=black>[temperature] ([round(temperature-T0C)]&deg;C) ([round(temperature*1.8-459.67)]&deg;F)</FONT>"
/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob)
user.set_machine(src)
var/temp_text = ""
if(temperature > (T0C - 50))
temp_text = "<FONT color=black>[temperature] ([round(temperature-T0C)]&deg;C) ([round(temperature*1.8-459.67)]&deg;F)</FONT>"
else
temp_text = "<FONT color=blue>[temperature] ([round(temperature-T0C)]&deg;C) ([round(temperature*1.8-459.67)]&deg;F)</FONT>"
var/dat = {"<B>Freeze Gun Configuration: </B><BR>
Current output temperature: [temp_text]<BR>
Target output temperature: <A href='?src=\ref[src];temp=-100'>-</A> <A href='?src=\ref[src];temp=-10'>-</A> <A href='?src=\ref[src];temp=-1'>-</A> [current_temperature] <A href='?src=\ref[src];temp=1'>+</A> <A href='?src=\ref[src];temp=10'>+</A> <A href='?src=\ref[src];temp=100'>+</A><BR>
"}
user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1")
onclose(user, "window=freezegun", src)
/obj/item/weapon/gun/energy/temperature/Topic(href, href_list)
if (..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
src.current_temperature = min(500, src.current_temperature+amount)
else
temp_text = "<FONT color=blue>[temperature] ([round(temperature-T0C)]&deg;C) ([round(temperature*1.8-459.67)]&deg;F)</FONT>"
var/dat = {"<B>Freeze Gun Configuration: </B><BR>
Current output temperature: [temp_text]<BR>
Target output temperature: <A href='?src=\ref[src];temp=-100'>-</A> <A href='?src=\ref[src];temp=-10'>-</A> <A href='?src=\ref[src];temp=-1'>-</A> [current_temperature] <A href='?src=\ref[src];temp=1'>+</A> <A href='?src=\ref[src];temp=10'>+</A> <A href='?src=\ref[src];temp=100'>+</A><BR>
"}
src.current_temperature = max(0, src.current_temperature+amount)
if (istype(src.loc, /mob))
attack_self(src.loc)
src.add_fingerprint(usr)
return
user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1")
onclose(user, "window=freezegun", src)
/obj/item/weapon/gun/energy/temperature/process()
switch(temperature)
if(0 to 100) charge_cost = 1000
if(100 to 250) charge_cost = 500
if(251 to 300) charge_cost = 100
if(301 to 400) charge_cost = 500
if(401 to 500) charge_cost = 1000
Topic(href, href_list)
if (..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
src.current_temperature = min(500, src.current_temperature+amount)
if(current_temperature != temperature)
var/difference = abs(current_temperature - temperature)
if(difference >= 10)
if(current_temperature < temperature)
temperature -= 10
else
src.current_temperature = max(0, src.current_temperature+amount)
if (istype(src.loc, /mob))
attack_self(src.loc)
src.add_fingerprint(usr)
return
process()
switch(temperature)
if(0 to 100) charge_cost = 1000
if(100 to 250) charge_cost = 500
if(251 to 300) charge_cost = 100
if(301 to 400) charge_cost = 500
if(401 to 500) charge_cost = 1000
if(current_temperature != temperature)
var/difference = abs(current_temperature - temperature)
if(difference >= 10)
if(current_temperature < temperature)
temperature -= 10
else
temperature += 10
else
temperature = current_temperature
return
temperature += 10
else
temperature = current_temperature

View File

@@ -0,0 +1,31 @@
/obj/item/weapon/gun/launcher
name = "launcher"
desc = "A device that launches things."
w_class = 5.0
flags = CONDUCT
slot_flags = SLOT_BACK
var/release_force = 0
var/throw_distance = 10
fire_sound_text = "a launcher firing"
//This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile.
/obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
return 1
//Override this to avoid a runtime with suicide handling.
/obj/item/weapon/gun/launcher/handle_suicide(mob/living/user)
user << "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it."
return
/obj/item/weapon/gun/launcher/proc/update_release_force(obj/item/projectile)
return 0
/obj/item/weapon/gun/launcher/process_projectile(obj/item/projectile, mob/user, atom/target, var/target_zone, var/params=null, var/pointblank=0, var/reflex=0)
update_release_force(projectile)
projectile.loc = get_turf(user)
projectile.throw_at(target, throw_distance, release_force, user)
return 1
/obj/item/weapon/gun/launcher/attack_self(mob/living/user as mob)
return

View File

@@ -48,46 +48,43 @@
/obj/item/weapon/gun/launcher/crossbow
name = "powered crossbow"
desc = "A 2557AD twist on an old classic. Pick up that can."
icon = 'icons/obj/weapons.dmi'
icon_state = "crossbow"
item_state = "crossbow-solid"
fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise.
ejectshell = 0 // No spent shells.
mouthshoot = 1 // No suiciding with this weapon, causes runtimes.
fire_sound_text = "a solid thunk"
fire_delay = 25
slot_flags = SLOT_BACK
var/obj/item/bolt
var/tension = 0 // Current draw on the bow.
var/max_tension = 5 // Highest possible tension.
var/release_speed = 5 // Speed per unit of tension.
var/obj/item/weapon/cell/cell = null // Used for firing superheated rods.
var/current_user // Used to check if the crossbow has changed hands since being drawn.
/obj/item/weapon/gun/launcher/crossbow/emp_act(severity)
if(cell && severity)
cell.use(100*severity)
/obj/item/weapon/gun/launcher/crossbow/special_check(user)
if(tension <= 0)
user << "\red \The [src] is not drawn back!"
return 0
return 1
/obj/item/weapon/gun/launcher/crossbow/update_release_force()
release_force = tension*release_speed
/obj/item/weapon/gun/launcher/crossbow/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
/obj/item/weapon/gun/launcher/crossbow/consume_next_projectile(mob/user=null)
if(tension <= 0)
user << "\red \The [src] is not drawn back!"
return null
return bolt
if(!..()) return //Only do this on a successful shot.
/obj/item/weapon/gun/launcher/crossbow/handle_post_fire(mob/user, atom/target)
bolt = null
icon_state = "crossbow"
tension = 0
..()
/obj/item/weapon/gun/launcher/crossbow/attack_self(mob/living/user as mob)
if(tension)
if(in_chamber && in_chamber.loc == src) //Just in case they click it the tick after firing.
user.visible_message("[user] relaxes the tension on [src]'s string and removes [in_chamber].","You relax the tension on [src]'s string and remove [in_chamber].")
in_chamber.loc = get_turf(src)
var/obj/item/weapon/arrow/A = in_chamber
in_chamber = null
if(bolt)
user.visible_message("[user] relaxes the tension on [src]'s string and removes [bolt].","You relax the tension on [src]'s string and remove [bolt].")
bolt.loc = get_turf(src)
var/obj/item/weapon/arrow/A = bolt
bolt = null
A.removed(user)
else
user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.")
@@ -98,7 +95,7 @@
/obj/item/weapon/gun/launcher/crossbow/proc/draw(var/mob/user as mob)
if(!in_chamber)
if(!bolt)
user << "You don't have anything nocked to [src]."
return
@@ -106,50 +103,57 @@
return
current_user = user
user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].")
user.visible_message("[user] begins to draw back the string of [src].","<span class='notice'>You begin to draw back the string of [src].</span>")
tension = 1
spawn(25) increase_tension(user) //TODO: This needs to be changed to something less shit.
while(bolt && tension && current_user == user)
if(!do_after(user, 25)) //crossbow strings don't just magically pull back on their own.
user.visible_message("[usr] stops drawing and relaxes the string of [src].","<span class='warning'>You stop drawing back and relax the string of [src].</span>")
tension = 0
icon_state = "crossbow"
return
tension++
icon_state = "crossbow-drawn"
if(tension >= max_tension)
tension = max_tension
usr << "[src] clunks as you draw the string to its maximum tension!"
return
user.visible_message("[usr] draws back the string of [src]!","<span class='notice'>You continue drawing back the string of [src]!</span>")
/obj/item/weapon/gun/launcher/crossbow/proc/increase_tension(var/mob/user as mob)
if(!in_chamber || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed.
if(!bolt || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed.
return
tension++
icon_state = "crossbow-drawn"
if(tension>=max_tension)
tension = max_tension
usr << "[src] clunks as you draw the string to its maximum tension!"
else
user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!")
spawn(25) increase_tension(user)
/obj/item/weapon/gun/launcher/crossbow/attackby(obj/item/W as obj, mob/user as mob)
if(!in_chamber)
if(!bolt)
if (istype(W,/obj/item/weapon/arrow))
user.drop_item()
in_chamber = W
in_chamber.loc = src
user.visible_message("[user] slides [in_chamber] into [src].","You slide [in_chamber] into [src].")
bolt = W
bolt.loc = src
user.visible_message("[user] slides [bolt] into [src].","You slide [bolt] into [src].")
icon_state = "crossbow-nocked"
return
else if(istype(W,/obj/item/stack/rods))
var/obj/item/stack/rods/R = W
if (R.use(1))
in_chamber = new /obj/item/weapon/arrow/rod(src)
in_chamber.fingerprintslast = src.fingerprintslast
in_chamber.loc = src
bolt = new /obj/item/weapon/arrow/rod(src)
bolt.fingerprintslast = src.fingerprintslast
bolt.loc = src
icon_state = "crossbow-nocked"
user.visible_message("[user] jams [in_chamber] into [src].","You jam [in_chamber] into [src].")
user.visible_message("[user] jams [bolt] into [src].","You jam [bolt] into [src].")
superheat_rod(user)
return
if(istype(W, /obj/item/weapon/cell))
if(!cell)
user.drop_item()
W.loc = src
cell = W
cell.loc = src
user << "<span class='notice'>You jam [cell] into [src] and wire it to the firing coil.</span>"
superheat_rod(user)
else
@@ -168,14 +172,14 @@
..()
/obj/item/weapon/gun/launcher/crossbow/proc/superheat_rod(var/mob/user)
if(!user || !cell || !in_chamber) return
if(!user || !cell || !bolt) return
if(cell.charge < 500) return
if(in_chamber.throwforce >= 15) return
if(!istype(in_chamber,/obj/item/weapon/arrow/rod)) return
if(bolt.throwforce >= 15) return
if(!istype(bolt,/obj/item/weapon/arrow/rod)) return
user << "<span class='notice'>[in_chamber] plinks and crackles as it begins to glow red-hot.</span>"
in_chamber.throwforce = 15
in_chamber.icon_state = "metal-rod-superheated"
user << "<span class='notice'>[bolt] plinks and crackles as it begins to glow red-hot.</span>"
bolt.throwforce = 15
bolt.icon_state = "metal-rod-superheated"
cell.use(500)

View File

@@ -0,0 +1,81 @@
/obj/item/weapon/gun/launcher/grenade
name = "grenade launcher"
desc = "A bulky pump-action grenade launcher. Holds up to 5 grenades in a revolving magazine."
icon_state = "riotgun"
item_state = "riotgun"
w_class = 4
force = 10
fire_sound = 'sound/weapons/empty.ogg'
fire_sound_text = "a metallic thunk"
recoil = 0
throw_distance = 7
release_force = 5
var/obj/item/weapon/grenade/chambered
var/list/grenades = new/list()
var/max_grenades = 4 //holds this + one in the chamber
matter = list("metal" = 2000)
//revolves the magazine, allowing players to choose between multiple grenade types
/obj/item/weapon/gun/launcher/grenade/proc/pump(mob/M as mob)
playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1)
var/obj/item/weapon/grenade/next
if(grenades.len)
next = grenades[1] //get this first, so that the chambered grenade can still be removed if the grenades list is empty
if(chambered)
grenades += chambered //rotate the revolving magazine
chambered = null
if(next)
grenades -= next //Remove grenade from loaded list.
chambered = next
M << "<span class='warning'>You pump [src], loading \a [next] into the chamber.</span>"
else
M << "<span class='warning'>You pump [src], but the magazine is empty.</span>"
update_icon()
/obj/item/weapon/gun/launcher/grenade/examine(mob/user)
if(..(user, 2))
var/grenade_count = grenades.len + (chambered? 1 : 0)
user << "Has [grenade_count] grenade\s remaining."
if(chambered)
user << "\A [chambered] is chambered."
/obj/item/weapon/gun/launcher/grenade/attack_self(mob/user)
pump(user)
/obj/item/weapon/gun/launcher/grenade/attackby(obj/item/I, mob/user)
if((istype(I, /obj/item/weapon/grenade)))
if(grenades.len >= max_grenades)
user << "<span class='warning'>[src] is full.</span>"
return
user.remove_from_mob(I)
I.loc = src
grenades.Insert(1, I) //add to the head of the list, so that it is loaded on the next pump
user.visible_message("[user] inserts \a [I] into [src].", "<span class='notice'>You insert \a [I] into [src].</span>")
else
..()
/obj/item/weapon/gun/launcher/grenade/attack_hand(mob/user)
if(user.get_inactive_hand() == src)
if(grenades.len)
var/obj/item/weapon/grenade/G = grenades[grenades.len]
grenades.len--
user.put_in_hands(G)
user.visible_message("[user] removes \a [G] from [src].", "<span class='notice'>You remove \a [G] from [src].</span>")
else
user << "<span class='warning'>[src] is empty.</span>"
else
..()
/obj/item/weapon/gun/launcher/grenade/consume_next_projectile()
if(chambered)
chambered.det_time = 10
chambered.activate(null)
return chambered
/obj/item/weapon/gun/launcher/grenade/handle_post_fire(mob/user)
message_admins("[key_name_admin(user)] fired a grenade ([chambered.name]) from a grenade launcher ([src.name]).")
log_game("[key_name_admin(user)] used a grenade ([chambered.name]).")
chambered = null

View File

@@ -1,9 +1,9 @@
/obj/item/weapon/gun/launcher/pneumatic
name = "pneumatic cannon"
desc = "A large gas-powered cannon."
icon = 'icons/obj/gun.dmi'
icon_state = "pneumatic"
item_state = "pneumatic"
slot_flags = SLOT_BELT
w_class = 5.0
flags = CONDUCT
fire_sound_text = "a loud whoosh of moving air"
@@ -61,8 +61,7 @@
icon_state = "pneumatic-tank"
item_state = "pneumatic-tank"
user.update_icons()
else if(W.w_class <= max_w_class)
else if(istype(W) && W.w_class <= max_w_class)
var/total_stored = 0
for(var/obj/item/O in src.contents)
total_stored += O.w_class
@@ -79,9 +78,6 @@
/obj/item/weapon/gun/launcher/pneumatic/attack_self(mob/user as mob)
if(contents.len > 0)
var/obj/item/removing = contents[contents.len]
if(removing == in_chamber)
in_chamber = null
removing.loc = get_turf(src)
user.put_in_hands(removing)
user << "You remove [removing] from the hopper."
@@ -89,12 +85,19 @@
user << "There is nothing to remove in \the [src]."
return
/obj/item/weapon/gun/launcher/pneumatic/load_into_chamber()
/obj/item/weapon/gun/launcher/pneumatic/consume_next_projectile(mob/user=null)
if(!contents.len)
return 0
return null
if (!tank)
user << "There is no gas tank in [src]!"
return null
in_chamber = contents[1]
return !isnull(in_chamber)
var/fire_pressure = (tank.air_contents.return_pressure()/100)*pressure_setting
if(fire_pressure < minimum_tank_pressure)
user << "There isn't enough gas in the tank to fire [src]."
return null
return contents[1]
/obj/item/weapon/gun/launcher/pneumatic/examine(mob/user)
if(!..(user, 2))
@@ -105,31 +108,21 @@
else
user << "Nothing is attached to the tank valve!"
/obj/item/weapon/gun/launcher/pneumatic/special_check(user)
/obj/item/weapon/gun/launcher/pneumatic/update_release_force(obj/item/projectile)
if(tank)
release_force = ((fire_pressure*tank.volume)/projectile.w_class)/force_divisor //projectile speed.
if(release_force > 80) release_force = 80 //damage cap.
else
release_force = 0
if (!tank)
user << "There is no gas tank in [src]!"
return 0
fire_pressure = (tank.air_contents.return_pressure()/100)*pressure_setting
if (fire_pressure < minimum_tank_pressure)
user << "There isn't enough gas in the tank to fire [src]."
return 0
return 1
/obj/item/weapon/gun/launcher/pneumatic/update_release_force()
if(!in_chamber) return
release_force = ((fire_pressure*tank.volume)/in_chamber.w_class)/force_divisor //projectile speed.
if(release_force >80) release_force = 80 //damage cap.
/obj/item/weapon/gun/launcher/pneumatic/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
if(!tank || !..()) return //Only do this on a successful shot.
var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100)
var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount)
user.loc.assume_air(removed)
/obj/item/weapon/gun/launcher/pneumatic/handle_post_fire()
if(tank)
var/lost_gas_amount = tank.air_contents.total_moles*(pressure_setting/100)
var/datum/gas_mixture/removed = tank.air_contents.remove(lost_gas_amount)
var/turf/T = get_turf(src.loc)
if(T) T.assume_air(removed)
..()
//Constructable pneumatic cannon.

View File

@@ -0,0 +1,48 @@
/obj/item/weapon/gun/launcher/rocket
name = "rocket launcher"
desc = "MAGGOT."
icon_state = "rocket"
item_state = "rocket"
w_class = 4.0
throw_speed = 2
throw_range = 10
force = 5.0
flags = CONDUCT | USEDELAY
slot_flags = 0
origin_tech = "combat=8;materials=5"
fire_sound = 'sound/effects/bang.ogg'
release_force = 15
throw_distance = 30
var/max_rockets = 1
var/list/rockets = new/list()
/obj/item/weapon/gun/launcher/rocket/examine(mob/user)
if(!..(user, 2))
return
user << "\blue [rockets.len] / [max_rockets] rockets."
/obj/item/weapon/gun/launcher/rocket/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/ammo_casing/rocket))
if(rockets.len < max_rockets)
user.drop_item()
I.loc = src
rockets += I
user << "\blue You put the rocket in [src]."
user << "\blue [rockets.len] / [max_rockets] rockets."
else
usr << "\red [src] cannot hold more rockets."
/obj/item/weapon/gun/launcher/rocket/consume_next_projectile()
if(rockets.len)
var/obj/item/ammo_casing/rocket/I = rockets[1]
var/obj/item/missile/M = new (src)
M.primed = 1
rockets -= I
return M
return null
/obj/item/weapon/gun/launcher/rocket/handle_post_fire(mob/user, atom/target)
message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]) at [target].")
log_game("[key_name_admin(user)] used a rocket launcher ([src.name]) at [target].")
..()

View File

@@ -0,0 +1,136 @@
/obj/item/weapon/syringe_cartridge
name = "syringe gun cartridge"
desc = "An impact-triggered compressed gas cartridge that can be fitted to a syringe for rapid injection."
icon = 'icons/obj/ammo.dmi'
icon_state = "syringe-cartridge"
var/icon_flight = "syringe-cartridge-flight" //so it doesn't look so weird when shot
matter = list("metal" = 125, "glass" = 375)
flags = CONDUCT
slot_flags = SLOT_BELT
throwforce = 3
force = 3
w_class = 1
var/obj/item/weapon/reagent_containers/syringe/syringe
/obj/item/weapon/syringe_cartridge/update_icon()
underlays.Cut()
if(syringe)
underlays += image(syringe.icon, src, syringe.icon_state)
underlays += syringe.filling
/obj/item/weapon/syringe_cartridge/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/weapon/reagent_containers/syringe))
syringe = I
user << "<span class='notice'>You carefully insert [syringe] into [src].</span>"
user.remove_from_mob(syringe)
syringe.loc = src
sharp = 1
name = "syringe dart"
update_icon()
/obj/item/weapon/syringe_cartridge/attack_self(mob/user)
if(syringe)
user << "<span class='notice'>You remove [syringe] from [src].</span>"
user.put_in_hands(syringe)
syringe = null
sharp = initial(sharp)
name = initial(name)
update_icon()
/obj/item/weapon/syringe_cartridge/proc/prime()
//the icon state will revert back when update_icon() is called from throw_impact()
icon_state = icon_flight
underlays.Cut()
/obj/item/weapon/syringe_cartridge/throw_impact(atom/hit_atom, var/speed)
..() //handles embedding for us. Should have a decent chance if thrown fast enough
if(syringe)
//check speed to see if we hit hard enough to trigger the rapid injection
//incidentally, this means syringe_cartridges can be used with the pneumatic launcher
if(speed >= 10 && isliving(hit_atom))
var/mob/living/L = hit_atom
//unfortuately we don't know where the dart will actually hit, since that's done by the parent.
if(L.can_inject())
if(syringe.reagents)
syringe.reagents.trans_to(L, 15)
syringe.break_syringe(iscarbon(hit_atom)? hit_atom : null)
syringe.update_icon()
icon_state = initial(icon_state) //reset icon state
update_icon()
/obj/item/weapon/gun/launcher/syringe
name = "syringe gun"
desc = "A spring loaded rifle designed to fit syringes, designed to incapacitate unruly patients from a distance."
icon_state = "syringegun"
item_state = "syringegun"
w_class = 3
force = 7
matter = list("metal" = 2000)
slot_flags = SLOT_BELT
fire_sound = 'sound/weapons/empty.ogg'
fire_sound_text = "a metallic thunk"
recoil = 0
release_force = 10
throw_distance = 10
var/list/darts = list()
var/max_darts = 1
var/obj/item/weapon/syringe_cartridge/next
/obj/item/weapon/gun/launcher/syringe/consume_next_projectile()
if(next)
next.prime()
return next
return null
/obj/item/weapon/gun/launcher/syringe/handle_post_fire()
..()
darts -= next
next = null
/obj/item/weapon/gun/launcher/syringe/attack_self(mob/living/user as mob)
if(next)
user.visible_message("[user] unlatches and carefully relaxes the bolt on [src].", "<span class='warning'>You unlatch and carefully relax the bolt on [src], unloading the spring.</span>")
next = null
else if(darts.len)
playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
user.visible_message("[user] draws back the bolt on [src], clicking it into place.", "<span class='warning'>You draw back the bolt on the [src], loading the spring!</span>")
next = darts[1]
add_fingerprint(user)
/obj/item/weapon/gun/launcher/syringe/attack_hand(mob/living/user as mob)
if(user.get_inactive_hand() == src)
if(!darts.len)
user << "<span class='warning'>[src] is empty.</span>"
return
if(next)
user << "<span class='warning'>[src]'s cover is locked shut.</span>"
return
var/obj/item/weapon/syringe_cartridge/C = darts[1]
darts -= C
user.put_in_hands(C)
user.visible_message("[user] removes \a [C] from [src].", "<span class='notice'>You remove \a [C] from [src].</span>")
else
..()
/obj/item/weapon/gun/launcher/syringe/attackby(var/obj/item/A as obj, mob/user as mob)
if(istype(A, /obj/item/weapon/syringe_cartridge))
var/obj/item/weapon/syringe_cartridge/C = A
if(darts.len >= max_darts)
user << "<span class='warning'>[src] is full!</span>"
return
user.remove_from_mob(C)
C.loc = src
darts += C //add to the end
user.visible_message("[user] inserts \a [C] into [src].", "<span class='notice'>You insert \a [C] into [src].</span>")
else
..()
/obj/item/weapon/gun/launcher/syringe/rapid
name = "syringe gun revolver"
desc = "A modification of the syringe gun design, using a rotating cylinder to store up to five syringes. The spring still needs to be drawn between shots."
icon_state = "rapidsyringegun"
max_darts = 5

View File

@@ -1,121 +1,205 @@
#define SPEEDLOADER 0
#define FROM_BOX 1
#define MAGAZINE 2
#define HOLD_CASINGS 0 //do not do anything after firing. Manual action, like pump shotguns, or guns that want to define custom behaviour
#define EJECT_CASINGS 1 //drop spent casings on the ground after firing
#define CYCLE_CASINGS 2 //experimental: cycle casings, like a revolver. Also works for multibarrelled guns
/obj/item/weapon/gun/projectile
name = "revolver"
desc = "A classic revolver. Uses .357 ammo"
name = "gun"
desc = "A gun that fires bullets."
icon_state = "revolver"
caliber = "357"
origin_tech = "combat=2;materials=2"
w_class = 3.0
w_class = 3
matter = list("metal" = 1000)
recoil = 1
var/ammo_type = "/obj/item/ammo_casing/a357"
var/list/loaded = list()
var/max_shells = 7
var/load_method = SPEEDLOADER //0 = Single shells or quick loader, 1 = box, 2 = magazine
var/obj/item/ammo_magazine/empty_mag = null
var/mag_type = null
var/caliber = "357" //determines which casings will fit
var/handle_casings = EJECT_CASINGS //determines how spent casings should be handled
var/load_method = SINGLE_CASING|SPEEDLOADER //1 = Single shells, 2 = box or quick loader, 3 = magazine
var/obj/item/ammo_casing/chambered = null
//For SINGLE_CASING or SPEEDLOADER guns
var/max_shells = 0 //the number of casings that will fit inside
var/ammo_type = null //the type of ammo that the gun comes preloaded with
var/list/loaded = list() //stored ammo
//For MAGAZINE guns
var/magazine_type = null //the type of magazine that the gun comes preloaded with
var/obj/item/ammo_magazine/ammo_magazine = null //stored magazine
var/auto_eject = 0 //if the magazine should automatically eject itself when empty.
var/auto_eject_sound = null
//TODO generalize ammo icon states for guns
//var/magazine_states = 0
//var/list/icon_keys = list() //keys
//var/list/ammo_states = list() //values
/obj/item/weapon/gun/projectile/New()
..()
for(var/i = 1, i <= max_shells, i++)
loaded += new ammo_type(src)
if(load_method == MAGAZINE)
empty_mag = new mag_type(src)
if(ispath(ammo_type) && (load_method & (SINGLE_CASING|SPEEDLOADER)))
for(var/i in 1 to max_shells)
loaded += new ammo_type(src)
if(ispath(magazine_type) && (load_method & MAGAZINE))
ammo_magazine = new magazine_type(src)
update_icon()
return
/obj/item/weapon/gun/projectile/consume_next_projectile()
//get the next casing
if(loaded.len)
chambered = loaded[1] //load next casing.
if(handle_casings != HOLD_CASINGS)
loaded -= chambered
else if(ammo_magazine && ammo_magazine.stored_ammo.len)
chambered = ammo_magazine.stored_ammo[1]
if(handle_casings != HOLD_CASINGS)
ammo_magazine.stored_ammo -= chambered
if (chambered)
return chambered.BB
return null
/obj/item/weapon/gun/projectile/handle_post_fire()
..()
if(chambered)
chambered.expend()
process_chambered()
/obj/item/weapon/gun/projectile/handle_click_empty()
..()
process_chambered()
/obj/item/weapon/gun/projectile/proc/process_chambered()
if (!chambered) return
switch(handle_casings)
if(EJECT_CASINGS) //eject casing onto ground.
chambered.loc = get_turf(src)
if(CYCLE_CASINGS) //cycle the casing back to the end.
if(ammo_magazine)
ammo_magazine.stored_ammo += chambered
else
loaded += chambered
if(handle_casings != HOLD_CASINGS)
chambered = null
/obj/item/weapon/gun/projectile/load_into_chamber()
if(in_chamber)
return 1 //{R}
//Attempts to load A into src, depending on the type of thing being loaded and the load_method
//Maybe this should be broken up into separate procs for each load method?
/obj/item/weapon/gun/projectile/proc/load_ammo(var/obj/item/A, mob/user)
if(istype(A, /obj/item/ammo_magazine))
var/obj/item/ammo_magazine/AM = A
if(!(load_method & AM.mag_type) || caliber != AM.caliber)
return //incompatible
if(!loaded.len)
return 0
var/obj/item/ammo_casing/AC = loaded[1] //load next casing.
loaded -= AC //Remove casing from loaded list.
if(isnull(AC) || !istype(AC))
return 0
AC.loc = get_turf(src) //Eject casing onto ground.
if(AC.BB)
in_chamber = AC.BB //Load projectile into chamber.
AC.BB.loc = src //Set projectile loc to gun.
return 1
return 0
switch(AM.mag_type)
if(MAGAZINE)
if(ammo_magazine)
user << "<span class='warning'>[src] already has a magazine loaded.</span>" //already a magazine here
return
user.remove_from_mob(AM)
AM.loc = src
ammo_magazine = AM
user.visible_message("[user] inserts [AM] into [src].", "<span class='notice'>You insert [AM] into [src].</span>")
playsound(src.loc, 'sound/weapons/flipblade.ogg', 50, 1)
if(SPEEDLOADER)
if(loaded.len >= max_shells)
user << "<span class='warning'>[src] is full!</span>"
return
var/count = 0
for(var/obj/item/ammo_casing/C in AM.stored_ammo)
if(loaded.len >= max_shells)
break
if(C.caliber == caliber)
C.loc = src
loaded += C
AM.stored_ammo -= C //should probably go inside an ammo_magazine proc, but I guess less proc calls this way...
count++
if(count)
user.visible_message("[user] reloads [src].", "<span class='notice'>You load [count] round\s into [src].</span>")
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
AM.update_icon()
else if(istype(A, /obj/item/ammo_casing))
var/obj/item/ammo_casing/C = A
if(!(load_method & SINGLE_CASING) || caliber != C.caliber)
return //incompatible
if(loaded.len >= max_shells)
user << "<span class='warning'>[src] is full.</span>"
return
user.remove_from_mob(C)
C.loc = src
loaded.Insert(1, C) //add to the head of the list
user.visible_message("[user] inserts \a [C] into [src].", "<span class='notice'>You insert \a [C] into [src].</span>")
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
update_icon()
//attempts to unload src. If allow_dump is set to 0, the speedloader unloading method will be disabled
/obj/item/weapon/gun/projectile/proc/unload_ammo(mob/user, var/allow_dump=1)
if(ammo_magazine)
user.put_in_hands(ammo_magazine)
user.visible_message("[user] removes [ammo_magazine] from [src].", "<span class='notice'>You remove [ammo_magazine] from [src].</span>")
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
ammo_magazine.update_icon()
ammo_magazine = null
else if(loaded.len)
//presumably, if it can be speed-loaded, it can be speed-unloaded.
if(allow_dump && (load_method & SPEEDLOADER))
var/count = 0
var/turf/T = get_turf(user)
if(T)
for(var/obj/item/ammo_casing/C in loaded)
C.loc = T
count++
loaded.Cut()
if(count)
user.visible_message("[user] unloads [src].", "<span class='notice'>You unload [count] round\s from [src].</span>")
else if(load_method & SINGLE_CASING)
var/obj/item/ammo_casing/C = loaded[loaded.len]
loaded.len--
user.put_in_hands(C)
user.visible_message("[user] removes \a [C] from [src].", "<span class='notice'>You remove \a [C] from [src].</span>")
else
user << "<span class='warning'>[src] is empty.</span>"
update_icon()
/obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob)
var/num_loaded = 0
if(istype(A, /obj/item/ammo_magazine))
if((load_method == MAGAZINE) && loaded.len) return
var/obj/item/ammo_magazine/AM = A
if(AM.stored_ammo.len <= 0)
user << "<span class='warning'>The magazine is empty!</span>"
return
for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
if(loaded.len >= max_shells)
break
if(AC.caliber == caliber && loaded.len < max_shells)
AC.loc = src
AM.stored_ammo -= AC
loaded += AC
num_loaded++
if(load_method == MAGAZINE)
user.remove_from_mob(AM)
empty_mag = AM
empty_mag.loc = src
if(istype(A, /obj/item/ammo_casing) && load_method == SPEEDLOADER)
var/obj/item/ammo_casing/AC = A
if(AC.caliber == caliber && loaded.len < max_shells)
user.drop_item()
AC.loc = src
loaded += AC
num_loaded++
if(num_loaded)
user << "\blue You load [num_loaded] shell\s into the gun!"
A.update_icon()
update_icon()
return
load_ammo(A, user)
/obj/item/weapon/gun/projectile/attack_self(mob/user as mob)
if (target)
return ..()
if (loaded.len)
if (load_method == SPEEDLOADER)
var/obj/item/ammo_casing/AC = loaded[1]
loaded -= AC
AC.loc = get_turf(src) //Eject casing onto ground.
user << "\blue You unload shell from \the [src]!"
if (load_method == MAGAZINE)
var/obj/item/ammo_magazine/AM = empty_mag
for (var/obj/item/ammo_casing/AC in loaded)
AM.stored_ammo += AC
loaded -= AC
AM.loc = get_turf(src)
empty_mag = null
update_icon()
AM.update_icon()
user << "\blue You unload magazine from \the [src]!"
unload_ammo(user)
/obj/item/weapon/gun/projectile/attack_hand(mob/user as mob)
if(user.get_inactive_hand() == src)
unload_ammo(user, allow_dump=0)
else
user << "\red Nothing loaded in \the [src]!"
return ..()
/obj/item/weapon/gun/projectile/afterattack(atom/A, mob/living/user)
..()
if(auto_eject && ammo_magazine && ammo_magazine.stored_ammo && !ammo_magazine.stored_ammo.len)
ammo_magazine.loc = get_turf(src.loc)
user.visible_message(
"[ammo_magazine] falls out and clatters on the floor!",
"<span class='notice'>[ammo_magazine] falls out and clatters on the floor!</span>"
)
if(auto_eject_sound)
playsound(user, auto_eject_sound, 40, 1)
ammo_magazine.update_icon()
ammo_magazine = null
update_icon() //make sure to do this after unsetting ammo_magazine
/obj/item/weapon/gun/projectile/examine(mob/user)
..(user)
user << "Has [getAmmo()] round\s remaining."
// if(in_chamber && !loaded.len)
// user << "However, it has a chambered round."
// if(in_chamber && loaded.len)
// user << "It also has a chambered round." {R}
if(ammo_magazine)
user << "It has \a [ammo_magazine] loaded."
return
/obj/item/weapon/gun/projectile/proc/getAmmo()
var/bullets = 0
for(var/obj/item/ammo_casing/AC in loaded)
if(istype(AC))
bullets += 1
if(loaded)
bullets += loaded.len
if(ammo_magazine && ammo_magazine.stored_ammo)
bullets += ammo_magazine.stored_ammo.len
if(chambered)
bullets += 1
return bullets

View File

@@ -2,67 +2,111 @@
name = "submachine gun"
desc = "A lightweight, fast firing gun. Uses 9mm rounds."
icon_state = "saber" //ugly
w_class = 3.0
w_class = 3
load_method = SPEEDLOADER //yup. until someone sprites a magazine for it.
max_shells = 22
caliber = "9mm"
origin_tech = "combat=4;materials=2"
ammo_type = "/obj/item/ammo_casing/c9mm"
automatic = 1
slot_flags = SLOT_BELT
ammo_type = /obj/item/ammo_casing/c9mm
multi_aim = 1
fire_delay = 0
isHandgun()
return 0
/obj/item/weapon/gun/projectile/automatic/test
name = "test gun"
ammo_type = "/obj/item/ammo_casing/a145"
/obj/item/weapon/gun/projectile/automatic/mini_uzi
name = "\improper Uzi"
desc = "A lightweight, fast firing gun, for when you want someone dead. Uses .45 rounds."
icon_state = "mini-uzi"
w_class = 3.0
max_shells = 16
w_class = 3
load_method = SPEEDLOADER //yup. until someone sprites a magazine for it.
max_shells = 15
caliber = ".45"
origin_tech = "combat=5;materials=2;syndicate=8"
ammo_type = "/obj/item/ammo_casing/c45"
isHandgun()
return 1
ammo_type = /obj/item/ammo_casing/c45
/obj/item/weapon/gun/projectile/automatic/c20r
name = "\improper C-20r SMG"
desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp"
desc = "A lightweight, fast firing gun, for when you REALLY need someone dead. Uses 12mm pistol rounds. Has a 'Scarborough Arms - Per falcis, per pravitas' buttstamp"
icon_state = "c20r"
item_state = "c20r"
w_class = 3.0
max_shells = 20
w_class = 3
force = 10
caliber = "12mm"
origin_tech = "combat=5;materials=2;syndicate=8"
ammo_type = "/obj/item/ammo_casing/a12mm"
slot_flags = SLOT_BELT|SLOT_BACK
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
mag_type = /obj/item/ammo_magazine/a12mm/empty
magazine_type = /obj/item/ammo_magazine/a12mm
auto_eject = 1
auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
if(!loaded.len && empty_mag)
empty_mag.loc = get_turf(src.loc)
empty_mag = null
playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
update_icon()
return
/obj/item/weapon/gun/projectile/automatic/c20r/update_icon()
..()
if(ammo_magazine)
icon_state = "c20r-[round(ammo_magazine.stored_ammo.len,4)]"
else
icon_state = "c20r"
return
/obj/item/weapon/gun/projectile/automatic/wt550
name = "\improper W-T 550 Saber"
desc = "A cheap, mass produced Ward-Takahashi PDW. Uses 9mm rounds."
icon_state = "wt550"
w_class = 3.0
caliber = "9mm"
origin_tech = "combat=5;materials=2"
slot_flags = SLOT_BELT
ammo_type = "/obj/item/ammo_casing/c9mmr"
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
magazine_type = /obj/item/ammo_magazine/mc9mmt/rubber
update_icon()
..()
if(empty_mag)
icon_state = "c20r-[round(loaded.len,4)]"
else
icon_state = "c20r"
return
/obj/item/weapon/gun/projectile/automatic/wt550/update_icon()
..()
if(ammo_magazine)
icon_state = "wt550-[round(ammo_magazine.stored_ammo.len,4)]"
else
icon_state = "wt550"
return
/obj/item/weapon/gun/projectile/automatic/z8
name = "\improper Z8 Bulldog"
desc = "An older model bullpup carbine, made by the now defunct Zendai Foundries. Uses armor piercing 5.56mm rounds. Makes you feel like a space marine when you hold it."
icon_state = "carbine"
item_state = "shotgun"
w_class = 4
force = 10
caliber = "a556"
origin_tech = "combat=8;materials=3"
ammo_type = "/obj/item/ammo_casing/a556"
fire_sound = 'sound/weapons/Gunshot.ogg'
slot_flags = SLOT_BACK
load_method = MAGAZINE
magazine_type = /obj/item/ammo_magazine/a556
/obj/item/weapon/gun/projectile/automatic/z8/update_icon()
..()
if(ammo_magazine)
icon_state = "carbine-[round(ammo_magazine.stored_ammo.len,2)]"
else
icon_state = "carbine"
return
/obj/item/weapon/gun/projectile/automatic/sts35
name = "\improper STS-35 automatic rifle"
desc = "A durable, rugged looking automatic weapon of a make popular on the frontier. Uses 7.62mm rounds. It is unmarked."
icon_state = "assltrifle"
item_state = "shotgun"
w_class = 4
force = 10
caliber = "a762"
origin_tech = "combat=6;materials=1;syndicate=4"
slot_flags = SLOT_BACK
load_method = MAGAZINE
magazine_type = /obj/item/ammo_magazine/c762
/obj/item/weapon/gun/projectile/automatic/sts35/update_icon()
..()
icon_state = (ammo_magazine)? "assltrifle" : "assltrifle-noclip"
/obj/item/weapon/gun/projectile/automatic/l6_saw
name = "\improper L6 SAW"
@@ -70,74 +114,39 @@
icon_state = "l6closed100"
item_state = "l6closedmag"
w_class = 4
force = 10
slot_flags = 0
max_shells = 50
caliber = "a762"
origin_tech = "combat=5;materials=1;syndicate=2"
origin_tech = "combat=6;materials=1;syndicate=2"
slot_flags = SLOT_BACK
ammo_type = "/obj/item/ammo_casing/a762"
fire_sound = 'sound/weapons/Gunshot_smg.ogg'
load_method = MAGAZINE
magazine_type = /obj/item/ammo_magazine/a762
var/cover_open = 0
var/mag_inserted = 1
/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_self(mob/user as mob)
cover_open = !cover_open
user << "<span class='notice'>You [cover_open ? "open" : "close"] [src]'s cover.</span>"
update_icon()
/obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon()
icon_state = "l6[cover_open ? "open" : "closed"][mag_inserted ? round(loaded.len, 25) : "-empty"]"
icon_state = "l6[cover_open ? "open" : "closed"][ammo_magazine ? round(ammo_magazine.stored_ammo.len, 25) : "-empty"]"
/obj/item/weapon/gun/projectile/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays
/obj/item/weapon/gun/projectile/automatic/l6_saw/special_check(mob/user)
if(cover_open)
user << "<span class='notice'>[src]'s cover is open! Close it before firing!</span>"
else
..()
update_icon()
user << "<span class='warning'>[src]'s cover is open! Close it before firing!</span>"
return 0
return ..()
/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_hand(mob/user as mob)
if(loc != user)
..()
return //let them pick it up
if(!cover_open || (cover_open && !mag_inserted))
..()
else if(cover_open && mag_inserted)
//drop the mag
empty_mag = new /obj/item/ammo_magazine/a762(src)
empty_mag.stored_ammo = loaded
empty_mag.icon_state = "a762-[round(loaded.len, 10)]"
empty_mag.desc = "There are [loaded.len] shells left!"
empty_mag.loc = get_turf(src.loc)
user.put_in_hands(empty_mag)
empty_mag = null
mag_inserted = 0
loaded = list()
update_icon()
user << "<span class='notice'>You remove the magazine from [src].</span>"
/obj/item/weapon/gun/projectile/automatic/l6_saw/attackby(var/obj/item/A as obj, mob/user as mob)
/obj/item/weapon/gun/projectile/automatic/l6_saw/load_ammo(var/obj/item/A, mob/user)
if(!cover_open)
user << "<span class='notice'>[src]'s cover is closed! You can't insert a new mag!</span>"
user << "<span class='warning'>You need to open the cover to load [src].</span>"
return
else if(cover_open && mag_inserted)
user << "<span class='notice'>[src] already has a magazine inserted!</span>"
return
else if(cover_open && !mag_inserted)
mag_inserted = 1
user << "<span class='notice'>You insert the magazine!</span>"
update_icon()
..()
/* The thing I found with guns in ss13 is that they don't seem to simulate the rounds in the magazine in the gun.
Afaik, since projectile.dm features a revolver, this would make sense since the magazine is part of the gun.
However, it looks like subsequent guns that use removable magazines don't take that into account and just get
around simulating a removable magazine by adding the casings into the loaded list and spawning an empty magazine
when the gun is out of rounds. Which means you can't eject magazines with rounds in them. The below is a very
rough and poor attempt at making that happen. -Ausops */
/obj/item/weapon/gun/projectile/automatic/l6_saw/unload_ammo(mob/user, var/allow_dump=1)
if(!cover_open)
return
..()

View File

@@ -0,0 +1,202 @@
/obj/item/projectile/bullet/chemdart
name = "dart"
icon_state = "dart"
damage = 5
sharp = 1
embed = 1 //the dart is shot fast enough to pierce space suits, so I guess splintering inside the target can be a thing. Should be rare due to low damage.
var/reagent_amount = 15
kill_count = 15 //shorter range
/obj/item/projectile/bullet/chemdart/New()
reagents = new/datum/reagents(reagent_amount)
reagents.my_atom = src
/obj/item/projectile/bullet/chemdart/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null)
if(blocked < 2 && isliving(target))
var/mob/living/L = target
if(L.can_inject(target_zone=def_zone))
reagents.trans_to(L, reagent_amount)
/obj/item/ammo_casing/chemdart
name = "chemical dart"
desc = "A small hardened, hollow dart."
icon_state = "dart"
caliber = "dart"
projectile_type = /obj/item/projectile/bullet/chemdart
/obj/item/ammo_casing/chemdart/expend()
del(src)
/obj/item/ammo_magazine/chemdart
name = "dart cartridge"
desc = "A rack of hollow darts."
icon_state = "darts"
item_state = "rcdammo"
origin_tech = "materials=2"
mag_type = MAGAZINE
caliber = "dart"
ammo_type = /obj/item/ammo_casing/chemdart
max_ammo = 5
multiple_sprites = 1
/obj/item/weapon/gun/projectile/dartgun
name = "dart gun"
desc = "A small gas-powered dartgun, capable of delivering chemical cocktails swiftly across short distances."
icon_state = "dartgun-empty"
caliber = "dart"
fire_sound = 'sound/weapons/empty.ogg'
fire_sound_text = "a metallic click"
recoil = 0
silenced = 1
load_method = MAGAZINE
magazine_type = /obj/item/ammo_magazine/chemdart
auto_eject = 0
var/list/beakers = list() //All containers inside the gun.
var/list/mixing = list() //Containers being used for mixing.
var/max_beakers = 3
var/dart_reagent_amount = 15
var/container_type = /obj/item/weapon/reagent_containers/glass/beaker
var/list/starting_chems = null
/obj/item/weapon/gun/projectile/dartgun/dartgun/New()
..()
if(starting_chems)
for(var/chem in starting_chems)
var/obj/B = new container_type(src)
B.reagents.add_reagent(chem, 60)
beakers += B
update_icon()
/obj/item/weapon/gun/projectile/dartgun/update_icon()
if(!ammo_magazine)
icon_state = "dartgun-empty"
return 1
if(!ammo_magazine.stored_ammo || ammo_magazine.stored_ammo.len)
icon_state = "dartgun-0"
else if(ammo_magazine.stored_ammo.len > 5)
icon_state = "dartgun-5"
else
icon_state = "dartgun-[ammo_magazine.stored_ammo.len]"
return 1
/obj/item/weapon/gun/projectile/dartgun/consume_next_projectile()
. = ..()
var/obj/item/projectile/bullet/chemdart/dart = .
if(istype(dart))
fill_dart(dart)
/obj/item/weapon/gun/projectile/dartgun/examine(mob/user)
//update_icon()
//if (!..(user, 2))
// return
..()
if (beakers.len)
user << "\blue [src] contains:"
for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
if(B.reagents && B.reagents.reagent_list.len)
for(var/datum/reagent/R in B.reagents.reagent_list)
user << "\blue [R.volume] units of [R.name]"
/obj/item/weapon/gun/projectile/dartgun/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/reagent_containers/glass))
if(!istype(I, container_type))
user << "\blue [I] doesn't seem to fit into [src]."
return
if(beakers.len >= max_beakers)
user << "\blue [src] already has [max_beakers] beakers in it - another one isn't going to fit!"
return
var/obj/item/weapon/reagent_containers/glass/beaker/B = I
user.drop_item()
B.loc = src
beakers += B
user << "\blue You slot [B] into [src]."
src.updateUsrDialog()
return 1
..()
//fills the given dart with reagents
/obj/item/weapon/gun/projectile/dartgun/proc/fill_dart(var/obj/item/projectile/bullet/chemdart/dart)
if(mixing.len)
var/mix_amount = dart.reagent_amount/mixing.len
for(var/obj/item/weapon/reagent_containers/glass/beaker/B in mixing)
B.reagents.trans_to(dart, mix_amount)
/obj/item/weapon/gun/projectile/dartgun/attack_self(mob/user)
user.set_machine(src)
var/dat = "<b>[src] mixing control:</b><br><br>"
if (beakers.len)
var/i = 1
for(var/obj/item/weapon/reagent_containers/glass/beaker/B in beakers)
dat += "Beaker [i] contains: "
if(B.reagents && B.reagents.reagent_list.len)
for(var/datum/reagent/R in B.reagents.reagent_list)
dat += "<br> [R.volume] units of [R.name], "
if (check_beaker_mixing(B))
dat += text("<A href='?src=\ref[src];stop_mix=[i]'><font color='green'>Mixing</font></A> ")
else
dat += text("<A href='?src=\ref[src];mix=[i]'><font color='red'>Not mixing</font></A> ")
else
dat += "nothing."
dat += " \[<A href='?src=\ref[src];eject=[i]'>Eject</A>\]<br>"
i++
else
dat += "There are no beakers inserted!<br><br>"
if(ammo_magazine)
if(ammo_magazine.stored_ammo && ammo_magazine.stored_ammo.len)
dat += "The dart cartridge has [ammo_magazine.stored_ammo.len] shots remaining."
else
dat += "<font color='red'>The dart cartridge is empty!</font>"
dat += " \[<A href='?src=\ref[src];eject_cart=1'>Eject</A>\]"
user << browse(dat, "window=dartgun")
onclose(user, "dartgun", src)
/obj/item/weapon/gun/projectile/dartgun/proc/check_beaker_mixing(var/obj/item/B)
if(!mixing || !beakers)
return 0
for(var/obj/item/M in mixing)
if(M == B)
return 1
return 0
/obj/item/weapon/gun/projectile/dartgun/Topic(href, href_list)
src.add_fingerprint(usr)
if(href_list["stop_mix"])
var/index = text2num(href_list["stop_mix"])
if(index <= beakers.len)
for(var/obj/item/M in mixing)
if(M == beakers[index])
mixing -= M
break
else if (href_list["mix"])
var/index = text2num(href_list["mix"])
if(index <= beakers.len)
mixing += beakers[index]
else if (href_list["eject"])
var/index = text2num(href_list["eject"])
if(index <= beakers.len)
if(beakers[index])
var/obj/item/weapon/reagent_containers/glass/beaker/B = beakers[index]
usr << "You remove [B] from [src]."
mixing -= B
beakers -= B
B.loc = get_turf(src)
else if (href_list["eject_cart"])
unload_ammo(usr)
src.updateUsrDialog()
return
/obj/item/weapon/gun/projectile/dartgun/vox
name = "alien dart gun"
desc = "A small gas-powered dartgun, fitted for nonhuman hands."
/obj/item/weapon/gun/projectile/dartgun/vox/medical
starting_chems = list("kelotane","bicaridine","anti_toxin")
/obj/item/weapon/gun/projectile/dartgun/vox/raider
starting_chems = list("space_drugs","stoxin","impedrezene")

View File

@@ -1,89 +0,0 @@
/obj/item/weapon/gun/launcher
name = "launcher"
desc = "A device that launches things."
icon = 'icons/obj/weapons.dmi'
w_class = 5.0
flags = CONDUCT
slot_flags = SLOT_BACK
var/release_force = 0
var/fire_sound_text = "a launcher firing"
//Check if we're drawing and if the bow is loaded.
/obj/item/weapon/gun/launcher/load_into_chamber()
return (!isnull(in_chamber))
//This should not fit in a combat belt or holster.
/obj/item/weapon/gun/launcher/isHandgun()
return 0
//Launchers are mechanical, no other impact.
/obj/item/weapon/gun/launcher/emp_act(severity)
return
//This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile.
/obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob)
return
//Override this to avoid a runtime with suicide handling.
/obj/item/weapon/gun/launcher/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
if (M == user && user.zone_sel.selecting == "mouth")
user << "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it."
return
..()
/obj/item/weapon/gun/launcher/proc/update_release_force()
return 0
/obj/item/weapon/gun/launcher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
if (!user.IsAdvancedToolUser())
return 0
add_fingerprint(user)
//Make sure target turfs both exist.
var/turf/curloc = get_turf(user)
var/turf/targloc = get_turf(target)
if (!istype(targloc) || !istype(curloc))
return 0
if(!special_check(user))
return 0
if (!ready_to_fire())
if (world.time % 3) //to prevent spam
user << "<span class='warning'>[src] is not ready to fire again!"
return 0
if(!load_into_chamber()) //CHECK
return click_empty(user)
if(!in_chamber)
return 0
update_release_force()
playsound(user, fire_sound, 50, 1)
user.visible_message("<span class='warning'>[user] fires [src][reflex ? " by reflex":""]!</span>", \
"<span class='warning'>You fire [src][reflex ? "by reflex":""]!</span>", \
"You hear [fire_sound_text]!")
in_chamber.loc = get_turf(user)
in_chamber.throw_at(target,10,release_force)
sleep(1)
in_chamber = null
update_icon()
if(user.hand)
user.update_inv_l_hand()
else
user.update_inv_r_hand()
return 1
/obj/item/weapon/gun/launcher/attack_self(mob/living/user as mob)
return

View File

@@ -1,47 +1,85 @@
/obj/item/weapon/gun/projectile/colt
name = "\improper Colt M1911"
desc = "A cheap Martian knock-off of a Colt M1911."
magazine_type = /obj/item/ammo_magazine/c45m
icon_state = "colt"
caliber = ".45"
origin_tech = "combat=2;materials=2"
load_method = MAGAZINE
/obj/item/weapon/gun/projectile/colt/flash
name = "\improper Colt M1911 signal pistol"
desc = "A cheap Martian knock-off of a Colt M1911. Uses .45 signal flash rounds."
magazine_type = /obj/item/ammo_magazine/c45m/flash
/obj/item/weapon/gun/projectile/colt/detective
desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds."
magazine_type = /obj/item/ammo_magazine/c45m/rubber
/obj/item/weapon/gun/projectile/colt/detective/verb/rename_gun()
set name = "Name Gun"
set category = "Object"
set desc = "Rename your gun. If you're the detective."
var/mob/M = usr
if(!M.mind) return 0
if(!M.mind.assigned_role == "Detective")
M << "<span class='notice'>You don't feel cool enough to name this gun, chump.</span>"
return 0
var/input = stripped_input(usr,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
if(src && input && !M.stat && in_range(M,src))
name = input
M << "You name the gun [input]. Say hello to your new friend."
return 1
/obj/item/weapon/gun/projectile/sec
desc = "A Nanotrasen designed sidearm, found pretty much everywhere humans are. Uses less-than-lethal .45 rounds."
name = "\improper NT Mk58"
icon_state = "secguncomp"
magazine_type = /obj/item/ammo_magazine/c45m/rubber
caliber = ".45"
origin_tech = "combat=3;materials=2"
load_method = MAGAZINE
/obj/item/weapon/gun/projectile/sec/wood
desc = "A Nanotrasen designed sidearm, this one has a sweet wooden grip. Uses less-than-lethal .45 rounds."
name = "\improper Custom NT Mk58"
icon_state = "secgundark"
/obj/item/weapon/gun/projectile/silenced
name = "silenced pistol"
desc = "A small, quiet, easily concealable gun. Uses .45 rounds."
icon_state = "silenced_pistol"
w_class = 3.0
max_shells = 12
w_class = 3
caliber = ".45"
silenced = 1
origin_tech = "combat=2;materials=2;syndicate=8"
ammo_type = "/obj/item/ammo_casing/c45"
load_method = MAGAZINE
magazine_type = /obj/item/ammo_magazine/c45m
/obj/item/weapon/gun/projectile/deagle
name = "desert eagle"
desc = "A robust handgun that uses .50 AE ammo"
icon_state = "deagle"
force = 14.0
max_shells = 7
caliber = ".50"
ammo_type ="/obj/item/ammo_casing/a50"
load_method = MAGAZINE
mag_type = /obj/item/ammo_magazine/a50/empty
afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
if(!loaded.len && empty_mag)
empty_mag.loc = get_turf(src.loc)
empty_mag = null
playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
update_icon()
return
magazine_type = /obj/item/ammo_magazine/a50
auto_eject = 1
/obj/item/weapon/gun/projectile/deagle/gold
desc = "A gold plated gun folded over a million times by superior martian gunsmiths. Uses .50 AE ammo."
icon_state = "deagleg"
item_state = "deagleg"
/obj/item/weapon/gun/projectile/deagle/camo
desc = "A Deagle brand Deagle for operators operating operationally. Uses .50 AE ammo."
icon_state = "deaglecamo"
item_state = "deagleg"
auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
@@ -55,47 +93,35 @@
origin_tech = "combat=3"
ammo_type = "/obj/item/ammo_casing/a75"
load_method = MAGAZINE
mag_type = /obj/item/ammo_magazine/a75/empty
magazine_type = /obj/item/ammo_magazine/a75
auto_eject = 1
auto_eject_sound = 'sound/weapons/smg_empty_alarm.ogg'
afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
if(!loaded.len && empty_mag)
empty_mag.loc = get_turf(src.loc)
empty_mag = null
playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1)
update_icon()
return
update_icon()
..()
if(empty_mag)
icon_state = "gyropistolloaded"
else
icon_state = "gyropistol"
return
/obj/item/weapon/gun/projectile/gyropistol/update_icon()
..()
if(ammo_magazine)
icon_state = "gyropistolloaded"
else
icon_state = "gyropistol"
/obj/item/weapon/gun/projectile/pistol
name = "\improper Stechtkin pistol"
desc = "A small, easily concealable gun. Uses 9mm rounds."
icon_state = "pistol"
w_class = 2
max_shells = 10
caliber = "9mm"
silenced = 0
origin_tech = "combat=2;materials=2;syndicate=2"
ammo_type = "/obj/item/ammo_casing/c9mm"
load_method = MAGAZINE
mag_type = /obj/item/ammo_magazine/mc9mm
magazine_type = /obj/item/ammo_magazine/mc9mm
/obj/item/weapon/gun/projectile/pistol/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
if(!loaded.len && empty_mag)
empty_mag.loc = get_turf(src.loc)
empty_mag = null
return
/obj/item/weapon/gun/projectile/pistol/flash
name = "\improper Stechtkin signal pistol"
desc = "A small, easily concealable gun. Uses 9mm signal flash rounds."
magazine_type = /obj/item/ammo_magazine/mc9mm/flash
/obj/item/weapon/gun/projectile/pistol/attack_hand(mob/user as mob)
if(loc == user)
if(user.get_inactive_hand() == src)
if(silenced)
if(user.l_hand != src && user.r_hand != src)
..()
@@ -108,7 +134,6 @@
return
..()
/obj/item/weapon/gun/projectile/pistol/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/silencer))
if(user.l_hand != src && user.r_hand != src) //if we're not in his hands

View File

@@ -1,186 +1,42 @@
/obj/item/weapon/gun/projectile/detective
/obj/item/weapon/gun/projectile/revolver
name = "revolver"
desc = "A classic revolver. Uses .357 ammo"
icon_state = "revolver"
caliber = "357"
origin_tech = "combat=2;materials=2"
handle_casings = CYCLE_CASINGS
max_shells = 7
ammo_type = /obj/item/ammo_casing/a357
/obj/item/weapon/gun/projectile/revolver/mateba
name = "mateba"
desc = "When you absolutely, positively need a 10mm hole in the other guy. Uses .357 ammo." //>10mm hole >.357
icon_state = "mateba"
origin_tech = "combat=2;materials=2"
/obj/item/weapon/gun/projectile/revolver/detective
name = "revolver"
desc = "A cheap Martian knock-off of a Smith & Wesson Model 10. Uses .38-Special rounds."
icon_state = "detective"
max_shells = 6
caliber = "38"
origin_tech = "combat=2;materials=2"
ammo_type = "/obj/item/ammo_casing/c38"
ammo_type = /obj/item/ammo_casing/c38
special_check(var/mob/living/carbon/human/M)
if(caliber == initial(caliber))
return 1
if(prob(70 - (loaded.len * 10))) //minimum probability of 10, maximum of 60
M << "<span class='danger'>[src] blows up in your face.</span>"
M.take_organ_damage(0,20)
M.drop_item()
del(src)
return 0
/obj/item/weapon/gun/projectile/revolver/detective/verb/rename_gun()
set name = "Name Gun"
set category = "Object"
set desc = "Click to rename your gun. If you're the detective."
var/mob/M = usr
if(!M.mind) return 0
if(!M.mind.assigned_role == "Detective")
M << "<span class='notice'>You don't feel cool enough to name this gun, chump.</span>"
return 0
var/input = stripped_input(usr,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
if(src && input && !M.stat && in_range(M,src))
name = input
M << "You name the gun [input]. Say hello to your new friend."
return 1
verb/rename_gun()
set name = "Name Gun"
set category = "Object"
set desc = "Click to rename your gun. If you're the detective."
var/mob/M = usr
if(!M.mind) return 0
if(!M.mind.assigned_role == "Detective")
M << "<span class='notice'>You don't feel cool enough to name this gun, chump.</span>"
return 0
var/input = stripped_input(usr,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
if(src && input && !M.stat && in_range(M,src))
name = input
M << "You name the gun [input]. Say hello to your new friend."
return 1
attackby(var/obj/item/A as obj, mob/user as mob)
..()
if(istype(A, /obj/item/weapon/screwdriver))
if(caliber == "38")
user << "<span class='notice'>You begin to reinforce the barrel of [src].</span>"
if(loaded.len)
afterattack(user, user) //you know the drill
playsound(user, fire_sound, 50, 1)
user.visible_message("<span class='danger'>[src] goes off!</span>", "<span class='danger'>[src] goes off in your face!</span>")
return
if(do_after(user, 30))
if(loaded.len)
user << "<span class='notice'>You can't modify it!</span>"
return
caliber = "357"
desc = "The barrel and chamber assembly seems to have been modified."
user << "<span class='warning'>You reinforce the barrel of [src]! Now it will fire .357 rounds.</span>"
else if (caliber == "357")
user << "<span class='notice'>You begin to revert the modifications to [src].</span>"
if(loaded.len)
afterattack(user, user) //and again
playsound(user, fire_sound, 50, 1)
user.visible_message("<span class='danger'>[src] goes off!</span>", "<span class='danger'>[src] goes off in your face!</span>")
return
if(do_after(user, 30))
if(loaded.len)
user << "<span class='notice'>You can't modify it!</span>"
return
caliber = "38"
desc = initial(desc)
user << "<span class='warning'>You remove the modifications on [src]! Now it will fire .38 rounds.</span>"
/obj/item/weapon/gun/projectile/detective/semiauto
name = "\improper Colt M1911"
desc = "A cheap Martian knock-off of a Colt M1911. Uses less-than-lethal .45 rounds."
icon_state = "colt"
max_shells = 7
caliber = ".45"
ammo_type = "/obj/item/ammo_casing/c45r"
load_method = MAGAZINE
mag_type = /obj/item/ammo_magazine/c45r/empty
/obj/item/weapon/gun/projectile/detective/semiauto/flash
ammo_type = "/obj/item/ammo_casing/c45f"
/obj/item/weapon/gun/projectile/detective/semiauto/colt
desc = "A cheap Martian knock-off of a Colt M1911."
ammo_type = "/obj/item/ammo_casing/c45"
/obj/item/weapon/gun/projectile/detective/semiauto/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag)
..()
if(!loaded.len && empty_mag)
empty_mag.loc = get_turf(src.loc)
empty_mag = null
user << "<span class='notice'>The Magazine falls out and clatters on the floor!</span>"
return
/obj/item/weapon/gun/projectile/mateba
name = "mateba"
desc = "When you absolutely, positively need a 10mm hole in the other guy. Uses .357 ammo." //>10mm hole >.357
icon_state = "mateba"
origin_tech = "combat=2;materials=2"
// A gun to play Russian Roulette!
// You can spin the chamber to randomize the position of the bullet.
/obj/item/weapon/gun/projectile/russian
name = "\improper Russian revolver"
desc = "A Russian made revolver. Uses .357 ammo. It has a single slot in it's chamber for a bullet."
max_shells = 6
origin_tech = "combat=2;materials=2"
/obj/item/weapon/gun/projectile/russian/New()
Spin()
update_icon()
/obj/item/weapon/gun/projectile/russian/proc/Spin()
for(var/obj/item/ammo_casing/AC in loaded)
del(AC)
loaded = list()
var/random = rand(1, max_shells)
for(var/i = 1; i <= max_shells; i++)
if(i != random)
loaded += i // Basically null
else
loaded += new ammo_type(src)
/obj/item/weapon/gun/projectile/russian/attackby(var/obj/item/A as obj, mob/user as mob)
if(!A) return
var/num_loaded = 0
if(istype(A, /obj/item/ammo_magazine))
if((load_method == MAGAZINE) && loaded.len) return
var/obj/item/ammo_magazine/AM = A
for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
if(getAmmo() > 0 || loaded.len >= max_shells)
break
if(AC.caliber == caliber && loaded.len < max_shells)
AC.loc = src
AM.stored_ammo -= AC
loaded += AC
num_loaded++
break
A.update_icon()
if(num_loaded)
user.visible_message("<span class='warning'>[user] loads a single bullet into the revolver and spins the chamber.</span>", "<span class='warning'>You load a single bullet into the chamber and spin it.</span>")
else
user.visible_message("<span class='warning'>[user] spins the chamber of the revolver.</span>", "<span class='warning'>You spin the revolver's chamber.</span>")
if(getAmmo() > 0)
Spin()
update_icon()
return
/obj/item/weapon/gun/projectile/russian/attack_self(mob/user as mob)
user.visible_message("<span class='warning'>[user] spins the chamber of the revolver.</span>", "<span class='warning'>You spin the revolver's chamber.</span>")
if(getAmmo() > 0)
Spin()
/obj/item/weapon/gun/projectile/russian/attack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj)
if(!loaded.len)
user.visible_message("\red *click*", "\red *click*")
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
return
if(isliving(target) && isliving(user))
if(target == user)
var/datum/organ/external/affecting = user.zone_sel.selecting
if(affecting == "head")
var/obj/item/ammo_casing/AC = loaded[1]
if(!load_into_chamber())
user.visible_message("\red *click*", "\red *click*")
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
return
if(!in_chamber)
return
var/obj/item/projectile/P = new AC.projectile_type
playsound(user, fire_sound, 50, 1)
user.visible_message("<span class='danger'>[user.name] fires [src] at \his head!</span>", "<span class='danger'>You fire [src] at your head!</span>", "You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!")
if(!P.nodamage)
user.apply_damage(300, BRUTE, affecting, sharp=1) // You are dead, dead, dead.
return
..()

View File

@@ -1,51 +0,0 @@
/obj/item/weapon/gun/rocketlauncher
name = "rocket launcher"
desc = "MAGGOT."
icon_state = "rocket"
item_state = "rocket"
w_class = 4.0
throw_speed = 2
throw_range = 10
force = 5.0
flags = CONDUCT | USEDELAY
slot_flags = 0
origin_tech = "combat=8;materials=5"
var/projectile = /obj/item/missile
var/missile_speed = 2
var/missile_range = 30
var/max_rockets = 1
var/list/rockets = new/list()
/obj/item/weapon/gun/rocketlauncher/examine(mob/user)
if(!..(user, 2))
return
user << "\blue [rockets.len] / [max_rockets] rockets."
/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/ammo_casing/rocket))
if(rockets.len < max_rockets)
user.drop_item()
I.loc = src
rockets += I
user << "\blue You put the rocket in [src]."
user << "\blue [rockets.len] / [max_rockets] rockets."
else
usr << "\red [src] cannot hold more rockets."
/obj/item/weapon/gun/rocketlauncher/can_fire()
return rockets.len
/obj/item/weapon/gun/rocketlauncher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)
if(rockets.len)
var/obj/item/ammo_casing/rocket/I = rockets[1]
var/obj/item/missile/M = new projectile(user.loc)
playsound(user.loc, 'sound/effects/bang.ogg', 50, 1)
M.primed = 1
M.throw_at(target, missile_range, missile_speed,user)
message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]).")
log_game("[key_name_admin(user)] used a rocket launcher ([src.name]).")
rockets -= I
del(I)
return
else
usr << "\red [src] is empty."

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