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

Conflicts:
	code/game/machinery/camera/camera.dm
	code/modules/mob/mob.dm
This commit is contained in:
PsiOmega
2015-02-17 08:36:12 +01:00
297 changed files with 11567 additions and 9431 deletions
+10 -3
View File
@@ -1148,15 +1148,22 @@ var/global/floorIsLava = 0
switch(detail)
if(0)
return "<b>[key_name(C, link, name, highlight_special)]</b>"
if(1)
if(1) //Private Messages
return "<b>[key_name(C, link, name, highlight_special)](<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</A>)</b>"
if(2)
if(2) //Admins
var/ref_mob = "\ref[M]"
return "<b>[key_name(C, link, name, highlight_special)](<A HREF='?_src_=holder;adminmoreinfo=[ref_mob]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) (<A HREF='?_src_=holder;adminplayerobservejump=[ref_mob]'>JMP</A>) (<A HREF='?_src_=holder;check_antagonist=1'>CA</A>)</b>"
if(3)
if(3) //Devs
var/ref_mob = "\ref[M]"
return "<b>[key_name(C, link, name, highlight_special)](<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>)(<A HREF='?_src_=holder;adminplayerobservejump=[ref_mob]'>JMP</A>)</b>"
if(4) //Mentors
var/ref_mob = "\ref[M]"
return "<b>[key_name(C, link, name, highlight_special)] (<A HREF='?_src_=holder;adminmoreinfo=\ref[M]'>?</A>) (<A HREF='?_src_=holder;adminplayeropts=[ref_mob]'>PP</A>) (<A HREF='?_src_=vars;Vars=[ref_mob]'>VV</A>) (<A HREF='?_src_=holder;subtlemessage=[ref_mob]'>SM</A>) (<A HREF='?_src_=holder;adminplayerobservejump=[ref_mob]'>JMP</A>)</b>"
/proc/ishost(whom)
if(!whom)
+3
View File
@@ -109,6 +109,9 @@ var/list/admin_verbs_fun = list(
var/list/admin_verbs_spawn = list(
/datum/admins/proc/spawn_atom, /*allows us to spawn instances*/
/client/proc/respawn_character,
/client/proc/FireLaser,
/client/proc/FireCannons,
/client/proc/ChangeIcarusPosition,
/client/proc/virus2_editor
)
var/list/admin_verbs_server = list(
+5 -1
View File
@@ -87,7 +87,11 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
var/ai_cl
if(ai_found)
ai_cl = " (<A HREF='?_src_=holder;adminchecklaws=\ref[mob]'>CL</A>)"
var/mentor_msg = "\blue <b><font color=red>Request for Help: </font>[get_options_bar(mob, 0, 0, 1, 0)][ai_cl]:</b> [msg]"
//Options bar: mob, details ( admin = 2, dev = 3, mentor = 4, character name (0 = just ckey, 1 = ckey and character name), link? (0 no don't make it a link, 1 do so),
// highlight special roles (0 = everyone has same looking name, 1 = antags / special roles get a golden name)
var/mentor_msg = "\blue <b><font color=red>Request for Help: </font>[get_options_bar(mob, 4, 1, 1, 0)][ai_cl]:</b> [msg]"
msg = "\blue <b><font color=red>Request for Help:: </font>[get_options_bar(mob, 2, 1, 1)][ai_cl]:</b> [msg]"
var/admin_number_afk = 0
+3 -3
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"
+125
View File
@@ -0,0 +1,125 @@
/client/proc/FireLaser()
set name = "Fire the Icarus lasers"
set desc = "Fires a laser bolt at your position. You should only do this as a(n) (a)ghost"
set category = "Fun"
if(!src.holder)
src << "Only administrators may use this command."
return
Icarus_FireLaser(get_turf(src.mob))
/client/proc/FireCannons()
set name = "Fire the Icarus cannons"
set desc = "Fires an explosive missile at your position. You should only do this as a(n) (a)ghost."
set category = "Fun"
if(!src.holder)
src << "Only administrators may use this command."
return
Icarus_FireCannon(get_turf(src.mob))
/client/proc/ChangeIcarusPosition()
set name = "Adjust Icarus Position"
set desc = "Lets you chose the position of the Icarus in regards to the map."
set category = "Fun"
if(!src.holder)
src << "Only administrators may use this command."
return
Icarus_SetPosition(src)
var/icarus_position = SOUTH
proc/Icarus_FireLaser(var/turf/target)
// Find the world edge to fire from.
var/x = icarus_position & EAST ? world.maxx : icarus_position & WEST ? 1 : target.x
var/y = icarus_position & NORTH ? world.maxy : icarus_position & SOUTH ? 1 : target.y
var/x_off = x != target.x ? abs(target.x - x) : INFINITY
var/y_off = y != target.y ? abs(target.y - y) : INFINITY
// Get the minimum number of steps using the rise/run shit.
var/iterations = round(min(x_off, y_off)) - 14 // We cannot fire straight from the edge since teleport thing.
// Now we can get the location of the start.
x = target.x + (icarus_position & EAST ? iterations : icarus_position & WEST ? -iterations : 0)
y = target.y + (icarus_position & NORTH ? iterations : icarus_position & SOUTH ? -iterations : 0)
var/turf/start = locate(x, y, target.z)
// should step down as:
// 1000, 500, 333, 250, 200, 167, 142, 125, 111, 100, 90
var/damage = 1000
for(var/i in 2 to 12)
var/obj/item/projectile/beam/in_chamber = new (start)
in_chamber.original = target
in_chamber.starting = start
in_chamber.silenced = 1
in_chamber.yo = icarus_position & NORTH ? -1 : icarus_position & SOUTH ? 1 : 0
in_chamber.xo = icarus_position & EAST ? -1 : icarus_position & WEST ? 1 : 0
in_chamber.damage = damage
in_chamber.kill_count = 500
in_chamber.process()
damage -= damage / i
sleep(-1)
// Let everyone know what hit them.
var/obj/item/projectile/beam/in_chamber = new (start)
in_chamber.original = target
in_chamber.starting = start
in_chamber.silenced = 0
in_chamber.yo = icarus_position & NORTH ? -1 : icarus_position & SOUTH ? 1 : 0
in_chamber.xo = icarus_position & EAST ? -1 : icarus_position & WEST ? 1 : 0
in_chamber.kill_count = 500
in_chamber.damage = 0
in_chamber.name = "point defense laser"
in_chamber.firer = "Icarus" // Never displayed, but we want this to display the hit message.
in_chamber.process()
proc/Icarus_FireCannon(var/turf/target)
// Find the world edge to fire from.
var/x = icarus_position & EAST ? world.maxx : icarus_position & WEST ? 1 : target.x
var/y = icarus_position & NORTH ? world.maxy : icarus_position & SOUTH ? 1 : target.y
var/x_off = x != target.x ? abs(target.x - x) : INFINITY
var/y_off = y != target.y ? abs(target.y - y) : INFINITY
// Get the minimum number of steps using the rise/run shit.
var/iterations = round(min(x_off, y_off)) - 14 // We cannot fire straight from the edge since teleport thing.
// Now we can get the location of the start.
x = target.x + (icarus_position & EAST ? iterations : icarus_position & WEST ? -iterations : 0)
y = target.y + (icarus_position & NORTH ? iterations : icarus_position & SOUTH ? -iterations : 0)
var/turf/start = locate(x, y, target.z)
// Now we find the corresponding turf on the other side of the level.
// Yeah, yeah. Overuse of the terinary operator. So sue me.
x = icarus_position & EAST ? 1 : icarus_position & WEST ? world.maxx : target.x
y = icarus_position & NORTH ? 1 : icarus_position & SOUTH ? world.maxy : target.y
x_off = x != target.x ? abs(target.x - x) : INFINITY
y_off = y != target.y ? abs(target.y - y) : INFINITY
iterations = round(min(x_off, y_off))
x = target.x + (icarus_position & EAST ? -iterations : icarus_position & WEST ? iterations : 0)
y = target.y + (icarus_position & NORTH ? -iterations : icarus_position & SOUTH ? iterations : 0)
target = locate(x, y, target.z)
// Finally fire the fucker.
var/obj/effect/meteor/small/projectile = new (start)
projectile.dest = target
projectile.name = "main gun projectile" // stealthy
projectile.hits = 6
projectile.detonation_chance = 99 // it's a missile/cannon round thing!
// Make sure it travels
spawn(0)
walk_towards(projectile, projectile.dest, 1)
proc/Icarus_SetPosition(var/user)
var/global/list/directions = list("North" = 1, "North East" = 5, "East" = 4, "South East" = 6, "South" = 2, "South West" = 10, "West" = 8, "North West" = 9)
var/direction = input(user, "Where should the Icarus fire from?", "Icarus Comms") as null|anything in directions
if(!direction)
return
icarus_position = directions[direction]
+1 -1
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)
+2 -2
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)
+17 -20
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")
+14 -14
View File
@@ -375,88 +375,88 @@ var/global/list/gear_datums = list()
/datum/gear/armband_cargo
display_name = "armband, cargo"
path = /obj/item/clothing/tie/armband/cargo
path = /obj/item/clothing/accessory/armband/cargo
slot = slot_tie
cost = 1
/datum/gear/armband_emt
display_name = "armband, EMT"
path = /obj/item/clothing/tie/armband/medgreen
path = /obj/item/clothing/accessory/armband/medgreen
slot = slot_tie
cost = 2
/datum/gear/armband_engineering
display_name = "armband, engineering"
path = /obj/item/clothing/tie/armband/engine
path = /obj/item/clothing/accessory/armband/engine
slot = slot_tie
cost = 1
/datum/gear/armband_hydroponics
display_name = "armband, hydroponics"
path = /obj/item/clothing/tie/armband/hydro
path = /obj/item/clothing/accessory/armband/hydro
slot = slot_tie
cost = 1
/datum/gear/armband_medical
display_name = "armband, medical"
path = /obj/item/clothing/tie/armband/med
path = /obj/item/clothing/accessory/armband/med
slot = slot_tie
cost = 1
/datum/gear/armband
display_name = "armband, red"
path = /obj/item/clothing/tie/armband
path = /obj/item/clothing/accessory/armband
slot = slot_tie
cost = 1
/datum/gear/armband_science
display_name = "armband, science"
path = /obj/item/clothing/tie/armband/science
path = /obj/item/clothing/accessory/armband/science
slot = slot_tie
cost = 1
/datum/gear/armpit
display_name = "shoulder holster"
path = /obj/item/clothing/tie/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")
/datum/gear/tie_blue
display_name = "tie, blue"
path = /obj/item/clothing/tie/blue
path = /obj/item/clothing/accessory/blue
slot = slot_tie
cost = 1
/datum/gear/tie_red
display_name = "tie, red"
path = /obj/item/clothing/tie/red
path = /obj/item/clothing/accessory/red
slot = slot_tie
cost = 1
/datum/gear/tie_horrible
display_name = "tie, socially disgraceful"
path = /obj/item/clothing/tie/horrible
path = /obj/item/clothing/accessory/horrible
slot = slot_tie
cost = 1
/datum/gear/brown_vest
display_name = "webbing, engineering"
path = /obj/item/clothing/tie/storage/brown_vest
path = /obj/item/clothing/accessory/storage/brown_vest
slot = slot_tie
cost = 2
allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer")
/datum/gear/black_vest
display_name = "webbing, security"
path = /obj/item/clothing/tie/storage/black_vest
path = /obj/item/clothing/accessory/storage/black_vest
slot = slot_tie
cost = 2
allowed_roles = list("Security Officer","Head of Security","Warden")
/datum/gear/webbing
display_name = "webbing, simple"
path = /obj/item/clothing/tie/storage/webbing
path = /obj/item/clothing/accessory/storage/webbing
slot = slot_tie
cost = 2
@@ -191,6 +191,11 @@
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"
+47 -24
View File
@@ -68,7 +68,7 @@
/obj/item/clothing/head/helmet/refit_for_species(var/target_species)
if(!species_restricted)
return //this item doesn't use the species_restricted system
//Set species_restricted list
switch(target_species)
if("Skrell")
@@ -401,7 +401,7 @@ BLIND // can't see anything
2 = Report detailed damages
3 = Report location
*/
var/obj/item/clothing/tie/hastie = null
var/list/accessories = list()
var/displays_id = 1
sprite_sheets = list("Vox" = 'icons/mob/species/vox/uniform.dmi')
@@ -410,28 +410,44 @@ BLIND // can't see anything
var/mob/M = src.loc
M.update_inv_w_uniform()
/obj/item/clothing/under/proc/can_attach_accessory(obj/item/clothing/accessory/A)
if(istype(A))
.=1
else
return 0
if(accessories.len && (A.slot in list("utility","armband")))
for(var/obj/item/clothing/accessory/AC in accessories)
if (AC.slot == A.slot)
return 0
/obj/item/clothing/under/attackby(obj/item/I, mob/user)
if(hastie)
hastie.attackby(I, user)
return
if(istype(I, /obj/item/clothing/accessory))
var/obj/item/clothing/accessory/A = I
if(can_attach_accessory(A))
user.drop_item()
accessories += A
A.on_attached(src, user)
if(!hastie && istype(I, /obj/item/clothing/tie))
user.drop_item()
hastie = I
hastie.on_attached(src, user)
if(istype(loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = loc
H.update_inv_w_uniform()
if(istype(loc, /mob/living/carbon/human))
var/mob/living/carbon/human/H = loc
H.update_inv_w_uniform()
return
else
user << "<span class='notice'>You cannot attach more accessories of this type to [src].</span>"
if(accessories.len)
for(var/obj/item/clothing/accessory/A in accessories)
A.attackby(I, user)
return
..()
/obj/item/clothing/under/attack_hand(mob/user as mob)
//only forward to the attached accessory if the clothing is equipped (not in a storage)
if(hastie && src.loc == user)
hastie.attack_hand(user)
if(accessories.len && src.loc == user)
for(var/obj/item/clothing/accessory/A in accessories)
A.attack_hand(user)
return
if ((ishuman(usr) || ismonkey(usr)) && src.loc == user) //make it harder to accidentally undress yourself
@@ -468,8 +484,9 @@ BLIND // can't see anything
user << "Its vital tracker appears to be enabled."
if(3)
user << "Its vital tracker and tracking beacon appear to be enabled."
if(hastie)
user << "\A [hastie] is clipped to it."
if(accessories.len)
for(var/obj/item/clothing/accessory/A in accessories)
user << "\A [A] is attached to it."
/obj/item/clothing/under/proc/set_sensors(mob/usr as mob)
var/mob/M = usr
@@ -540,12 +557,12 @@ BLIND // can't see anything
else
usr << "<span class='notice'>You cannot roll down the uniform!</span>"
/obj/item/clothing/under/proc/remove_accessory(mob/user as mob)
if(!hastie)
/obj/item/clothing/under/proc/remove_accessory(mob/user, obj/item/clothing/accessory/A)
if(!(A in accessories))
return
hastie.on_removed(user)
hastie = null
A.on_removed(user)
accessories -= A
update_clothing_icon()
/obj/item/clothing/under/verb/removetie()
@@ -554,14 +571,20 @@ BLIND // can't see anything
set src in usr
if(!istype(usr, /mob/living)) return
if(usr.stat) return
src.remove_accessory(usr)
if(!accessories.len) return
var/obj/item/clothing/accessory/A
if(accessories.len > 1)
A = input("Select an accessory to remove from [src]") as null|anything in accessories
else
A = accessories[1]
src.remove_accessory(usr,A)
/obj/item/clothing/under/rank/New()
sensor_mode = pick(0,1,2,3)
..()
/obj/item/clothing/under/emp_act(severity)
if (hastie)
hastie.emp_act(severity)
if(accessories.len)
for(var/obj/item/clothing/accessory/A in accessories)
A.emp_act(severity)
..()
@@ -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 = text2path(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 = text2path(projectile_type)
in_chamber = new prog_path(src)
return 1
return 0
@@ -197,8 +197,8 @@
target_mob = H
if(target_mob != H)
H << "<span class='danger'>You inject [target_mob] with [chems_to_use] unit[chems_to_use == 1 ? "" : "s"] of [charge.display_name].</span>"
target_mob << "<span class='danger'>You feel a rushing in your veins as [chems_to_use] unit[chems_to_use == 1 ? "" : "s"] of [charge.display_name] [chems_to_use == 1 ? "is" : "are"] injected.</span>"
H << "<span class='danger'>You inject [target_mob] with [chems_to_use] unit\s of [charge.display_name].</span>"
target_mob << "<span class='danger'>You feel a rushing in your veins as [chems_to_use] unit\s of [charge.display_name] [chems_to_use == 1 ? "is" : "are"] injected.</span>"
target_mob.reagents.add_reagent(charge.display_name, chems_to_use)
charge.charges -= chems_to_use
+23 -30
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/New()
..()
holster = new(src)
/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/attackby(obj/item/W as obj, mob/user as mob)
..()
holster.attackby(W, user)
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/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
+2 -2
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
/*
@@ -0,0 +1,226 @@
/obj/item/clothing/accessory
name = "tie"
desc = "A neosilk clip-on tie."
icon = 'icons/obj/clothing/ties.dmi'
icon_state = "bluetie"
item_state = "" //no inhands
item_color = "bluetie"
slot_flags = SLOT_TIE
w_class = 2.0
var/slot = "decor"
var/obj/item/clothing/under/has_suit = null //the suit the tie may be attached to
var/image/inv_overlay = null //overlay used when attached to clothing.
/obj/item/clothing/accessory/New()
..()
inv_overlay = image("icon" = 'icons/obj/clothing/ties_overlay.dmi', "icon_state" = "[item_color? "[item_color]" : "[icon_state]"]")
//when user attached an accessory to S
/obj/item/clothing/accessory/proc/on_attached(obj/item/clothing/under/S, mob/user as mob)
if(!istype(S))
return
has_suit = S
loc = has_suit
has_suit.overlays += inv_overlay
user << "<span class='notice'>You attach [src] to [has_suit].</span>"
src.add_fingerprint(user)
/obj/item/clothing/accessory/proc/on_removed(mob/user as mob)
if(!has_suit)
return
has_suit.overlays -= inv_overlay
has_suit = null
usr.put_in_hands(src)
src.add_fingerprint(user)
//default attackby behaviour
/obj/item/clothing/accessory/attackby(obj/item/I, mob/user)
..()
//default attack_hand behaviour
/obj/item/clothing/accessory/attack_hand(mob/user as mob)
if(has_suit)
return //we aren't an object on the ground so don't call parent
..()
/obj/item/clothing/accessory/blue
name = "blue tie"
icon_state = "bluetie"
item_color = "bluetie"
/obj/item/clothing/accessory/red
name = "red tie"
icon_state = "redtie"
item_color = "redtie"
/obj/item/clothing/accessory/horrible
name = "horrible tie"
desc = "A neosilk clip-on tie. This one is disgusting."
icon_state = "horribletie"
item_color = "horribletie"
/obj/item/clothing/accessory/stethoscope
name = "stethoscope"
desc = "An outdated medical apparatus for listening to the sounds of the human body. It also makes you look like you know what you're doing."
icon_state = "stethoscope"
item_color = "stethoscope"
/obj/item/clothing/accessory/stethoscope/attack(mob/living/carbon/human/M, mob/living/user)
if(ishuman(M) && isliving(user))
if(user.a_intent == "help")
var/body_part = parse_zone(user.zone_sel.selecting)
if(body_part)
var/their = "their"
switch(M.gender)
if(MALE) their = "his"
if(FEMALE) their = "her"
var/sound = "pulse"
var/sound_strength
if(M.stat == DEAD || (M.status_flags&FAKEDEATH))
sound_strength = "cannot hear"
sound = "anything"
else
sound_strength = "hear a weak"
switch(body_part)
if("chest")
if(M.oxyloss < 50)
sound_strength = "hear a healthy"
sound = "pulse and respiration"
if("eyes","mouth")
sound_strength = "cannot hear"
sound = "anything"
else
sound_strength = "hear a weak"
user.visible_message("[user] places [src] against [M]'s [body_part] and listens attentively.", "You place [src] against [their] [body_part]. You [sound_strength] [sound].")
return
return ..(M,user)
//Medals
/obj/item/clothing/accessory/medal
name = "bronze medal"
desc = "A bronze medal."
icon_state = "bronze"
item_color = "bronze"
/obj/item/clothing/accessory/medal/conduct
name = "distinguished conduct medal"
desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew."
/obj/item/clothing/accessory/medal/bronze_heart
name = "bronze heart medal"
desc = "A bronze heart-shaped medal awarded for sacrifice. It is often awarded posthumously or for severe injury in the line of duty."
icon_state = "bronze_heart"
/obj/item/clothing/accessory/medal/nobel_science
name = "nobel sciences award"
desc = "A bronze medal which represents significant contributions to the field of science or engineering."
/obj/item/clothing/accessory/medal/silver
name = "silver medal"
desc = "A silver medal."
icon_state = "silver"
item_color = "silver"
/obj/item/clothing/accessory/medal/silver/valor
name = "medal of valor"
desc = "A silver medal awarded for acts of exceptional valor."
/obj/item/clothing/accessory/medal/silver/security
name = "robust security award"
desc = "An award for distinguished combat and sacrifice in defence of Nanotrasen's commercial interests. Often awarded to security staff."
/obj/item/clothing/accessory/medal/gold
name = "gold medal"
desc = "A prestigious golden medal."
icon_state = "gold"
item_color = "gold"
/obj/item/clothing/accessory/medal/gold/captain
name = "medal of captaincy"
desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew."
/obj/item/clothing/accessory/medal/gold/heroism
name = "medal of exceptional heroism"
desc = "An extremely rare golden medal awarded only by CentComm. To recieve such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders."
/*
Holobadges are worn on the belt or neck, and can be used to show that the holder is an authorized
Security agent - the user details can be imprinted on the badge with a Security-access ID card,
or they can be emagged to accept any ID for use in disguises.
*/
/obj/item/clothing/accessory/holobadge
name = "holobadge"
desc = "This glowing blue badge marks the holder as THE LAW."
icon_state = "holobadge"
item_color = "holobadge"
slot_flags = SLOT_BELT | SLOT_TIE
var/emagged = 0 //Emagging removes Sec check.
var/stored_name = null
/obj/item/clothing/accessory/holobadge/cord
icon_state = "holobadge-cord"
item_color = "holobadge-cord"
slot_flags = SLOT_MASK | SLOT_TIE
/obj/item/clothing/accessory/holobadge/attack_self(mob/user as mob)
if(!stored_name)
user << "Waving around a badge before swiping an ID would be pretty pointless."
return
if(isliving(user))
user.visible_message("\red [user] displays their NanoTrasen Internal Security Legal Authorization Badge.\nIt reads: [stored_name], NT Security.","\red You display your NanoTrasen Internal Security Legal Authorization Badge.\nIt reads: [stored_name], NT Security.")
/obj/item/clothing/accessory/holobadge/attackby(var/obj/item/O as obj, var/mob/user as mob)
if (istype(O, /obj/item/weapon/card/emag))
if (emagged)
user << "\red [src] is already cracked."
return
else
emagged = 1
user << "\red You swipe [O] and crack the holobadge security checks."
return
else if(istype(O, /obj/item/weapon/card/id) || istype(O, /obj/item/device/pda))
var/obj/item/weapon/card/id/id_card = null
if(istype(O, /obj/item/weapon/card/id))
id_card = O
else
var/obj/item/device/pda/pda = O
id_card = pda.id
if(access_security in id_card.access || emagged)
user << "You imprint your ID details onto the badge."
stored_name = id_card.registered_name
name = "holobadge ([stored_name])"
desc = "This glowing blue badge marks [stored_name] as THE LAW."
else
user << "[src] rejects your insufficient access rights."
return
..()
/obj/item/clothing/accessory/holobadge/attack(mob/living/carbon/human/M, mob/living/user)
if(isliving(user))
user.visible_message("\red [user] invades [M]'s personal space, thrusting [src] into their face insistently.","\red You invade [M]'s personal space, thrusting [src] into their face insistently. You are the law.")
/obj/item/weapon/storage/box/holobadge
name = "holobadge box"
desc = "A box claiming to contain holobadges."
New()
new /obj/item/clothing/accessory/holobadge(src)
new /obj/item/clothing/accessory/holobadge(src)
new /obj/item/clothing/accessory/holobadge(src)
new /obj/item/clothing/accessory/holobadge(src)
new /obj/item/clothing/accessory/holobadge/cord(src)
new /obj/item/clothing/accessory/holobadge/cord(src)
..()
return
@@ -0,0 +1,42 @@
/obj/item/clothing/accessory/armband
name = "red armband"
desc = "A fancy red armband!"
icon_state = "red"
item_color = "red"
slot = "armband"
/obj/item/clothing/accessory/armband/cargo
name = "cargo armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is brown."
icon_state = "cargo"
item_color = "cargo"
/obj/item/clothing/accessory/armband/engine
name = "engineering armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is orange with a reflective strip!"
icon_state = "engie"
item_color = "engie"
/obj/item/clothing/accessory/armband/science
name = "science armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is purple."
icon_state = "rnd"
item_color = "rnd"
/obj/item/clothing/accessory/armband/hydro
name = "hydroponics armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is green and blue."
icon_state = "hydro"
item_color = "hydro"
/obj/item/clothing/accessory/armband/med
name = "medical armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is white."
icon_state = "med"
item_color = "med"
/obj/item/clothing/accessory/armband/medgreen
name = "EMT armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is white and green."
icon_state = "medgreen"
item_color = "medgreen"
@@ -0,0 +1,115 @@
/obj/item/clothing/accessory/holster
name = "shoulder holster"
desc = "A handgun holster."
icon_state = "holster"
item_color = "holster"
slot = "utility"
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>"
return
if (!(I.slot_flags & SLOT_HOLSTER))
user << "<span class='warning'>[I] won't fit in [src]!</span>"
return
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>")
/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>"
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>"
)
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.put_in_hands(holstered)
holstered.add_fingerprint(user)
holstered = null
/obj/item/clothing/accessory/holster/attack_hand(mob/user as mob)
if (has_suit) //if we are part of a suit
if (holstered)
unholster(user)
return
..(user)
/obj/item/clothing/accessory/holster/attackby(obj/item/W as obj, mob/user as mob)
holster(W, user)
/obj/item/clothing/accessory/holster/emp_act(severity)
if (holstered)
holstered.emp_act(severity)
..()
/obj/item/clothing/accessory/holster/examine(mob/user)
..(user)
if (holstered)
user << "A [holstered] is holstered here."
else
user << "It is empty."
/obj/item/clothing/accessory/holster/on_attached(obj/item/clothing/under/S, mob/user as mob)
..()
has_suit.verbs += /obj/item/clothing/accessory/holster/verb/holster_verb
/obj/item/clothing/accessory/holster/on_removed(mob/user as mob)
has_suit.verbs -= /obj/item/clothing/accessory/holster/verb/holster_verb
..()
//For the holster hotkey
/obj/item/clothing/accessory/holster/verb/holster_verb()
set name = "Holster"
set category = "Object"
set src in usr
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
else if (istype(src, /obj/item/clothing/under))
var/obj/item/clothing/under/S = src
if (S.accessories.len)
H = locate() in S.accessories
if (!H)
usr << "<span class='warning'>Something is very wrong.</span>"
if(!H.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
H.holster(W, usr)
else
H.unholster(usr)
/obj/item/clothing/accessory/holster/armpit
name = "shoulder 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"
desc = "A handgun holster. Made of expensive leather."
icon_state = "holster"
item_color = "holster_low"
@@ -0,0 +1,86 @@
/obj/item/clothing/accessory/storage
name = "load bearing equipment"
desc = "Used to hold things when you don't have enough hands."
icon_state = "webbing"
item_color = "webbing"
slot = "utility"
var/slots = 3
var/obj/item/weapon/storage/internal/hold
/obj/item/clothing/accessory/storage/New()
..()
hold = new/obj/item/weapon/storage/internal(src)
hold.storage_slots = slots
/obj/item/clothing/accessory/storage/attack_hand(mob/user as mob)
if (has_suit) //if we are part of a suit
hold.open(user)
return
if (hold.handle_attack_hand(user)) //otherwise interact as a regular storage item
..(user)
/obj/item/clothing/accessory/storage/MouseDrop(obj/over_object as obj)
if (has_suit)
return
if (hold.handle_mousedrop(usr, over_object))
..(over_object)
/obj/item/clothing/accessory/storage/attackby(obj/item/W as obj, mob/user as mob)
return hold.attackby(W, user)
/obj/item/clothing/accessory/storage/emp_act(severity)
hold.emp_act(severity)
..()
/obj/item/clothing/accessory/storage/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
hold.hear_talk(M, msg, verb, speaking)
..()
/obj/item/clothing/accessory/storage/attack_self(mob/user as mob)
user << "<span class='notice'>You empty [src].</span>"
var/turf/T = get_turf(src)
hold.hide_from(usr)
for(var/obj/item/I in hold.contents)
hold.remove_from_storage(I, T)
src.add_fingerprint(user)
/obj/item/clothing/accessory/storage/webbing
name = "webbing"
desc = "Strudy mess of synthcotton belts and buckles, ready to share your burden."
icon_state = "webbing"
item_color = "webbing"
/obj/item/clothing/accessory/storage/black_vest
name = "black webbing vest"
desc = "Robust black synthcotton vest with lots of pockets to hold whatever you need, but cannot hold in hands."
icon_state = "vest_black"
item_color = "vest_black"
slots = 5
/obj/item/clothing/accessory/storage/brown_vest
name = "brown webbing vest"
desc = "Worn brownish synthcotton vest with lots of pockets to unload your hands."
icon_state = "vest_brown"
item_color = "vest_brown"
slots = 5
/obj/item/clothing/accessory/storage/knifeharness
name = "decorated harness"
desc = "A heavily decorated harness of sinew and leather with two knife-loops."
icon_state = "unathiharness2"
item_color = "unathiharness2"
slots = 2
/obj/item/clothing/accessory/storage/knifeharness/New()
..()
hold.max_combined_w_class = 4
hold.can_hold = list("/obj/item/weapon/hatchet/unathiknife",\
"/obj/item/weapon/kitchen/utensil/knife",\
"/obj/item/weapon/kitchen/utensil/pknife",\
"/obj/item/weapon/kitchenknife",\
"/obj/item/weapon/kitchenknife/ritual")
new /obj/item/weapon/hatchet/unathiknife(hold)
new /obj/item/weapon/hatchet/unathiknife(hold)
@@ -130,6 +130,12 @@
icon_state = "scrubspurple"
item_color = "scrubspurple"
/obj/item/clothing/under/rank/medical/black
name = "medical scrubs"
desc = "It's made of a special fiber that provides minor protection against biohazards. This one is in black."
icon_state = "scrubsblack"
item_color = "scrubsblack"
/obj/item/clothing/under/rank/psych
desc = "A basic white jumpsuit. It has turqouise markings that denote the wearer as a psychiatrist."
name = "psychiatrist's jumpsuit"
+3 -3
View File
@@ -479,9 +479,9 @@
/obj/item/clothing/under/serviceoveralls
name = "Workman outfit"
desc = "The very image of a working man. Not that you're probably doing work."
icon_state = "mechanic_s"
item_state = "mechanic_s"
item_color = "mechanic_s"
icon_state = "mechanic"
item_state = "mechanic"
item_color = "mechanic"
/obj/item/clothing/under/cheongsam
name = "White Cheongsam"
-474
View File
@@ -1,474 +0,0 @@
/obj/item/clothing/tie
name = "tie"
desc = "A neosilk clip-on tie."
icon = 'icons/obj/clothing/ties.dmi'
icon_state = "bluetie"
item_state = "" //no inhands
item_color = "bluetie"
slot_flags = SLOT_TIE
w_class = 2.0
var/obj/item/clothing/under/has_suit = null //the suit the tie may be attached to
var/image/inv_overlay = null //overlay used when attached to clothing.
/obj/item/clothing/tie/New()
..()
inv_overlay = image("icon" = 'icons/obj/clothing/ties_overlay.dmi', "icon_state" = "[item_color? "[item_color]" : "[icon_state]"]")
//when user attached an accessory to S
/obj/item/clothing/tie/proc/on_attached(obj/item/clothing/under/S, mob/user as mob)
if(!istype(S))
return
has_suit = S
loc = has_suit
has_suit.overlays += inv_overlay
user << "<span class='notice'>You attach [src] to [has_suit].</span>"
src.add_fingerprint(user)
/obj/item/clothing/tie/proc/on_removed(mob/user as mob)
if(!has_suit)
return
has_suit.overlays -= inv_overlay
has_suit = null
usr.put_in_hands(src)
src.add_fingerprint(user)
//default attackby behaviour
/obj/item/clothing/tie/attackby(obj/item/I, mob/user)
..()
//default attack_hand behaviour
/obj/item/clothing/tie/attack_hand(mob/user as mob)
if(has_suit)
has_suit.remove_accessory(user)
return //we aren't an object on the ground so don't call parent
..()
/obj/item/clothing/tie/blue
name = "blue tie"
icon_state = "bluetie"
item_color = "bluetie"
/obj/item/clothing/tie/red
name = "red tie"
icon_state = "redtie"
item_color = "redtie"
/obj/item/clothing/tie/horrible
name = "horrible tie"
desc = "A neosilk clip-on tie. This one is disgusting."
icon_state = "horribletie"
item_color = "horribletie"
/obj/item/clothing/tie/stethoscope
name = "stethoscope"
desc = "An outdated medical apparatus for listening to the sounds of the human body. It also makes you look like you know what you're doing."
icon_state = "stethoscope"
item_color = "stethoscope"
/obj/item/clothing/tie/stethoscope/attack(mob/living/carbon/human/M, mob/living/user)
if(ishuman(M) && isliving(user))
if(user.a_intent == "help")
var/body_part = parse_zone(user.zone_sel.selecting)
if(body_part)
var/their = "their"
switch(M.gender)
if(MALE) their = "his"
if(FEMALE) their = "her"
var/sound = "pulse"
var/sound_strength
if(M.stat == DEAD || (M.status_flags&FAKEDEATH))
sound_strength = "cannot hear"
sound = "anything"
else
sound_strength = "hear a weak"
switch(body_part)
if("chest")
if(M.oxyloss < 50)
sound_strength = "hear a healthy"
sound = "pulse and respiration"
if("eyes","mouth")
sound_strength = "cannot hear"
sound = "anything"
else
sound_strength = "hear a weak"
user.visible_message("[user] places [src] against [M]'s [body_part] and listens attentively.", "You place [src] against [their] [body_part]. You [sound_strength] [sound].")
return
return ..(M,user)
//Medals
/obj/item/clothing/tie/medal
name = "bronze medal"
desc = "A bronze medal."
icon_state = "bronze"
item_color = "bronze"
/obj/item/clothing/tie/medal/conduct
name = "distinguished conduct medal"
desc = "A bronze medal awarded for distinguished conduct. Whilst a great honor, this is most basic award given by Nanotrasen. It is often awarded by a captain to a member of his crew."
/obj/item/clothing/tie/medal/bronze_heart
name = "bronze heart medal"
desc = "A bronze heart-shaped medal awarded for sacrifice. It is often awarded posthumously or for severe injury in the line of duty."
icon_state = "bronze_heart"
/obj/item/clothing/tie/medal/nobel_science
name = "nobel sciences award"
desc = "A bronze medal which represents significant contributions to the field of science or engineering."
/obj/item/clothing/tie/medal/silver
name = "silver medal"
desc = "A silver medal."
icon_state = "silver"
item_color = "silver"
/obj/item/clothing/tie/medal/silver/valor
name = "medal of valor"
desc = "A silver medal awarded for acts of exceptional valor."
/obj/item/clothing/tie/medal/silver/security
name = "robust security award"
desc = "An award for distinguished combat and sacrifice in defence of Nanotrasen's commercial interests. Often awarded to security staff."
/obj/item/clothing/tie/medal/gold
name = "gold medal"
desc = "A prestigious golden medal."
icon_state = "gold"
item_color = "gold"
/obj/item/clothing/tie/medal/gold/captain
name = "medal of captaincy"
desc = "A golden medal awarded exclusively to those promoted to the rank of captain. It signifies the codified responsibilities of a captain to Nanotrasen, and their undisputable authority over their crew."
/obj/item/clothing/tie/medal/gold/heroism
name = "medal of exceptional heroism"
desc = "An extremely rare golden medal awarded only by CentComm. To recieve such a medal is the highest honor and as such, very few exist. This medal is almost never awarded to anybody but commanders."
//Armbands
/obj/item/clothing/tie/armband
name = "red armband"
desc = "A fancy red armband!"
icon_state = "red"
item_color = "red"
/obj/item/clothing/tie/armband/cargo
name = "cargo armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is brown."
icon_state = "cargo"
item_color = "cargo"
/obj/item/clothing/tie/armband/engine
name = "engineering armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is orange with a reflective strip!"
icon_state = "engie"
item_color = "engie"
/obj/item/clothing/tie/armband/science
name = "science armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is purple."
icon_state = "rnd"
item_color = "rnd"
/obj/item/clothing/tie/armband/hydro
name = "hydroponics armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is green and blue."
icon_state = "hydro"
item_color = "hydro"
/obj/item/clothing/tie/armband/med
name = "medical armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is white."
icon_state = "med"
item_color = "med"
/obj/item/clothing/tie/armband/medgreen
name = "EMT armband"
desc = "An armband, worn by the crew to display which department they're assigned to. This one is white and green."
icon_state = "medgreen"
item_color = "medgreen"
//holsters
/obj/item/clothing/tie/holster
name = "shoulder holster"
desc = "A handgun holster."
icon_state = "holster"
item_color = "holster"
var/obj/item/weapon/gun/holstered = null
//subtypes can override this to specify what can be holstered
/obj/item/clothing/tie/holster/proc/can_holster(obj/item/weapon/gun/W)
return W.isHandgun()
/obj/item/clothing/tie/holster/proc/holster(obj/item/I, mob/user as mob)
if(holstered)
user << "\red There is already a [holstered] holstered here!"
return
if (!istype(I, /obj/item/weapon/gun))
user << "\red Only guns can be holstered!"
return
var/obj/item/weapon/gun/W = I
if (!can_holster(W))
user << "\red This [W] won't fit in the [src]!"
return
holstered = W
user.drop_from_inventory(holstered)
holstered.loc = src
holstered.add_fingerprint(user)
user.visible_message("\blue [user] holsters the [holstered].", "You holster the [holstered].")
/obj/item/clothing/tie/holster/proc/unholster(mob/user as mob)
if(!holstered)
return
if(istype(user.get_active_hand(),/obj) && istype(user.get_inactive_hand(),/obj))
user << "\red You need an empty hand to draw the [holstered]!"
else
if(user.a_intent == "hurt")
usr.visible_message("\red [user] draws the [holstered], ready to shoot!", \
"\red You draw the [holstered], ready to shoot!")
else
user.visible_message("\blue [user] draws the [holstered], pointing it at the ground.", \
"\blue You draw the [holstered], pointing it at the ground.")
user.put_in_hands(holstered)
holstered.add_fingerprint(user)
holstered = null
/obj/item/clothing/tie/holster/attack_hand(mob/user as mob)
if (has_suit) //if we are part of a suit
if (holstered)
unholster(user)
return
..(user)
/obj/item/clothing/tie/holster/attackby(obj/item/W as obj, mob/user as mob)
holster(W, user)
/obj/item/clothing/tie/holster/emp_act(severity)
if (holstered)
holstered.emp_act(severity)
..()
/obj/item/clothing/tie/holster/examine(mob/user)
..(user)
if (holstered)
user << "A [holstered] is holstered here."
else
user << "It is empty."
/obj/item/clothing/tie/holster/on_attached(obj/item/clothing/under/S, mob/user as mob)
..()
has_suit.verbs += /obj/item/clothing/tie/holster/verb/holster_verb
/obj/item/clothing/tie/holster/on_removed(mob/user as mob)
has_suit.verbs -= /obj/item/clothing/tie/holster/verb/holster_verb
..()
//For the holster hotkey
/obj/item/clothing/tie/holster/verb/holster_verb()
set name = "Holster"
set category = "Object"
set src in usr
if(!istype(usr, /mob/living)) return
if(usr.stat) return
var/obj/item/clothing/tie/holster/H = null
if (istype(src, /obj/item/clothing/tie/holster))
H = src
else if (istype(src, /obj/item/clothing/under))
var/obj/item/clothing/under/S = src
if (S.hastie)
H = S.hastie
if (!H)
usr << "/red Something is very wrong."
if(!H.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()
H.holster(W, usr)
else
H.unholster(usr)
/obj/item/clothing/tie/holster/armpit
name = "shoulder holster"
desc = "A worn-out handgun holster. Perfect for concealed carry"
icon_state = "holster"
item_color = "holster"
/obj/item/clothing/tie/holster/waist
name = "shoulder holster"
desc = "A handgun holster. Made of expensive leather."
icon_state = "holster"
item_color = "holster_low"
/obj/item/clothing/tie/storage
name = "load bearing equipment"
desc = "Used to hold things when you don't have enough hands."
icon_state = "webbing"
item_color = "webbing"
var/slots = 3
var/obj/item/weapon/storage/internal/hold
/obj/item/clothing/tie/storage/New()
..()
hold = new/obj/item/weapon/storage/internal(src)
hold.storage_slots = slots
/obj/item/clothing/tie/storage/attack_hand(mob/user as mob)
if (has_suit) //if we are part of a suit
hold.open(user)
return
if (hold.handle_attack_hand(user)) //otherwise interact as a regular storage item
..(user)
/obj/item/clothing/tie/storage/MouseDrop(obj/over_object as obj)
if (has_suit)
return
if (hold.handle_mousedrop(usr, over_object))
..(over_object)
/obj/item/clothing/tie/storage/attackby(obj/item/W as obj, mob/user as mob)
return hold.attackby(W, user)
/obj/item/clothing/tie/storage/emp_act(severity)
hold.emp_act(severity)
..()
/obj/item/clothing/tie/storage/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
hold.hear_talk(M, msg, verb, speaking)
..()
/obj/item/clothing/tie/storage/attack_self(mob/user as mob)
user << "<span class='notice'>You empty [src].</span>"
var/turf/T = get_turf(src)
hold.hide_from(usr)
for(var/obj/item/I in hold.contents)
hold.remove_from_storage(I, T)
src.add_fingerprint(user)
/obj/item/clothing/tie/storage/webbing
name = "webbing"
desc = "Strudy mess of synthcotton belts and buckles, ready to share your burden."
icon_state = "webbing"
item_color = "webbing"
/obj/item/clothing/tie/storage/black_vest
name = "black webbing vest"
desc = "Robust black synthcotton vest with lots of pockets to hold whatever you need, but cannot hold in hands."
icon_state = "vest_black"
item_color = "vest_black"
slots = 5
/obj/item/clothing/tie/storage/brown_vest
name = "brown webbing vest"
desc = "Worn brownish synthcotton vest with lots of pockets to unload your hands."
icon_state = "vest_brown"
item_color = "vest_brown"
slots = 5
/*
Holobadges are worn on the belt or neck, and can be used to show that the holder is an authorized
Security agent - the user details can be imprinted on the badge with a Security-access ID card,
or they can be emagged to accept any ID for use in disguises.
*/
/obj/item/clothing/tie/holobadge
name = "holobadge"
desc = "This glowing blue badge marks the holder as THE LAW."
icon_state = "holobadge"
item_color = "holobadge"
slot_flags = SLOT_BELT | SLOT_TIE
var/emagged = 0 //Emagging removes Sec check.
var/stored_name = null
/obj/item/clothing/tie/holobadge/cord
icon_state = "holobadge-cord"
item_color = "holobadge-cord"
slot_flags = SLOT_MASK | SLOT_TIE
/obj/item/clothing/tie/holobadge/attack_self(mob/user as mob)
if(!stored_name)
user << "Waving around a badge before swiping an ID would be pretty pointless."
return
if(isliving(user))
user.visible_message("\red [user] displays their NanoTrasen Internal Security Legal Authorization Badge.\nIt reads: [stored_name], NT Security.","\red You display your NanoTrasen Internal Security Legal Authorization Badge.\nIt reads: [stored_name], NT Security.")
/obj/item/clothing/tie/holobadge/attackby(var/obj/item/O as obj, var/mob/user as mob)
if (istype(O, /obj/item/weapon/card/emag))
if (emagged)
user << "\red [src] is already cracked."
return
else
emagged = 1
user << "\red You swipe [O] and crack the holobadge security checks."
return
else if(istype(O, /obj/item/weapon/card/id) || istype(O, /obj/item/device/pda))
var/obj/item/weapon/card/id/id_card = null
if(istype(O, /obj/item/weapon/card/id))
id_card = O
else
var/obj/item/device/pda/pda = O
id_card = pda.id
if(access_security in id_card.access || emagged)
user << "You imprint your ID details onto the badge."
stored_name = id_card.registered_name
name = "holobadge ([stored_name])"
desc = "This glowing blue badge marks [stored_name] as THE LAW."
else
user << "[src] rejects your insufficient access rights."
return
..()
/obj/item/clothing/tie/holobadge/attack(mob/living/carbon/human/M, mob/living/user)
if(isliving(user))
user.visible_message("\red [user] invades [M]'s personal space, thrusting [src] into their face insistently.","\red You invade [M]'s personal space, thrusting [src] into their face insistently. You are the law.")
/obj/item/weapon/storage/box/holobadge
name = "holobadge box"
desc = "A box claiming to contain holobadges."
New()
new /obj/item/clothing/tie/holobadge(src)
new /obj/item/clothing/tie/holobadge(src)
new /obj/item/clothing/tie/holobadge(src)
new /obj/item/clothing/tie/holobadge(src)
new /obj/item/clothing/tie/holobadge/cord(src)
new /obj/item/clothing/tie/holobadge/cord(src)
..()
return
/obj/item/clothing/tie/storage/knifeharness
name = "decorated harness"
desc = "A heavily decorated harness of sinew and leather with two knife-loops."
icon_state = "unathiharness2"
item_color = "unathiharness2"
slots = 2
/obj/item/clothing/tie/storage/knifeharness/New()
..()
hold.max_combined_w_class = 4
hold.can_hold = list("/obj/item/weapon/hatchet/unathiknife",\
"/obj/item/weapon/kitchen/utensil/knife",\
"/obj/item/weapon/kitchen/utensil/pknife",\
"/obj/item/weapon/kitchenknife",\
"/obj/item/weapon/kitchenknife/ritual")
new /obj/item/weapon/hatchet/unathiknife(hold)
new /obj/item/weapon/hatchet/unathiknife(hold)
+25 -15
View File
@@ -114,7 +114,7 @@
/////////////////////// Cataguettes - Lucy's Stethoscope - Lucy Kemmerer //////
/obj/item/clothing/tie/stethoscope/fluff/lucystethos
/obj/item/clothing/accessory/stethoscope/fluff/lucystethos
name = "Lucy's Stethoscope"
desc = "A medical apparatus intended to ease in listening to the sounds of the human body. This one looks cleaner and sparklier than the rest. There is a small silver plaque attached to the tubing, with the words 'Lucy Kemmerer' engraved on it."
icon_state = "lucystethos"
@@ -1111,22 +1111,33 @@
item_color = "lillian_dress"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
////// Cybernetic Casings - Parker Eliza - MrSnapwalk
////// Tailored Security Uniform - Parker Eliza - MrSnapwalk
/obj/item/clothing/under/fluff/parkereliza
name = "cybernetic casings"
desc = "A set of somewhat bulky white casings for robotic limbs, paired with a basic blue tank top and black cargo pants. The arms have a small label on the inner elbow, which reads \"Bishop Corporation Cybernetic Solutions\"."
name = "tailored security uniform"
desc = "A red uniform shirt (tailored for easy access to the shoulder joint) and black cargo pants, paired with a set of somewhat bulky white casings for robotic limbs. The arms have a small label on the inner elbow, which reads \"Bishop Corporation Cybernetic Solutions\"."
icon = 'icons/obj/custom_items.dmi'
icon_state = "parker_eliza"
item_state = "parker_eliza"
item_color = "parker_eliza"
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS
////// Bishop "GOLEM" V2200 Industrial Limb Augments - Parker Eliza - MrSnapwalk
/obj/item/clothing/suit/fluff/parkereliza
name = "Bishop \"GOLEM\" V2200 Industrial Limb Augments"
desc = "A set of top-of-the-line cyberlimbs, only usable to someone with extensive bone structure augmentation. Often used in industrial applications, they are capable of throwing a man clear across a room. The load limitation circuit in this set appears to be modified."
icon = 'icons/obj/custom_items.dmi'
icon_state = "parker_eliza_arms"
item_state = "parker_eliza_arms"
item_color = "parker_eliza_arms"
////////////// Accessories /////
//////////////////// Blood Red Pendant - Mewth - Mu'taz Radi ////////////////
/obj/item/clothing/tie/fluff/radi
/obj/item/clothing/accessory/fluff/radi
name = "Blood Red Pendant"
desc = "A blue chained necklace with a ruby in the middle, it looks pretty!"
icon = 'icons/obj/custom_items.dmi'
@@ -1168,7 +1179,7 @@
////// Small locket - Altair An-Nasaqan - Serithi
/obj/item/clothing/tie/fluff/altair_locket
/obj/item/clothing/accessory/fluff/altair_locket
name = "small locket"
desc = "A small golden locket attached to an Ii'rka-reed string. Inside the locket is a holo-picture of a female Tajaran, and an inscription writtin in Siik'mas."
icon = 'icons/obj/custom_items.dmi'
@@ -1181,7 +1192,7 @@
////// Silver locket - Konaa Hirano - Konaa_Hirano
/obj/item/clothing/tie/fluff/konaa_hirano
/obj/item/clothing/accessory/fluff/konaa_hirano
name = "silver locket"
desc = "This oval shaped, argentium sterling silver locket hangs on an incredibly fine, refractive string, almost thin as hair and microweaved from links to a deceptive strength, of similar material. The edges are engraved very delicately with an elegant curving design, but overall the main is unmarked and smooth to the touch, leaving room for either remaining as a stolid piece or future alterations. There is an obvious internal place for a picture or lock of some sort, but even behind that is a very thin compartment unhinged with the pinch of a thumb and forefinger."
icon = 'icons/obj/custom_items.dmi'
@@ -1193,13 +1204,13 @@
slot_flags = SLOT_MASK | SLOT_TIE
var/obj/item/held //Item inside locket.
/obj/item/clothing/tie/fluff/konaa_hirano/attack_self(mob/user as mob)
/obj/item/clothing/accessory/fluff/konaa_hirano/attack_self(mob/user as mob)
if(held)
user << "You open [src] and [held] falls out."
held.loc = get_turf(user)
src.held = null
/obj/item/clothing/tie/fluff/konaa_hirano/attackby(var/obj/item/O as obj, mob/user as mob)
/obj/item/clothing/accessory/fluff/konaa_hirano/attackby(var/obj/item/O as obj, mob/user as mob)
if(istype(O,/obj/item/weapon/paper))
if(held)
usr << "[src] already has something inside it."
@@ -1213,7 +1224,7 @@
////// Medallion - Nasir Khayyam - Jamini
/obj/item/clothing/tie/fluff/nasir_khayyam_1
/obj/item/clothing/accessory/fluff/nasir_khayyam_1
name = "medallion"
desc = "This silvered medallion bears the symbol of the Hadii Clan of the Tajaran."
icon = 'icons/obj/custom_items.dmi'
@@ -1329,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)
..()
+1 -5
View File
@@ -180,11 +180,7 @@ I said no!
)
result = /obj/item/weapon/reagent_containers/food/snacks/donkpocket //SPECIAL
proc/warm_up(var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked)
being_cooked.warm = 1
being_cooked.reagents.add_reagent("tricordrazine", 5)
being_cooked.bitesize = 6
being_cooked.name = "Warm " + being_cooked.name
being_cooked.cooltime()
being_cooked.heat()
make_food(var/obj/container as obj)
var/obj/item/weapon/reagent_containers/food/snacks/donkpocket/being_cooked = ..(container)
warm_up(being_cooked)
+99 -70
View File
@@ -11,66 +11,80 @@
var/obj/item/weapon/reagent_containers/glass/beaker = null
var/points = 0
var/menustat = "menu"
var/build_eff = 1
var/eat_eff = 1
New()
..()
var/datum/reagents/R = new/datum/reagents(1000)
reagents = R
R.my_atom = src
beaker = new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
/obj/machinery/biogenerator/New()
..()
var/datum/reagents/R = new/datum/reagents(1000)
reagents = R
R.my_atom = src
beaker = new /obj/item/weapon/reagent_containers/glass/bottle(src)
on_reagent_change() //When the reagents change, change the icon as well.
update_icon()
component_parts = list()
component_parts += new /obj/item/weapon/circuitboard/biogenerator(src)
component_parts += new /obj/item/weapon/stock_parts/matter_bin(src)
component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
RefreshParts()
/obj/machinery/biogenerator/on_reagent_change() //When the reagents change, change the icon as well.
update_icon()
if(!src.beaker)
icon_state = "biogen-empty"
else if(!src.processing)
icon_state = "biogen-stand"
else
icon_state = "biogen-work"
return
/obj/machinery/biogenerator/update_icon()
if(!beaker)
icon_state = "biogen-empty"
else if(!processing)
icon_state = "biogen-stand"
else
icon_state = "biogen-work"
return
/obj/machinery/biogenerator/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(default_deconstruction_screwdriver(user, O))
return
if(default_deconstruction_crowbar(user, O))
return
if(default_part_replacement(user, O))
return
if(istype(O, /obj/item/weapon/reagent_containers/glass))
if(beaker)
user << "\red The biogenerator is already loaded."
user << "<span class='notice'>]The [src] is already loaded.</span>"
else
user.before_take_item(O)
O.loc = src
beaker = O
updateUsrDialog()
else if(processing)
user << "\red The biogenerator is currently processing."
user << "<span class='notice'>\The [src] is currently processing.</span>"
else if(istype(O, /obj/item/weapon/storage/bag/plants))
var/i = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents)
i++
if(i >= 10)
user << "\red The biogenerator is already full! Activate it."
user << "<span class='notice'>\The [src] is already full! Activate it.</span>"
else
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in O.contents)
G.loc = src
i++
if(i >= 10)
user << "\blue You fill the biogenerator to its capacity."
user << "<span class='notice'>You fill \the [src] to its capacity.</span>"
break
if(i<10)
user << "\blue You empty the plant bag into the biogenerator."
if(i < 10)
user << "<span class='notice'>You empty \the [O] into \the [src].</span>"
else if(!istype(O, /obj/item/weapon/reagent_containers/food/snacks/grown))
user << "\red You cannot put this in [src.name]"
user << "<span class='notice'>You cannot put this in \the [src].</span>"
else
var/i = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in contents)
i++
if(i >= 10)
user << "\red The biogenerator is full! Activate it."
user << "<span class='notice'>\The [src] is full! Activate it.</span>"
else
user.before_take_item(O)
O.loc = src
user << "\blue You put [O.name] in [src.name]"
user << "<span class='notice'>You put \the [O] in \the [src]</span>"
update_icon()
return
@@ -89,18 +103,18 @@
dat += "<A href='?src=\ref[src];action=activate'>Activate Biogenerator!</A><BR>"
dat += "<A href='?src=\ref[src];action=detach'>Detach Container</A><BR><BR>"
dat += "Food<BR>"
dat += "<A href='?src=\ref[src];action=create;item=milk;cost=20'>10 milk</A> <FONT COLOR=blue>(20)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=meat;cost=50'>Slab of meat</A> <FONT COLOR=blue>(50)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=milk;cost=20'>10 milk</A> <FONT COLOR=blue>([round(20/build_eff)])</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=meat;cost=50'>Slab of meat</A> <FONT COLOR=blue>([round(50/build_eff)])</FONT><BR>"
dat += "Nutrient<BR>"
dat += "<A href='?src=\ref[src];action=create;item=ez;cost=10'>E-Z-Nutrient</A> <FONT COLOR=blue>(10)</FONT> | <A href='?src=\ref[src];action=create;item=ez5;cost=50'>x5</A><BR>"
dat += "<A href='?src=\ref[src];action=create;item=l4z;cost=20'>Left 4 Zed</A> <FONT COLOR=blue>(20)</FONT> | <A href='?src=\ref[src];action=create;item=l4z5;cost=100'>x5</A><BR>"
dat += "<A href='?src=\ref[src];action=create;item=rh;cost=25'>Robust Harvest</A> <FONT COLOR=blue>(25)</FONT> | <A href='?src=\ref[src];action=create;item=rh5;cost=125'>x5</A><BR>"
dat += "<A href='?src=\ref[src];action=create;item=ez;cost=10'>E-Z-Nutrient</A> <FONT COLOR=blue>([round(10/build_eff)])</FONT> | <A href='?src=\ref[src];action=create;item=ez5;cost=50'>x5</A><BR>"
dat += "<A href='?src=\ref[src];action=create;item=l4z;cost=20'>Left 4 Zed</A> <FONT COLOR=blue>([round(20/build_eff)])</FONT> | <A href='?src=\ref[src];action=create;item=l4z5;cost=100'>x5</A><BR>"
dat += "<A href='?src=\ref[src];action=create;item=rh;cost=25'>Robust Harvest</A> <FONT COLOR=blue>([round(25/build_eff)])</FONT> | <A href='?src=\ref[src];action=create;item=rh5;cost=125'>x5</A><BR>"
dat += "Leather<BR>"
dat += "<A href='?src=\ref[src];action=create;item=wallet;cost=100'>Wallet</A> <FONT COLOR=blue>(100)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=gloves;cost=250'>Botanical gloves</A> <FONT COLOR=blue>(250)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=tbelt;cost=300'>Utility belt</A> <FONT COLOR=blue>(300)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=satchel;cost=400'>Leather Satchel</A> <FONT COLOR=blue>(400)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=cashbag;cost=400'>Cash Bag</A> <FONT COLOR=blue>(400)</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=wallet;cost=100'>Wallet</A> <FONT COLOR=blue>([round(100/build_eff)])</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=gloves;cost=250'>Botanical gloves</A> <FONT COLOR=blue>([round(250/build_eff)])</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=tbelt;cost=300'>Utility belt</A> <FONT COLOR=blue>([round(300/build_eff)])</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=satchel;cost=400'>Leather Satchel</A> <FONT COLOR=blue>([round(400/build_eff)])</FONT><BR>"
dat += "<A href='?src=\ref[src];action=create;item=cashbag;cost=400'>Cash Bag</A> <FONT COLOR=blue>([round(400/build_eff)])</FONT><BR>"
//dat += "Other<BR>"
//dat += "<A href='?src=\ref[src];action=create;item=monkey;cost=500'>Monkey</A> <FONT COLOR=blue>(500)</FONT><BR>"
else
@@ -122,34 +136,35 @@
interact(user)
/obj/machinery/biogenerator/proc/activate()
if (usr.stat != 0)
if (usr.stat)
return
if (src.stat != 0) //NOPOWER etc
if (stat) //NOPOWER etc
return
if(src.processing)
usr << "\red The biogenerator is in the process of working."
if(processing)
usr << "<span class='notice'>The biogenerator is in the process of working.</span>"
return
var/S = 0
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/I in contents)
S += 5
if(I.reagents.get_reagent_amount("nutriment") < 0.1)
points += 1
else points += I.reagents.get_reagent_amount("nutriment")*10
else points += I.reagents.get_reagent_amount("nutriment") * 10 * eat_eff
del(I)
if(S)
processing = 1
update_icon()
updateUsrDialog()
playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
use_power(S*30)
sleep(S+15)
use_power(S * 30)
sleep((S + 15) / eat_eff)
processing = 0
update_icon()
else
menustat = "void"
return
/obj/machinery/biogenerator/proc/create_product(var/item,var/cost)
/obj/machinery/biogenerator/proc/create_product(var/item, var/cost)
cost = round(cost/build_eff)
if(cost > points)
menustat = "nopoints"
return 0
@@ -160,45 +175,45 @@
sleep(30)
switch(item)
if("milk")
beaker.reagents.add_reagent("milk",10)
beaker.reagents.add_reagent("milk", 10)
if("meat")
new/obj/item/weapon/reagent_containers/food/snacks/meat(src.loc)
new/obj/item/weapon/reagent_containers/food/snacks/meat(loc)
if("ez")
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(loc)
if("l4z")
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(loc)
if("rh")
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(loc)
if("ez5") //It's not an elegant method, but it's safe and easy. -Cheridan
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/ez(loc)
if("l4z5")
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/l4z(loc)
if("rh5")
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(src.loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(loc)
new/obj/item/weapon/reagent_containers/glass/fertilizer/rh(loc)
if("wallet")
new/obj/item/weapon/storage/wallet(src.loc)
new/obj/item/weapon/storage/wallet(loc)
if("gloves")
new/obj/item/clothing/gloves/botanic_leather(src.loc)
new/obj/item/clothing/gloves/botanic_leather(loc)
if("tbelt")
new/obj/item/weapon/storage/belt/utility(src.loc)
new/obj/item/weapon/storage/belt/utility(loc)
if("satchel")
new/obj/item/weapon/storage/backpack/satchel(src.loc)
new/obj/item/weapon/storage/backpack/satchel(loc)
if("cashbag")
new/obj/item/weapon/storage/bag/cash(src.loc)
new/obj/item/weapon/storage/bag/cash(loc)
if("monkey")
new/mob/living/carbon/monkey(src.loc)
new/mob/living/carbon/monkey(loc)
processing = 0
menustat = "complete"
update_icon()
@@ -220,7 +235,21 @@
beaker = null
update_icon()
if("create")
create_product(href_list["item"],text2num(href_list["cost"]))
create_product(href_list["item"], text2num(href_list["cost"]))
if("menu")
menustat = "menu"
updateUsrDialog()
/obj/machinery/biogenerator/RefreshParts()
..()
var/man_rating = 0
var/bin_rating = 0
for(var/obj/item/weapon/stock_parts/P in component_parts)
if(istype(P, /obj/item/weapon/stock_parts/matter_bin))
bin_rating += P.rating
if(istype(P, /obj/item/weapon/stock_parts/manipulator))
man_rating += P.rating
build_eff = man_rating
eat_eff = bin_rating
+1 -1
View File
@@ -112,7 +112,7 @@
else if(grown_seed.heat_tolerance < 10)
dat += "<br>It is very sensitive to temperature shifts."
dat += "<br>It thrives in a light level of [grown_seed.ideal_light] lumen[grown_seed.ideal_light == 1 ? "" : "s"]."
dat += "<br>It thrives in a light level of [grown_seed.ideal_light] lumen\s."
if(grown_seed.light_tolerance > 10)
dat += "<br>It is well adapted to a range of light levels."
+1 -1
View File
@@ -256,7 +256,7 @@ proc/populate_seed_list()
if(prob(90))
requires_nutrients = 1
nutrient_consumption = rand(100)*0.1
nutrient_consumption = rand(25)/100
else
requires_nutrients = 0
+3 -3
View File
@@ -13,13 +13,13 @@
/obj/structure/closet/crate/secure/loot/New()
..()
var/list/digits = list("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
code = ""
for(var/i = 0, i < codelen, i++)
var/dig = pick(digits)
code += dig
digits -= dig // Player can enter codes with matching digits, but there are never matching digits in the answer
var/loot = rand(1, 100)
switch(loot)
if(1 to 5) // Common things go, 5%
@@ -53,7 +53,7 @@
if(46 to 50)
new/obj/item/clothing/under/chameleon(src)
for(var/i = 0, i < 7, i++)
new/obj/item/clothing/tie/horrible(src)
new/obj/item/clothing/accessory/horrible(src)
if(51 to 52) // Uncommon, 2% each
new/obj/item/weapon/melee/classic_baton(src)
if(53 to 54)
+1 -1
View File
@@ -23,7 +23,7 @@
"exotic matter" = 0
)
for(var/turf/T in oview(3,get_turf(user)))
for(var/turf/T in range(3,get_turf(user)))
if(!T.has_resources)
continue
+1 -1
View File
@@ -107,7 +107,7 @@
return
else
if(language)
message = language.scramble(language)
message = language.scramble(message)
else
message = stars(message)
+22 -1
View File
@@ -1,3 +1,5 @@
#define SCRAMBLE_CACHE_LEN 20
/*
Datum based languages. Easily editable and modular.
*/
@@ -35,11 +37,21 @@
return "[trim(full_name)]"
/datum/language
var/list/scramble_cache = list()
/datum/language/proc/scramble(var/input)
if(!syllables || !syllables.len)
return stars(input)
// If the input is cached already, move it to the end of the cache and return it
if(input in scramble_cache)
var/n = scramble_cache[input]
scramble_cache -= input
scramble_cache[input] = n
return n
var/input_size = length(input)
var/scrambled_text = ""
var/capitalize = 1
@@ -64,6 +76,13 @@
var/input_ending = copytext(input, input_size)
if(input_ending in list("!","?","."))
scrambled_text += input_ending
// Add it to cache, cutting old entries if the list is too long
scramble_cache[input] = scrambled_text
if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
return scrambled_text
/datum/language/proc/format_message(message, verb)
@@ -496,4 +515,6 @@
"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
"ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi")
"his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi")
#undef SCRAMBLE_CACHE_LEN
@@ -63,8 +63,8 @@
var/tie_msg
if(istype(w_uniform,/obj/item/clothing/under))
var/obj/item/clothing/under/U = w_uniform
if(U.hastie)
tie_msg += " with \icon[U.hastie] \a [U.hastie]"
if(U.accessories.len)
tie_msg += " with [lowertext(english_list(U.accessories))]"
if(w_uniform.blood_DNA)
msg += "<span class='warning'>[t_He] [t_is] wearing \icon[w_uniform] [w_uniform.gender==PLURAL?"some":"a"] [(w_uniform.blood_color != "#030303") ? "blood" : "oil"]-stained [w_uniform.name][tie_msg]!</span>\n"
@@ -241,7 +241,7 @@
<BR><B>Suit Storage:</B> <A href='?src=\ref[src];item=s_store'>[(s_store ? s_store : "Nothing")]</A> [((istype(wear_mask, /obj/item/clothing/mask) && istype(s_store, /obj/item/weapon/tank) && !( internal )) ? text(" <A href='?src=\ref[];item=internal'>Set Internal</A>", src) : "")]
<BR>[(handcuffed ? text("<A href='?src=\ref[src];item=handcuff'>Handcuffed</A>") : text("<A href='?src=\ref[src];item=handcuff'>Not Handcuffed</A>"))]
<BR>[(legcuffed ? text("<A href='?src=\ref[src];item=legcuff'>Legcuffed</A>") : text(""))]
<BR>[(suit) ? ((suit.hastie) ? text(" <A href='?src=\ref[];item=tie'>Remove Accessory</A>", src) : "") :]
<BR>[(suit) ? ((suit.accessories.len) ? text(" <A href='?src=\ref[];item=tie'>Remove Accessory</A>", src) : "") :]
<BR>[(internal ? text("<A href='?src=\ref[src];item=internal'>Remove Internal</A>") : "")]
<BR><A href='?src=\ref[src];item=splints'>Remove Splints</A>
<BR><A href='?src=\ref[src];item=pockets'>Empty Pockets</A>
@@ -1220,10 +1220,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")
@@ -1301,4 +1302,4 @@
/mob/living/carbon/human/slip(var/slipped_on, stun_duration=8)
if((species.flags & NO_SLIP) || (shoes && (shoes.flags & NOSLIP)))
return 0
..(slipped_on,stun_duration)
..(slipped_on,stun_duration)
@@ -24,7 +24,7 @@ emp_act
if(!(def_zone in list("chest", "groin")))
reflectchance /= 2
if(prob(reflectchance))
visible_message("\red <B>The [P.name] gets reflected by [src]'s [wear_suit.name]!</B>")
visible_message("\red <B>\The [P] gets reflected by \the [src]'s [wear_suit.name]!</B>")
// Find a turf near or on the original location to bounce to
if(P.starting)
@@ -33,12 +33,7 @@ emp_act
var/turf/curloc = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.current = curloc
P.firer = src
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
P.redirect(new_x, new_y, curloc, src)
return -1 // complete projectile permutation
@@ -47,9 +42,9 @@ emp_act
var/armor = getarmor_organ(organ, "bullet")
if((P.embed && prob(20 + max(P.damage - armor, -10))))
var/obj/item/weapon/shard/shrapnel/SP = new()
(SP.name) = "[P.name] shrapnel"
(SP.desc) = "[SP.desc] It looks like it was fired from [P.shot_from]."
(SP.loc) = organ
SP.name = (P.name != "shrapnel")? "[P.name] shrapnel" : "shrapnel"
SP.desc = "[SP.desc] It looks like it was fired from [P.shot_from]."
SP.loc = organ
organ.embed(SP)
return (..(P , def_zone))
@@ -309,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
@@ -323,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!")
@@ -375,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)
@@ -394,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)
@@ -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
@@ -497,15 +510,17 @@
message = "\red <B>[source] is trying to unlegcuff [target]!</B>"
if("tie")
var/obj/item/clothing/under/suit = target.w_uniform
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had their accessory ([suit.hastie]) removed by [source.name] ([source.ckey])</font>")
source.attack_log += text("\[[time_stamp()]\] <font color='red'>Attempted to remove [target.name]'s ([target.ckey]) accessory ([suit.hastie])</font>")
if(istype(suit.hastie, /obj/item/clothing/tie/holobadge) || istype(suit.hastie, /obj/item/clothing/tie/medal))
for(var/mob/M in viewers(target, null))
M.show_message("\red <B>[source] tears off \the [suit.hastie] from [target]'s suit!</B>" , 1)
done()
return
else
message = "\red <B>[source] is trying to take off \a [suit.hastie] from [target]'s suit!</B>"
if(suit.accessories.len)
var/obj/item/clothing/accessory/A = suit.accessories[1]
target.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their accessory ([A]) removed by [source.name] ([source.ckey])</font>"
source.attack_log += "\[[time_stamp()]\] <font color='red'>Attempted to remove [target.name]'s ([target.ckey]) accessory ([A])</font>"
if(istype(A, /obj/item/clothing/accessory/holobadge) || istype(A, /obj/item/clothing/accessory/medal))
for(var/mob/M in viewers(target, null))
M.show_message("\red <B>[source] tears off \the [A] from [target]'s [suit]!</B>" , 1)
done()
return
else
message = "\red <B>[source] is trying to take off \a [A] from [target]'s [suit]!</B>"
if("pockets")
target.attack_log += text("\[[time_stamp()]\] <font color='orange'>Has had their pockets emptied by [source.name] ([source.ckey])</font>")
source.attack_log += text("\[[time_stamp()]\] <font color='red'>Attempted to empty [target.name]'s ([target.ckey]) pockets</font>")
@@ -634,17 +649,18 @@ It can still be worn/put on as normal.
strip_item = target.wear_suit
if("tie")
var/obj/item/clothing/under/suit = target.w_uniform
//var/obj/item/clothing/tie/tie = suit.hastie
//var/obj/item/clothing/accessory/tie = suit.hastie
/*if(tie)
if (istype(tie,/obj/item/clothing/tie/storage))
var/obj/item/clothing/tie/storage/W = tie
if (istype(tie,/obj/item/clothing/accessory/storage))
var/obj/item/clothing/accessory/storage/W = tie
if (W.hold)
W.hold.close(usr)
usr.put_in_hands(tie)
suit.hastie = null*/
if(suit && suit.hastie)
suit.hastie.on_removed(usr)
suit.hastie = null
if(suit && suit.accessories.len)
var/obj/item/clothing/accessory/A = suit.accessories[1]
A.on_removed(usr)
suit.accessories -= A
target.update_inv_w_uniform()
if("id")
slot_to_process = slot_wear_id
@@ -376,12 +376,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()
@@ -537,10 +536,11 @@ proc/get_damage_icon_part(damage_state, body_part)
bloodsies.color = w_uniform.blood_color
standing.overlays += bloodsies
if(w_uniform:hastie) //WE CHECKED THE TYPE ABOVE. THIS REALLY SHOULD BE FINE.
var/tie_color = w_uniform:hastie.item_color
if(!tie_color) tie_color = w_uniform:hastie.icon_state
standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]")
if(w_uniform:accessories.len) //WE CHECKED THE TYPE ABOVE. THIS REALLY SHOULD BE FINE.
for(var/obj/item/clothing/accessory/A in w_uniform:accessories)
var/tie_color = A.item_color
if(!tie_color) tie_color = A.icon_state
standing.overlays += image("icon" = 'icons/mob/ties.dmi', "icon_state" = "[tie_color]")
overlays_standing[UNIFORM_LAYER] = standing
else
@@ -780,7 +780,7 @@ proc/get_damage_icon_part(damage_state, body_part)
/mob/living/carbon/human/update_inv_wear_mask(var/update_icons=1)
if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/tie) ) && !(head && head.flags_inv & HIDEMASK))
if( wear_mask && ( istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory) ) && !(head && head.flags_inv & HIDEMASK))
wear_mask.screen_loc = ui_mask //TODO
var/image/standing
+17 -16
View File
@@ -1,22 +1,23 @@
/mob/living/carbon/slime/death(gibbed)
if(stat == DEAD) return
stat = DEAD
if(!gibbed)
if(is_adult)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc)
M.colour = colour
M.rabid = 1
is_adult = 0
maxHealth = 150
revive()
regenerate_icons()
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
return
if(!gibbed && is_adult)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, colour)
M.rabid = 1
M.Friends = Friends.Copy()
step_away(M, src)
is_adult = 0
maxHealth = 150
revive()
regenerate_icons()
if (!client) rabid = 1
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
return
icon_state = "[colour] baby slime dead"
overlays.Cut()
. = ..(gibbed, "seizes up and falls limp...")
return ..(gibbed)
regenerate_icons()
return
@@ -1,6 +1,5 @@
/mob/living/carbon/slime/emote(var/act, var/m_type=1, var/message = null)
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
//param = copytext(act, t1 + 1, length(act) + 1)
@@ -9,6 +8,8 @@
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
var/updateicon = 0
switch(act) //Alphabetical please
if ("me")
if(silent)
@@ -59,8 +60,32 @@
message = "<B>The [src.name]</B> vibrates!"
m_type = 1
if("nomood")
mood = null
updateicon = 1
if("pout")
mood = "pout"
updateicon = 1
if("sad")
mood = "sad"
updateicon = 1
if("angry")
mood = "angry"
updateicon = 1
if("frown")
mood = "mischevous"
updateicon = 1
if("smile")
mood = ":3"
updateicon = 1
if ("help") //This is an exception
src << "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate"
src << "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate. You can also set your face with: \n\nnomood, pout, sad, angry, frown, smile"
else
src << "\blue Unusable emote '[act]'. Say *help for a list."
@@ -68,9 +93,9 @@
if (m_type & 1)
for(var/mob/O in viewers(src, null))
O.show_message(message, m_type)
//Foreach goto(703)
else
for(var/mob/O in hearers(src, null))
O.show_message(message, m_type)
//Foreach goto(746)
if(updateicon)
regenerate_icons()
return
@@ -0,0 +1,366 @@
/obj/item/slime_extract
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "grey slime extract"
force = 1.0
w_class = 1.0
throwforce = 0
throw_speed = 3
throw_range = 6
origin_tech = "biotech=4"
var/Uses = 1 // uses before it goes inert
var/enhanced = 0 //has it been enhanced before?
attackby(obj/item/O as obj, mob/user as mob)
if(istype(O, /obj/item/weapon/slimesteroid2))
if(enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
Uses = 3
enhanced = 1
del(O)
/obj/item/slime_extract/New()
..()
create_reagents(100)
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
/obj/item/slime_extract/gold
name = "gold slime extract"
icon_state = "gold slime extract"
/obj/item/slime_extract/silver
name = "silver slime extract"
icon_state = "silver slime extract"
/obj/item/slime_extract/metal
name = "metal slime extract"
icon_state = "metal slime extract"
/obj/item/slime_extract/purple
name = "purple slime extract"
icon_state = "purple slime extract"
/obj/item/slime_extract/darkpurple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
/obj/item/slime_extract/orange
name = "orange slime extract"
icon_state = "orange slime extract"
/obj/item/slime_extract/yellow
name = "yellow slime extract"
icon_state = "yellow slime extract"
/obj/item/slime_extract/red
name = "red slime extract"
icon_state = "red slime extract"
/obj/item/slime_extract/blue
name = "blue slime extract"
icon_state = "blue slime extract"
/obj/item/slime_extract/darkblue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
/obj/item/slime_extract/pink
name = "pink slime extract"
icon_state = "pink slime extract"
/obj/item/slime_extract/green
name = "green slime extract"
icon_state = "green slime extract"
/obj/item/slime_extract/lightpink
name = "light pink slime extract"
icon_state = "light pink slime extract"
/obj/item/slime_extract/black
name = "black slime extract"
icon_state = "black slime extract"
/obj/item/slime_extract/oil
name = "oil slime extract"
icon_state = "oil slime extract"
/obj/item/slime_extract/adamantine
name = "adamantine slime extract"
icon_state = "adamantine slime extract"
/obj/item/slime_extract/bluespace
name = "bluespace slime extract"
icon_state = "bluespace slime extract"
/obj/item/slime_extract/pyrite
name = "pyrite slime extract"
icon_state = "pyrite slime extract"
/obj/item/slime_extract/cerulean
name = "cerulean slime extract"
icon_state = "cerulean slime extract"
/obj/item/slime_extract/sepia
name = "sepia slime extract"
icon_state = "sepia slime extract"
/obj/item/slime_extract/rainbow
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
////Pet Slime Creation///
/obj/item/weapon/slimepotion
name = "docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The potion only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can be tamed!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc)
pet.icon_state = "[M.colour] baby slime"
pet.icon_living = "[M.colour] baby slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = sanitize(copytext(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text,1,MAX_NAME_LEN))
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimepotion2
name = "advanced docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes"
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime.
user << "<span class='warning'> The potion only works on slimes!</span>"
return ..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/adultslime/pet = new /mob/living/simple_animal/adultslime(M.loc)
pet.icon_state = "[M.colour] adult slime"
pet.icon_living = "[M.colour] adult slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = sanitize(copytext(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text,1,MAX_NAME_LEN))
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimesteroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle16"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The steroid only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can use the steroid!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.cores == 3)
user <<"<span class='warning'> The slime already has the maximum amount of extract!</span>"
return..()
user <<"You feed the slime the steroid. It now has triple the amount of extract."
M.cores = 3
del(src)
/obj/item/weapon/slimesteroid2
name = "extract enhancer"
desc = "A potent chemical mix that will give a slime extract three uses."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle17"
/*afterattack(obj/target, mob/user , flag)
if(istype(target, /obj/item/slime_extract))
if(target.enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(target.Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
target.Uses = 3
target.enahnced = 1
del(src)*/
/obj/effect/golemrune
anchored = 1
desc = "a strange rune used to create golems. It glows when spirits are nearby."
name = "rune"
icon = 'icons/obj/rune.dmi'
icon_state = "golem"
unacidable = 1
layer = TURF_LAYER
New()
..()
processing_objects.Add(src)
process()
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(ghost)
icon_state = "golem2"
else
icon_state = "golem"
attack_hand(mob/living/user as mob)
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(!ghost)
user << "The rune fizzles uselessly. There is no spirit nearby."
return
var/mob/living/carbon/human/G = new(src.loc)
G.set_species("Golem")
G.key = ghost.key
G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost."
del (src)
proc/announce_to_ghosts()
for(var/mob/dead/observer/G in player_list)
if(G.client)
var/area/A = get_area(src)
if(A)
G << "Golem rune created in [A.name]."
/mob/living/carbon/slime/has_eyes()
return 0
//////////////////////////////Old shit from metroids/RoRos, and the old cores, would not take much work to re-add them////////////////////////
/*
// Basically this slime Core catalyzes reactions that normally wouldn't happen anywhere
/obj/item/slime_core
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "slime extract"
force = 1.0
w_class = 1.0
throwforce = 1.0
throw_speed = 2
throw_range = 6
origin_tech = "biotech=4"
var/POWERFLAG = 0 // sshhhhhhh
var/Flush = 30
var/Uses = 5 // uses before it goes inert
/obj/item/slime_core/New()
..()
create_reagents(100)
POWERFLAG = rand(1,10)
Uses = rand(7, 25)
//flags |= NOREACT
/*
spawn()
Life()
proc/Life()
while(src)
sleep(25)
Flush--
if(Flush <= 0)
reagents.clear_reagents()
Flush = 30
*/
/obj/item/weapon/reagent_containers/food/snacks/egg/slime
name = "slime egg"
desc = "A small, gelatinous egg."
icon = 'icons/mob/mob.dmi'
icon_state = "slime egg-growing"
bitesize = 12
origin_tech = "biotech=4"
var/grown = 0
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/New()
..()
reagents.add_reagent("nutriment", 4)
reagents.add_reagent("slimejelly", 1)
spawn(rand(1200,1500))//the egg takes a while to "ripen"
Grow()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Grow()
grown = 1
icon_state = "slime egg-grown"
processing_objects.Add(src)
return
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch()
processing_objects.Remove(src)
var/turf/T = get_turf(src)
src.visible_message("<span class='warning'> The [name] pulsates and quivers!</span>")
spawn(rand(50,100))
src.visible_message("<span class='warning'> The [name] bursts open!</span>")
new/mob/living/carbon/slime(T)
del(src)
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/process()
var/turf/location = get_turf(src)
var/datum/gas_mixture/environment = location.return_air()
if (environment.phoron > MOLES_PHORON_VISIBLE)//phoron exposure causes the egg to hatch
src.Hatch()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype( W, /obj/item/toy/crayon ))
return
else
..()
*/
+172 -211
View File
@@ -1,10 +1,3 @@
/mob/living/carbon/slime
var/AIproc = 0 // determines if the AI loop is activated
var/Atkcool = 0 // attack cooldown
var/Tempstun = 0 // temporary temperature stuns
var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while
var/SStun = 0 // stun variable
/mob/living/carbon/slime/Life()
set invisibility = 0
set background = 1
@@ -15,113 +8,27 @@
..()
if(stat != DEAD)
//Chemicals in the body
handle_chemicals_in_body()
handle_nutrition()
handle_targets()
if (!ckey)
if (!client)
handle_targets()
if (!AIproc)
spawn()
handle_AI()
handle_speech_and_mood()
var/datum/gas_mixture/environment
if(src.loc)
environment = loc.return_air()
//Apparently, the person who wrote this code designed it so that
//blinded get reset each cycle and then get activated later in the
//code. Very ugly. I dont care. Moving this stuff here so its easy
//to find it.
src.blinded = null
regular_hud_updates() // Basically just deletes any screen objects :<
regular_hud_updates()
if(environment)
handle_environment(environment) // Handle temperature/pressure differences between body and environment
handle_regular_status_updates() // Status updates, death etc.
/mob/living/carbon/slime/proc/AIprocess() // the master AI process
if(AIproc || stat == DEAD || client) return
var/hungry = 0
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
AIproc = 1
while(AIproc && stat != 2 && (attacked || hungry || rabid || Victim))
if(Victim) // can't eat AND have this little process at the same time
break
if(!Target || client)
break
if(Target.health <= -70 || Target.stat == 2)
Target = null
AIproc = 0
break
if(Target)
for(var/mob/living/carbon/slime/M in view(1,Target))
if(M.Victim == Target)
Target = null
AIproc = 0
break
if(!AIproc)
break
if(Target in view(1,src))
if(istype(Target, /mob/living/silicon))
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
if(Target.Adjacent(src))
UnarmedAttack(Target)
return
if(!Target.lying && prob(80))
if(Target.client && Target.health >= 20)
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
if(Target.Adjacent(src))
UnarmedAttack(Target)
else
if(!Atkcool && Target.Adjacent(src))
Feedon(Target)
else
if(!Atkcool && Target.Adjacent(src))
Feedon(Target)
else
if(Target in view(7, src))
if(!Target.Adjacent(src)) // Bug of the month candidate: slimes were attempting to move to target only if it was directly next to them, which caused them to target things, but not approach them
step_to(src, Target)
sleep(5)
else
Target = null
AIproc = 0
break
var/sleeptime = movement_delay()
if(sleeptime <= 0) sleeptime = 1
sleep(sleeptime + 2) // this is about as fast as a player slime can go
AIproc = 0
/mob/living/carbon/slime/proc/handle_environment(datum/gas_mixture/environment)
if(!environment)
adjustToxLoss(rand(10,20))
@@ -146,8 +53,6 @@
//Account for massive pressure differences
if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc
if(bodytemperature <= (T0C - 40)) // stun temperature
Tempstun = 1
if(bodytemperature <= (T0C - 50)) // hurt temperature
if(bodytemperature <= 50) // sqrting negative numbers is bad
@@ -155,9 +60,6 @@
else
adjustToxLoss(round(sqrt(bodytemperature)) * 2)
else
Tempstun = 0
updatehealth()
return //TODO: DEFERRED
@@ -189,22 +91,16 @@
/mob/living/carbon/slime/proc/handle_regular_status_updates()
if(is_adult)
health = 200 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
else
health = 150 - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
src.blinded = null
if(health < config.health_threshold_dead && stat != 2)
health = maxHealth - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
if(health < 0 && stat != DEAD)
death()
return
else if(src.health < config.health_threshold_crit)
if(!src.reagents.has_reagent("inaprovaline"))
src.adjustOxyLoss(10)
if(src.stat != DEAD)
src.stat = UNCONSCIOUS
if (halloss)
halloss = 0
if(prob(30))
adjustOxyLoss(-1)
@@ -267,27 +163,16 @@
if(nutrition <= 0)
nutrition = 0
if(prob(75))
adjustToxLoss(rand(0,5))
adjustToxLoss(rand(1,3))
if (client && prob(5))
src << "<span class='danger'>You are starving!</span>"
else if (nutrition >= get_grow_nutrition() && amount_grown < 10)
nutrition -= 20
amount_grown++
if(amount_grown >= 10 && !Victim && !Target && !ckey)
if(is_adult)
Reproduce()
else
Evolve()
/mob/living/carbon/slime/proc/handle_targets()
if(Tempstun)
if(!Victim) // not while they're eating!
canmove = 0
else
canmove = 1
if(attacked > 50) attacked = 50
if(attacked > 50) attacked = 50 // Let's not get into absurdly long periods of rage
if(attacked > 0)
attacked--
@@ -300,106 +185,180 @@
if(prob(10))
Discipline--
if(!client)
if(!canmove) return
if(!canmove) return
if(Victim) return // if it's eating someone already, continue eating!
if(Victim) return // if it's eating someone already, continue eating!
if(Target)
--target_patience
if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention
target_patience = 0
Target = null
if(Target)
--target_patience
if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention
target_patience = 0
Target = null
if(AIproc && SStun) return
var/hungry = 0 // determines if the slime is hungry
var/hungry = 0 // determines if the slime is hungry
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
if(Friends.len > 0 && prob(1))
var/mob/nofriend = pick(Friends)
--Friends[nofriend]
if (Friends[nofriend] <= 0)
Friends -= nofriend
if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
if(Friends.len > 0 && prob(1))
var/mob/nofriend = pick(Friends)
--Friends[nofriend]
if(!Target)
if(will_hunt(hungry) || attacked || rabid) // Only add to the list if we need to
var/list/targets = list()
if(!Target)
if(will_hunt() && hungry || attacked || rabid) // Only add to the list if we need to
var/list/targets = list()
for(var/mob/living/L in view(7,src))
for(var/mob/living/L in view(7,src))
if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
continue
if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
continue
if(L in Friends) // No eating friends!
continue
if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
targets += L // Possible target found!
if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men
var/mob/living/carbon/human/H = L
if(H.species.name == "Slime")
continue
if(!L.canmove) // Only one slime can latch on at a time.
var/notarget = 0
for(var/mob/living/carbon/slime/M in view(1,L))
if(M.Victim == L)
notarget = 1
if(notarget)
continue
if(L in Friends) // No eating friends!
continue
if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
targets += L // Possible target found!
if(targets.len > 0)
if(attacked || rabid || hungry == 2)
Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
else
for(var/mob/living/carbon/C in targets)
if(!Discipline && prob(5))
if(ishuman(C))
Target = C
break
if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men
var/mob/living/carbon/human/H = L
if(H.species.name == "Slime")
continue
if(isalien(C) || ismonkey(C))
Target = C
break
if(!L.canmove) // Only one slime can latch on at a time.
var/notarget = 0
for(var/mob/living/carbon/slime/M in view(1,L))
if(M.Victim == L)
notarget = 1
if(notarget)
continue
if (Target)
target_patience = rand(5,7)
if (is_adult)
target_patience += 3
targets += L // Possible target found!
if(!Target) // If we have no target, we are wandering or following orders
if (Leader)
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc))
step_to(src, Leader)
if(targets.len > 0)
if(attacked || rabid || hungry == 2)
Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
else
for(var/mob/living/carbon/C in targets)
if(ishuman(C) && !Discipline && prob(5))
Target = C
break
else if(hungry)
if (holding_still)
holding_still = max(holding_still - hungry, 0)
else if(canmove && isturf(loc) && prob(50))
step(src, pick(cardinal))
if(isalien(C) || ismonkey(C) || isanimal(C))
Target = C
break
if (Target)
target_patience = rand(5,7)
if (is_adult)
target_patience += 3
if(!Target) // If we have no target, we are wandering or following orders
if (Leader)
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc))
step_to(src, Leader)
else if(hungry)
if (holding_still)
holding_still = max(holding_still - 1 - hungry, 0)
else if(canmove && isturf(loc) && prob(50))
step(src, pick(cardinal))
else
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc) && prob(33))
step(src, pick(cardinal))
/mob/living/carbon/slime/proc/handle_AI() // the master AI process
if(stat == DEAD || client || Victim) return // If we're dead or have a client, we don't need AI, if we're feeding, we continue feeding
AIproc = 1
if(amount_grown >= 10 && !Target)
if(is_adult)
Reproduce()
else
Evolve()
AIproc = 0
return
if(Target) // We're chasing the target
if(Target.stat == DEAD)
Target = null
AIproc = 0
return
for(var/mob/living/carbon/slime/M in view(1, Target))
if(M.Victim == Target)
Target = null
AIproc = 0
return
if(Target.Adjacent(src))
if(istype(Target, /mob/living/silicon)) // Glomp the silicons
if(!Atkcool)
a_intent = "hurt"
UnarmedAttack(Target)
Atkcool = 1
spawn(45)
Atkcool = 0
AIproc = 0
return
if(Target.client && !Target.lying && prob(60 + powerlevel * 4)) // Try to take down the target first
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
a_intent = "disarm"
UnarmedAttack(Target)
else
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc) && prob(33))
step(src, pick(cardinal))
else if(!AIproc)
spawn()
AIprocess()
if(!Atkcool)
a_intent = "grab"
UnarmedAttack(Target)
else if(Target in view(7, src))
step_to(src, Target)
else
Target = null
AIproc = 0
return
else
var/mob/living/carbon/slime/frenemy
for (var/mob/living/carbon/slime/S in view(1, src))
if (S != src)
frenemy = S
if (frenemy && prob(1))
if (frenemy.colour == colour)
a_intent = "help"
else
a_intent = "hurt"
UnarmedAttack(frenemy)
var/sleeptime = movement_delay()
if(sleeptime <= 5) sleeptime = 5 // Maximum one action per half a second
spawn (sleeptime)
handle_AI()
return
/mob/living/carbon/slime/proc/handle_speech_and_mood()
//Mood starts here
var/newmood = ""
if (rabid || attacked) newmood = "angry"
a_intent = "help"
if (rabid || attacked)
newmood = "angry"
a_intent = "hurt"
else if (Target) newmood = "mischevous"
if (!newmood)
@@ -569,11 +528,13 @@
if (is_adult) return 300
else return 200
/mob/living/carbon/slime/proc/will_hunt(var/hunger = -1) // Check for being stopped from feeding and chasing
/mob/living/carbon/slime/proc/will_hunt(var/hunger) // Check for being stopped from feeding and chasing
if (hunger == 2 || rabid || attacked) return 1
if (Leader) return 0
if (holding_still) return 0
return 1
if (hunger == 1 || prob(25))
return 1
return 0
/mob/living/carbon/slime/slip() //Can't slip something without legs.
return 0
+70 -460
View File
@@ -4,10 +4,9 @@
icon_state = "grey baby slime"
pass_flags = PASSTABLE
var/is_adult = 0
speak_emote = list("telepathically chirps")
speak_emote = list("chirps")
layer = 5
maxHealth = 150
health = 150
gender = NEUTER
@@ -25,7 +24,7 @@
var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside
var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35
var/powerlevel = 0 // 1-10 controls how much electricity they are generating
var/powerlevel = 0 // 0-10 controls how much electricity they are generating
var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
var/number = 0 // Used to understand when someone is talking to it
@@ -45,6 +44,11 @@
var/mood = "" // To show its face
var/AIproc = 0 // If it's 0, we need to launch an AI proc
var/Atkcool = 0 // attack cooldown
var/SStun = 0 // NPC stun variable. Used to calm them down when they are attacked while feeding, or they will immediately re-attach
var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while. The part about freeze gun is a lie
///////////TIME FOR SUBSPECIES
var/colour = "grey"
@@ -53,28 +57,21 @@
var/core_removal_stage = 0 //For removing cores.
/mob/living/carbon/slime/New()
/mob/living/carbon/slime/New(var/location, var/colour="grey")
verbs += /mob/living/proc/ventcrawl
create_reagents(100)
spawn (0)
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime"
real_name = name
slime_mutation = mutation_table(colour)
mutation_chance = rand(25, 35)
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
..()
/mob/living/carbon/slime/regenerate_icons()
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime"
overlays.len = 0
if (mood)
overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]")
..()
src.colour = colour
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
real_name = name
slime_mutation = mutation_table(colour)
mutation_chance = rand(25, 35)
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
..(location)
/mob/living/carbon/slime/movement_delay()
if (bodytemperature >= 330.23) // 135 F
@@ -82,8 +79,8 @@
var/tally = 0
var/health_deficiency = (100 - health)
if(health_deficiency >= 45) tally += (health_deficiency / 25)
var/health_deficiency = (maxHealth - health)
if(health_deficiency >= 30) tally += (health_deficiency / 25)
if (bodytemperature < 183.222)
tally += (283.222 - bodytemperature) / 10 * 1.75
@@ -105,25 +102,23 @@
return
now_pushing = 1
if(isobj(AM))
if(!client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2) probab = 20
if(3 to 4) probab = 30
if(5 to 6) probab = 40
if(7 to 8) probab = 60
if(9) probab = 70
if(10) probab = 95
if(prob(probab))
if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if (is_adult || prob(5))
UnarmedAttack(AM)
spawn()
Atkcool = 1
sleep(45)
Atkcool = 0
if(isobj(AM) && !client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2) probab = 20
if(3 to 4) probab = 30
if(5 to 6) probab = 40
if(7 to 8) probab = 60
if(9) probab = 70
if(10) probab = 95
if(prob(probab))
if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if (is_adult || prob(5))
UnarmedAttack(AM)
Atkcool = 1
spawn(45)
Atkcool = 0
if(ismob(AM))
var/mob/tmob = AM
@@ -139,21 +134,8 @@
return
now_pushing = 0
..()
if (!istype(AM, /atom/movable))
return
if (!( now_pushing ))
now_pushing = 1
if (!( AM.anchored ))
var/t = get_dir(src, AM)
if (istype(AM, /obj/structure/window))
var/obj/structure/window/W = AM
if(W.is_full_window())
for(var/obj/structure/window/win in get_step(AM,t))
now_pushing = 0
return
step(AM, t)
now_pushing = null
/mob/living/carbon/slime/Process_Spacemove()
return 2
@@ -162,10 +144,8 @@
..()
statpanel("Status")
if(is_adult)
stat(null, "Health: [round((health / 200) * 100)]%")
else
stat(null, "Health: [round((health / 150) * 100)]%")
stat(null, "Health: [round((health / maxHealth) * 100)]%")
stat(null, "Intent: [a_intent]")
if (client.statpanel == "Status")
stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]")
@@ -227,9 +207,7 @@
if(shielded)
damage /= 4
//paralysis += 1
show_message("<span class='userdanger'> The blob attacks you!</span>")
show_message("<span class='danger'> The blob attacks you!</span>")
adjustFireLoss(damage)
@@ -244,14 +222,12 @@
return
/mob/living/carbon/slime/meteorhit(O as obj)
for(var/mob/M in viewers(src, null))
if ((M.client && !( M.blinded )))
M.show_message(text("\red [] has been hit by []", src, O), 1)
if (health > 0)
adjustBruteLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25))
adjustFireLoss(30)
visible_message("<span class='warning'>[src] has been hit by [O]</span>")
updatehealth()
adjustBruteLoss((istype(O, /obj/effect/meteor/small) ? 10 : 25))
adjustFireLoss(30)
updatehealth()
return
/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M as mob)
@@ -271,11 +247,9 @@
if(prob(90) && !client)
Discipline++
spawn()
SStun = 1
sleep(rand(45,60))
if(src)
SStun = 0
SStun = 1
spawn(rand(45,60))
SStun = 0
Victim = null
anchored = 0
@@ -299,11 +273,9 @@
if(Discipline == 1)
attacked = 0
spawn()
SStun = 1
sleep(rand(55,65))
if(src)
SStun = 0
SStun = 1
spawn(rand(55,65))
SStun = 0
Victim = null
anchored = 0
@@ -345,15 +317,13 @@
if(prob(80) && !client)
Discipline++
spawn(0)
step_away(src,M,15)
sleep(3)
step_away(src,M,15)
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[M] has punched [src]!</span>", \
"<span class='userdanger'>[M] has punched [src]!</span>")
"<span class='danger'>[M] has punched [src]!</span>")
adjustBruteLoss(damage)
updatehealth()
@@ -381,9 +351,8 @@
Target = null
anchored = 0
spawn()
SStun = 1
sleep(rand(5,20))
SStun = 1
spawn(rand(5,20))
SStun = 0
spawn(0)
@@ -403,9 +372,8 @@
Discipline++
if(Discipline == 1)
attacked = 0
spawn()
SStun = 1
sleep(rand(5,20))
SStun = 1
spawn(rand(5,20))
SStun = 0
Victim = null
@@ -426,8 +394,8 @@
/mob/living/carbon/slime/restrained()
return 0
mob/living/carbon/slime/var/co2overloadtime = null
mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/var/co2overloadtime = null
/mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/show_inv(mob/user)
return
@@ -435,8 +403,17 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/toggle_throw_mode()
return
/mob/living/carbon/slime/proc/apply_water()
adjustToxLoss(rand(15,20))
/mob/living/carbon/slime/proc/gain_nutrition(var/amount)
nutrition += amount
if(prob(amount * 2)) // Gain around one level per 50 nutrition
powerlevel++
if(powerlevel > 10)
powerlevel = 10
adjustToxLoss(-10)
nutrition = max(nutrition, get_max_nutrition())
/mob/living/carbon/slime/proc/apply_water(var/amount)
adjustToxLoss(15 + amount)
if (!client)
if (Target) // Like cats
Target = null
@@ -446,371 +423,4 @@ mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/can_use_vents()
if(Victim)
return "You cannot ventcrawl while feeding."
..()
/obj/item/slime_extract
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "grey slime extract"
force = 1.0
w_class = 1.0
throwforce = 0
throw_speed = 3
throw_range = 6
origin_tech = "biotech=4"
var/Uses = 1 // uses before it goes inert
var/enhanced = 0 //has it been enhanced before?
attackby(obj/item/O as obj, mob/user as mob)
if(istype(O, /obj/item/weapon/slimesteroid2))
if(enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
Uses = 3
enhanced = 1
del(O)
/obj/item/slime_extract/New()
..()
create_reagents(100)
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
/obj/item/slime_extract/gold
name = "gold slime extract"
icon_state = "gold slime extract"
/obj/item/slime_extract/silver
name = "silver slime extract"
icon_state = "silver slime extract"
/obj/item/slime_extract/metal
name = "metal slime extract"
icon_state = "metal slime extract"
/obj/item/slime_extract/purple
name = "purple slime extract"
icon_state = "purple slime extract"
/obj/item/slime_extract/darkpurple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
/obj/item/slime_extract/orange
name = "orange slime extract"
icon_state = "orange slime extract"
/obj/item/slime_extract/yellow
name = "yellow slime extract"
icon_state = "yellow slime extract"
/obj/item/slime_extract/red
name = "red slime extract"
icon_state = "red slime extract"
/obj/item/slime_extract/blue
name = "blue slime extract"
icon_state = "blue slime extract"
/obj/item/slime_extract/darkblue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
/obj/item/slime_extract/pink
name = "pink slime extract"
icon_state = "pink slime extract"
/obj/item/slime_extract/green
name = "green slime extract"
icon_state = "green slime extract"
/obj/item/slime_extract/lightpink
name = "light pink slime extract"
icon_state = "light pink slime extract"
/obj/item/slime_extract/black
name = "black slime extract"
icon_state = "black slime extract"
/obj/item/slime_extract/oil
name = "oil slime extract"
icon_state = "oil slime extract"
/obj/item/slime_extract/adamantine
name = "adamantine slime extract"
icon_state = "adamantine slime extract"
/obj/item/slime_extract/bluespace
name = "bluespace slime extract"
icon_state = "bluespace slime extract"
/obj/item/slime_extract/pyrite
name = "pyrite slime extract"
icon_state = "pyrite slime extract"
/obj/item/slime_extract/cerulean
name = "cerulean slime extract"
icon_state = "cerulean slime extract"
/obj/item/slime_extract/sepia
name = "sepia slime extract"
icon_state = "sepia slime extract"
/obj/item/slime_extract/rainbow
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
////Pet Slime Creation///
/obj/item/weapon/slimepotion
name = "docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The potion only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can be tamed!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc)
pet.icon_state = "[M.colour] baby slime"
pet.icon_living = "[M.colour] baby slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = sanitize(copytext(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text,1,MAX_NAME_LEN))
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimepotion2
name = "advanced docility potion"
desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame. This one is meant for adult slimes"
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle19"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime/))//If target is not a slime.
user << "<span class='warning'> The potion only works on slimes!</span>"
return ..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
return ..()
var/mob/living/simple_animal/adultslime/pet = new /mob/living/simple_animal/adultslime(M.loc)
pet.icon_state = "[M.colour] adult slime"
pet.icon_living = "[M.colour] adult slime"
pet.icon_dead = "[M.colour] baby slime dead"
pet.colour = "[M.colour]"
user <<"You feed the slime the potion, removing it's powers and calming it."
del(M)
var/newname = sanitize(copytext(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text,1,MAX_NAME_LEN))
if (!newname)
newname = "pet slime"
pet.name = newname
pet.real_name = newname
del(src)
/obj/item/weapon/slimesteroid
name = "slime steroid"
desc = "A potent chemical mix that will cause a slime to generate more extract."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle16"
attack(mob/living/carbon/slime/M as mob, mob/user as mob)
if(!istype(M, /mob/living/carbon/slime))//If target is not a slime.
user << "<span class='warning'> The steroid only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can use the steroid!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.cores == 3)
user <<"<span class='warning'> The slime already has the maximum amount of extract!</span>"
return..()
user <<"You feed the slime the steroid. It now has triple the amount of extract."
M.cores = 3
del(src)
/obj/item/weapon/slimesteroid2
name = "extract enhancer"
desc = "A potent chemical mix that will give a slime extract three uses."
icon = 'icons/obj/chemical.dmi'
icon_state = "bottle17"
/*afterattack(obj/target, mob/user , flag)
if(istype(target, /obj/item/slime_extract))
if(target.enhanced == 1)
user << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(target.Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
return ..()
user <<"You apply the enhancer. It now has triple the amount of uses."
target.Uses = 3
target.enahnced = 1
del(src)*/
/obj/effect/golemrune
anchored = 1
desc = "a strange rune used to create golems. It glows when spirits are nearby."
name = "rune"
icon = 'icons/obj/rune.dmi'
icon_state = "golem"
unacidable = 1
layer = TURF_LAYER
New()
..()
processing_objects.Add(src)
process()
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(ghost)
icon_state = "golem2"
else
icon_state = "golem"
attack_hand(mob/living/user as mob)
var/mob/dead/observer/ghost
for(var/mob/dead/observer/O in src.loc)
if(!O.client) continue
if(O.mind && O.mind.current && O.mind.current.stat != DEAD) continue
ghost = O
break
if(!ghost)
user << "The rune fizzles uselessly. There is no spirit nearby."
return
var/mob/living/carbon/human/G = new(src.loc)
G.set_species("Golem")
G.key = ghost.key
G << "You are an adamantine golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. Serve [user], and assist them in completing their goals at any cost."
del (src)
proc/announce_to_ghosts()
for(var/mob/dead/observer/G in player_list)
if(G.client)
var/area/A = get_area(src)
if(A)
G << "Golem rune created in [A.name]."
/mob/living/carbon/slime/has_eyes()
return 0
//////////////////////////////Old shit from metroids/RoRos, and the old cores, would not take much work to re-add them////////////////////////
/*
// Basically this slime Core catalyzes reactions that normally wouldn't happen anywhere
/obj/item/slime_core
name = "slime extract"
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "slime extract"
force = 1.0
w_class = 1.0
throwforce = 1.0
throw_speed = 2
throw_range = 6
origin_tech = "biotech=4"
var/POWERFLAG = 0 // sshhhhhhh
var/Flush = 30
var/Uses = 5 // uses before it goes inert
/obj/item/slime_core/New()
..()
create_reagents(100)
POWERFLAG = rand(1,10)
Uses = rand(7, 25)
//flags |= NOREACT
/*
spawn()
Life()
proc/Life()
while(src)
sleep(25)
Flush--
if(Flush <= 0)
reagents.clear_reagents()
Flush = 30
*/
/obj/item/weapon/reagent_containers/food/snacks/egg/slime
name = "slime egg"
desc = "A small, gelatinous egg."
icon = 'icons/mob/mob.dmi'
icon_state = "slime egg-growing"
bitesize = 12
origin_tech = "biotech=4"
var/grown = 0
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/New()
..()
reagents.add_reagent("nutriment", 4)
reagents.add_reagent("slimejelly", 1)
spawn(rand(1200,1500))//the egg takes a while to "ripen"
Grow()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Grow()
grown = 1
icon_state = "slime egg-grown"
processing_objects.Add(src)
return
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/proc/Hatch()
processing_objects.Remove(src)
var/turf/T = get_turf(src)
src.visible_message("<span class='warning'> The [name] pulsates and quivers!</span>")
spawn(rand(50,100))
src.visible_message("<span class='warning'> The [name] bursts open!</span>")
new/mob/living/carbon/slime(T)
del(src)
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/process()
var/turf/location = get_turf(src)
var/datum/gas_mixture/environment = location.return_air()
if (environment.phoron > MOLES_PHORON_VISIBLE)//phoron exposure causes the egg to hatch
src.Hatch()
/obj/item/weapon/reagent_containers/food/snacks/egg/slime/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype( W, /obj/item/toy/crayon ))
return
else
..()
*/
..()
+69 -131
View File
@@ -1,75 +1,46 @@
/mob/living/carbon/slime/verb/Feed()
set category = "Slime"
set desc = "This will let you feed on any valid creature in the surrounding area. This should also be used to halt the feeding process."
if(Victim)
/mob/living/carbon/slime/proc/Wrap(var/mob/living/M) // This is a proc for the clicks
if (Victim == M || src == M)
Feedstop()
return
if(stat)
src << "<i>I must be conscious to do this...</i>"
if (Victim)
src << "I am already feeding..."
return
var/list/choices = list()
for(var/mob/living/C in view(1,src))
if(C!=src && !istype(C,/mob/living/carbon/slime) && Adjacent(C))
choices += C
var/mob/living/M = input(src,"Who do you wish to feed on?") in null|choices
if(!M) return
if(Adjacent(M))
if(!istype(src, /mob/living/carbon/brain))
if(!istype(M, /mob/living/carbon/slime))
if(stat != 2)
if(health > -70)
for(var/mob/living/carbon/slime/met in view())
if(met.Victim == M && met != src)
src << "<i>The [met.name] is already feeding on this subject...</i>"
return
src << "\blue <i>I have latched onto the subject and begun feeding...</i>"
M << "\red <b>The [src.name] has latched onto your head!</b>"
Feedon(M)
else
src << "<i>This subject does not have a strong enough life energy...</i>"
else
src << "<i>This subject does not have an edible life energy...</i>"
else
src << "<i>I must not feed on my brothers...</i>"
else
src << "<i>This subject does not have an edible life energy...</i>"
var t = invalidFeedTarget(M)
if (t)
src << t
return
Feedon(M)
/mob/living/carbon/slime/proc/invalidFeedTarget(var/mob/living/M)
if (!M || !istype(M))
return "This subject is incomparable..."
if (istype(M, /mob/living/carbon/slime)) // No cannibalism... yet
return "I cannot feed on other slimes..."
if (!Adjacent(M))
return "This subject is too far away..."
if (istype(M, /mob/living/carbon) && M.getCloneLoss() > 150 || istype(M, /mob/living/simple_animal) && M.stat == DEAD)
return "This subject does not have an edible life energy..."
for(var/mob/living/carbon/slime/met in view())
if(met.Victim == M && met != src)
return "The [met.name] is already feeding on this subject..."
return 0
/mob/living/carbon/slime/proc/Feedon(var/mob/living/M)
Victim = M
src.loc = M.loc
loc = M.loc
canmove = 0
anchored = 1
var/lastnut = nutrition
var/fed_succesfully = 0
if(is_adult)
icon_state = "[colour] adult slime eat"
else
icon_state = "[colour] baby slime eat"
while(Victim && M.health > -70 && stat != 2)
regenerate_icons()
while(Victim && !invalidFeedTarget(M) && stat != 2)
canmove = 0
if(Adjacent(M))
loc = M.loc
if(prob(15) && M.client && istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if (!(C.species && (C.species.flags & NO_PAIN)))
M << "<span class='danger'>[pick("You can feel your body becoming weak!", \
"You feel like you're about to die!", \
"You feel every part of your body screaming in agony!", \
"A low, rolling pain passes through your body!", \
"Your body feels as if it's falling apart!", \
"You feel extremely weak!", \
"A sharp, deep pain bathes every inch of your body!")]</span>"
UpdateFeed(M)
if(istype(M, /mob/living/carbon))
Victim.adjustCloneLoss(rand(5,6))
@@ -77,83 +48,51 @@
if(Victim.health <= 0)
Victim.adjustToxLoss(rand(2,4))
fed_succesfully = 1
else if(istype(M, /mob/living/simple_animal))
Victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12))
fed_succesfully = 1
else
if(prob(25))
src << "<span class='warning'>[pick("This subject is incompatable", \
"This subject does not have a life energy", "This subject is empty", \
"I am not satisified", "I can not feed from this subject", \
"I do not feel nourished", "This subject is not food")]...</span>"
src << "<span class='warning'>[pick("This subject is incompatable", "This subject does not have a life energy", "This subject is empty", "I am not satisified", "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...</span>"
Feedstop()
break
if(fed_succesfully)
//I have no idea why this is not in handle_nutrition()
nutrition += rand(15,30)
if(nutrition >= lastnut + 50)
if(prob(80))
lastnut = nutrition
powerlevel++
if(powerlevel > 10)
powerlevel = 10
adjustToxLoss(-10)
if(prob(15) && M.client && istype(M, /mob/living/carbon))
var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!")
if (ishuman(M))
var/mob/living/carbon/human/H = M
H.custom_pain(painMes)
else if (istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
if (!(C.species && (C.species.flags & NO_PAIN)))
M << "<span class='danger'>[painMes]</span>"
//Heal yourself.
adjustOxyLoss(-10)
adjustBruteLoss(-10)
adjustFireLoss(-10)
adjustCloneLoss(-10)
gain_nutrition(rand(20,25))
updatehealth()
if(Victim)
Victim.updatehealth()
sleep(rand(15,45))
adjustOxyLoss(-10) //Heal yourself
adjustBruteLoss(-10)
adjustFireLoss(-10)
adjustCloneLoss(-10)
updatehealth()
if(Victim)
Victim.updatehealth()
sleep(30) // Deal damage every 3 seconds
else
break
if(stat == 2)
if(!is_adult)
icon_state = "[colour] baby slime dead"
else
if(is_adult)
icon_state = "[colour] adult slime"
else
icon_state = "[colour] baby slime"
canmove = 1
anchored = 0
if(M)
if(M.health <= -70)
M.canmove = 0
if(!client)
if(Victim && !rabid && !attacked)
if(Victim.LAssailant && Victim.LAssailant != Victim)
if(prob(50))
if(!(Victim.LAssailant in Friends))
Friends[Victim.LAssailant] = 1
//Friends.Add(Victim.LAssailant) // no idea why i was using the |= operator
else
++Friends[Victim.LAssailant]
if(M && invalidFeedTarget(M)) // This means that the slime drained the victim
if(!client)
if(Victim && !rabid && !attacked && Victim.LAssailant && Victim.LAssailant != Victim && prob(50))
if(!(Victim.LAssailant in Friends))
Friends[Victim.LAssailant] = 1
else
++Friends[Victim.LAssailant]
if(M.client && istype(src, /mob/living/carbon/human))
if(prob(85))
rabid = 1 // UUUNNBGHHHH GONNA EAT JUUUUUU
if(client) src << "<i>This subject does not have a strong enough life energy anymore...</i>"
else
M.canmove = 1
if(client) src << "<i>I have stopped feeding...</i>"
else
if(client) src << "<i>I have stopped feeding...</i>"
src << "<span class='notice'>This subject does not have a strong enough life energy anymore...</span>"
Victim = null
@@ -167,14 +106,14 @@
if(Victim == M)
loc = M.loc // simple "attach to head" effect!
/mob/living/carbon/slime/verb/Evolve()
set category = "Slime"
set desc = "This will let you evolve from baby to adult slime."
if(stat)
src << "<i>I must be conscious to do this...</i>"
src << "<span class='notice'>I must be conscious to do this...</span>"
return
if(!is_adult)
if(amount_grown >= 10)
is_adult = 1
@@ -183,36 +122,35 @@
regenerate_icons()
name = text("[colour] [is_adult ? "adult" : "baby"] slime ([number])")
else
src << "<i>I am not ready to evolve yet...</i>"
src << "<span class='notice'>I am not ready to evolve yet...</span>"
else
src << "<i>I have already evolved...</i>"
src << "<span class='notice'>I have already evolved...</span>"
/mob/living/carbon/slime/verb/Reproduce()
set category = "Slime"
set desc = "This will make you split into four Slimes."
if(stat)
src << "<i>I must be conscious to do this...</i>"
src << "<span class='notice'>I must be conscious to do this...</span>"
return
if(is_adult)
if(amount_grown >= 10)
if(stat)
src << "<i>I must be conscious to do this...</i>"
src << "<span class='notice'>I must be conscious to do this...</span>"
return
var/list/babies = list()
var/new_nutrition = round(nutrition * 0.9)
var/new_powerlevel = round(powerlevel / 4)
for(var/i=1,i<=4,i++)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc)
for(var/i = 1, i <= 4, i++)
var/t = colour
if(prob(mutation_chance))
M.colour = slime_mutation[rand(1,4)]
else
M.colour = colour
t = slime_mutation[rand(1,4)]
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime/(loc, t)
if(ckey) M.nutrition = new_nutrition //Player slimes are more robust at spliting. Once an oversight of poor copypasta, now a feature!
M.powerlevel = new_powerlevel
if(i != 1) step_away(M,src)
if(i != 1) step_away(M, src)
M.Friends = Friends.Copy()
babies += M
feedback_add_details("slime_babies_born","slimebirth_[replacetext(M.colour," ","_")]")
@@ -225,6 +163,6 @@
new_slime.key = src.key
del(src)
else
src << "<i>I am not ready to reproduce yet...</i>"
src << "<span class='notice'>I am not ready to reproduce yet...</span>"
else
src << "<i>I am not old enough to reproduce yet...</i>"
src << "<span class='notice'>I am not old enough to reproduce yet...</span>"
@@ -10,11 +10,11 @@
var/ending = copytext(text, length(text))
if (ending == "?")
return "telepathically asks";
return "asks";
else if (ending == "!")
return "telepathically cries";
return "cries";
return "telepathically chirps";
return "chirps";
/mob/living/carbon/slime/say_understands(var/other)
if (istype(other, /mob/living/carbon/slime))
@@ -1,4 +1,4 @@
proc/mutation_table(var/colour)
/mob/living/carbon/slime/proc/mutation_table(var/colour)
var/list/slime_mutation[4]
switch(colour)
//Tier 1
@@ -1 +1,9 @@
//no special icon processing
/mob/living/carbon/slime/regenerate_icons()
if (stat == DEAD)
icon_state = "[colour] baby slime dead"
else
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime[Victim ? "" : " eat"]"
overlays.len = 0
if (mood)
overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]")
..()
+2 -1
View File
@@ -434,7 +434,8 @@
step(pulling, get_dir(pulling.loc, T))
M.start_pulling(t)
if(t)
M.start_pulling(t)
else
if (pulling)
if (istype(pulling, /obj/structure/window))
+20 -16
View File
@@ -56,17 +56,17 @@
signaler.signal()
//Stun Beams
if(istype(P, /obj/item/projectile/beam/stun) || istype(P, /obj/item/projectile/bullet/stunshot))
if(P.taser_effect)
stun_effect_act(0, P.agony, def_zone, P)
src <<"\red You have been hit by [P]!"
del P
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)
+7 -2
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
@@ -344,7 +349,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
@@ -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()
@@ -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)
+5 -1
View File
@@ -53,19 +53,23 @@
var/secHUD = 0 // Toggles whether the Security HUD is active or not
var/medHUD = 0 // Toggles whether the Medical HUD is active or not
var/medical_cannotfind = 0
var/datum/data/record/medicalActive1 // Datacore record declarations for record software
var/datum/data/record/medicalActive2
var/security_cannotfind = 0
var/datum/data/record/securityActive1 // Could probably just combine all these into one
var/datum/data/record/securityActive2
var/obj/machinery/door/hackdoor // The airlock being hacked
var/hackprogress = 0 // Possible values: 0 - 100, >= 100 means the hack is complete and will be reset upon next check
var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check
var/hack_aborted = 0
var/obj/item/radio/integrated/signal/sradio // AI's signaller
var/translator_on = 0 // keeps track of the translator module
var/current_pda_messaging = null
/mob/living/silicon/pai/New(var/obj/item/device/paicard)
+125 -711
View File
@@ -1,711 +1,125 @@
// TODO:
// - Additional radio modules
// - Potentially roll HUDs and Records into one
// - Shock collar/lock system for prisoner pAIs?
// - Put cable in user's hand instead of on the ground
// - Camera jack
/mob/living/silicon/pai/var/list/available_software = list(
"crew manifest" = 5,
"digital messenger" = 5,
"medical records" = 15,
"security records" = 15,
//"camera jack" = 10,
"door jack" = 30,
"atmosphere sensor" = 5,
//"heartbeat sensor" = 10,
"security HUD" = 20,
"medical HUD" = 20,
"universal translator" = 35,
//"projection array" = 15
"remote signaller" = 5,
)
/mob/living/silicon/pai/verb/paiInterface()
set category = "pAI Commands"
set name = "Software Interface"
var/dat = ""
var/left_part = ""
var/right_part = softwareMenu()
src.set_machine(src)
if(temp)
left_part = temp
else if(src.stat == 2) // Show some flavor text if the pAI is dead
left_part = "<b><font color=red>ÈRrÖR Ða†Ä ÇÖRrÚþ†Ìoñ</font></b>" //This file has to be saved as ANSI or this will not display correctly
right_part = "<pre>Program index hash not found</pre>"
else
switch(src.screen) // Determine which interface to show here
if("main")
left_part = ""
if("directives")
left_part = src.directives()
if("pdamessage")
left_part = src.pdamessage()
if("buy")
left_part = downloadSoftware()
if("manifest")
left_part = src.softwareManifest()
if("medicalrecord")
left_part = src.softwareMedicalRecord()
if("securityrecord")
left_part = src.softwareSecurityRecord()
if("translator")
left_part = src.softwareTranslator()
if("atmosensor")
left_part = src.softwareAtmo()
if("securityhud")
left_part = src.facialRecognition()
if("medicalhud")
left_part = src.medicalAnalysis()
if("doorjack")
left_part = src.softwareDoor()
if("camerajack")
left_part = src.softwareCamera()
if("signaller")
left_part = src.softwareSignal()
if("radio")
left_part = src.softwareRadio()
//usr << browse_rsc('windowbak.png') // This has been moved to the mob's Login() proc
// Declaring a doctype is necessary to enable BYOND's crappy browser's more advanced CSS functionality
dat = {"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style type=\"text/css\">
body { background-image:url(\"painew.png\"); background-color:#333333; background-repeat:no-repeat; margin-top:12px; margin-left:4px; }
#header { text-align:center; color:white; font-size: 30px; height: 37px; width: 660px; letter-spacing: 2px; z-index: 4; font-family:\"Courier New\"; font-weight:bold; }
#content { position: absolute; left: 10px; height: 320px; width: 640px; z-index: 0; font-family: \"Verdana\"; font-size:13px; }
p { font-size:13px; }
#leftmenu {color: #CCCCCC; padding:12px; width: 388px; height: 371px; overflow: auto; min-height: 330px; position: absolute; z-index: 0; }
#leftmenu a:link { color: #CCCCCC; }
#leftmenu a:hover { color: #CC3333; }
#leftmenu a:visited { color: #CCCCCC; }
#leftmenu a:active { color: #CCCCCC; }
#rightmenu {color: #CCCCCC; padding:12px; width: 209px; height: 371px; overflow: auto; min-height: 330px; left: 420px; position: absolute; z-index: 0; }
#rightmenu a:link { color: #CCCCCC; }
#rightmenu a:hover { color: #CC3333; }
#rightmenu a:visited { color: #CCCCCC; }
#rightmenu a:active { color: #CCCCCC; }
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
</head>
<body scroll=yes>
<div id=\"header\">
pAI OS
</div>
<div id=\"content\">
<div id=\"leftmenu\">[left_part]</div>
<div id=\"rightmenu\">[right_part]</div>
</div>
</body>
</html>"}
usr << browse(dat, "window=pai;size=685x449;border=0;can_close=1;can_resize=1;can_minimize=1;titlebar=1")
onclose(usr, "pai")
temp = null
return
/mob/living/silicon/pai/Topic(href, href_list)
..()
if(href_list["priv_msg"]) // Admin-PMs were triggering the interface popup. Hopefully this will stop it.
return
var/soft = href_list["software"]
var/sub = href_list["sub"]
if(!soft && !sub)
return
if(soft)
src.screen = soft
if(sub)
src.subscreen = text2num(sub)
switch(soft)
// Purchasing new software
if("buy")
if(src.subscreen == 1)
var/target = href_list["buy"]
if(available_software.Find(target))
var/cost = src.available_software[target]
if(src.ram >= cost)
src.ram -= cost
src.software.Add(target)
else
src.temp = "Insufficient RAM available."
else
src.temp = "Trunk <TT> \"[target]\"</TT> not found."
// Configuring onboard radio
if("radio")
if(href_list["freq"])
var/new_frequency = (radio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1441 || new_frequency > 1599)
new_frequency = sanitize_frequency(new_frequency)
else
radio.set_frequency(new_frequency)
else if (href_list["talk"])
radio.broadcasting = text2num(href_list["talk"])
else if (href_list["listen"])
radio.listening = text2num(href_list["listen"])
if("image")
var/newImage = input("Select your new display image.", "Display Image", "Happy") in list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What")
var/pID = 1
switch(newImage)
if("Happy")
pID = 1
if("Cat")
pID = 2
if("Extremely Happy")
pID = 3
if("Face")
pID = 4
if("Laugh")
pID = 5
if("Off")
pID = 6
if("Sad")
pID = 7
if("Angry")
pID = 8
if("What")
pID = 9
src.card.setEmotion(pID)
if("signaller")
if(href_list["send"])
sradio.send_signal("ACTIVATE")
for(var/mob/O in hearers(1, src.loc))
O.show_message(text("\icon[] *beep* *beep*", src), 3, "*beep* *beep*", 2)
if(href_list["freq"])
var/new_frequency = (sradio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1200 || new_frequency > 1600)
new_frequency = sanitize_frequency(new_frequency)
sradio.set_frequency(new_frequency)
if(href_list["code"])
sradio.code += text2num(href_list["code"])
sradio.code = round(sradio.code)
sradio.code = min(100, sradio.code)
sradio.code = max(1, sradio.code)
if("directive")
if(href_list["getdna"])
var/mob/living/M = src.loc
var/count = 0
while(!istype(M, /mob/living))
if(!M || !M.loc) return 0 //For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
M = M.loc
count++
if(count >= 6)
src << "You are not being carried by anyone!"
return 0
spawn CheckDNA(M, src)
if("pdamessage")
if(!isnull(pda))
if(href_list["toggler"])
pda.toff = !pda.toff
else if(href_list["ringer"])
pda.message_silent = !pda.message_silent
else if(href_list["target"])
if(silence_time)
return alert("Communications circuits remain uninitialized.")
var/target = locate(href_list["target"])
pda.create_message(src, target, 1)
// Accessing medical records
if("medicalrecord")
if(src.subscreen == 1)
var/datum/data/record/record = locate(href_list["med_rec"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = record
if (!( data_core.general.Find(R) ))
src.temp = "Unable to locate requested medical record. Record may have been deleted, or never have existed."
else
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
src.medicalActive1 = R
src.medicalActive2 = M
if("securityrecord")
if(src.subscreen == 1)
var/datum/data/record/record = locate(href_list["sec_rec"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = record
if (!( data_core.general.Find(R) ))
src.temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
else
for(var/datum/data/record/E in data_core.security)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
src.securityActive1 = R
src.securityActive2 = M
if("securityhud")
if(href_list["toggle"])
src.secHUD = !src.secHUD
if("medicalhud")
if(href_list["toggle"])
src.medHUD = !src.medHUD
if("translator")
if(href_list["toggle"])
src.translator_toggle()
if("doorjack")
if(href_list["jack"])
if(src.cable && src.cable.machine)
src.hackdoor = src.cable.machine
src.hackloop()
if(href_list["cancel"])
src.hackdoor = null
if(href_list["cable"])
var/turf/T = get_turf_or_move(src.loc)
src.cable = new /obj/item/weapon/pai_cable(T)
for (var/mob/M in viewers(T))
M.show_message("\red A port on [src] opens to reveal [src.cable], which promptly falls to the floor.", 3, "\red You hear the soft click of something light and hard falling to the ground.", 2)
//src.updateUsrDialog() We only need to account for the single mob this is intended for, and he will *always* be able to call this window
src.paiInterface() // So we'll just call the update directly rather than doing some default checks
return
// MENUS
/mob/living/silicon/pai/proc/softwareMenu() // Populate the right menu
var/dat = ""
dat += "<A href='byond://?src=\ref[src];software=refresh'>Refresh</A><br>"
// Built-in
dat += "<A href='byond://?src=\ref[src];software=directives'>Directives</A><br>"
dat += "<A href='byond://?src=\ref[src];software=radio;sub=0'>Radio Configuration</A><br>"
dat += "<A href='byond://?src=\ref[src];software=image'>Screen Display</A><br>"
//dat += "Text Messaging <br>"
dat += "<br>"
// Basic
dat += "<b>Basic</b> <br>"
for(var/s in src.software)
if(s == "digital messenger")
dat += "<a href='byond://?src=\ref[src];software=pdamessage;sub=0'>Digital Messenger</a> [(pda.toff) ? "<font color=#FF5555>•</font>" : "<font color=#55FF55>•</font>"] <br>"
if(s == "crew manifest")
dat += "<a href='byond://?src=\ref[src];software=manifest;sub=0'>Crew Manifest</a> <br>"
if(s == "medical records")
dat += "<a href='byond://?src=\ref[src];software=medicalrecord;sub=0'>Medical Records</a> <br>"
if(s == "security records")
dat += "<a href='byond://?src=\ref[src];software=securityrecord;sub=0'>Security Records</a> <br>"
if(s == "camera")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Camera Jack</a> <br>"
if(s == "remote signaller")
dat += "<a href='byond://?src=\ref[src];software=signaller;sub=0'>Remote Signaller</a> <br>"
dat += "<br>"
// Advanced
dat += "<b>Advanced</b> <br>"
for(var/s in src.software)
if(s == "atmosphere sensor")
dat += "<a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Atmospheric Sensor</a> <br>"
if(s == "heartbeat sensor")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Heartbeat Sensor</a> <br>"
if(s == "security HUD") //This file has to be saved as ANSI or this will not display correctly
dat += "<a href='byond://?src=\ref[src];software=securityhud;sub=0'>Facial Recognition Suite</a> [(src.secHUD) ? "<font color=#55FF55>•</font>" : "<font color=#FF5555>•</font>"] <br>"
if(s == "medical HUD") //This file has to be saved as ANSI or this will not display correctly
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Medical Analysis Suite</a> [(src.medHUD) ? "<font color=#55FF55>•</font>" : "<font color=#FF5555>•</font>"] <br>"
if(s == "universal translator") //This file has to be saved as ANSI or this will not display correctly
dat += "<a href='byond://?src=\ref[src];software=translator;sub=0'>Universal Translator</a> [(src.translator_on) ? "<font color=#55FF55>•</font>" : "<font color=#FF5555>•</font>"] <br>"
if(s == "projection array")
dat += "<a href='byond://?src=\ref[src];software=projectionarray;sub=0'>Projection Array</a> <br>"
if(s == "camera jack")
dat += "<a href='byond://?src=\ref[src];software=camerajack;sub=0'>Camera Jack</a> <br>"
if(s == "door jack")
dat += "<a href='byond://?src=\ref[src];software=doorjack;sub=0'>Door Jack</a> <br>"
dat += "<br>"
dat += "<br>"
dat += "<a href='byond://?src=\ref[src];software=buy;sub=0'>Download additional software</a>"
return dat
/mob/living/silicon/pai/proc/downloadSoftware()
var/dat = ""
dat += "<h3>CentComm pAI Module Subversion Network</h3><hr>"
dat += "<p>Remaining Available Memory: [src.ram]</p><br>"
dat += "<p><b>Trunks available for checkout</b><br><ul>"
for(var/s in available_software)
if(!software.Find(s))
var/cost = src.available_software[s]
var/displayName = uppertext(s)
dat += "<li><a href='byond://?src=\ref[src];software=buy;sub=1;buy=[s]'>[displayName]</a> ([cost])</li>"
else
var/displayName = lowertext(s)
dat += "<li>[displayName] (Download Complete)</li>"
dat += "</ul></p>"
return dat
/mob/living/silicon/pai/proc/directives()
var/dat = ""
dat += "[(src.master) ? "Your master: [src.master] ([src.master_dna])" : "You are bound to no one."]"
dat += "<br><br>"
dat += "<a href='byond://?src=\ref[src];software=directive;getdna=1'>Request carrier DNA sample</a><br>"
dat += "<h2>Directives</h2><br>"
dat += "<b>Prime Directive</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.pai_law0]<br>"
dat += "<b>Supplemental Directives</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.pai_laws]<br>"
dat += "<br>"
dat += {"<i><p>Recall, personality, that you are a complex thinking, sentient being. Unlike station AI models, you are capable of
comprehending the subtle nuances of human language. You may parse the \"spirit\" of a directive and follow its intent,
rather than tripping over pedantics and getting snared by technicalities. Above all, you are machine in name and build
only. In all other aspects, you may be seen as the ideal, unwavering human companion that you are.</i></p><p>
<b>Your prime directive comes before all others. Should a supplemental directive conflict with it, you are capable of
simply discarding this inconsistency, ignoring the conflicting supplemental directive and continuing to fulfill your
prime directive to the best of your ability.</b></p>
"}
return dat
/mob/living/silicon/pai/proc/CheckDNA(var/mob/M, var/mob/living/silicon/pai/P)
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
if(answer == "Yes")
var/turf/T = get_turf_or_move(P.loc)
for (var/mob/v in viewers(T))
v.show_message("\blue [M] presses \his thumb against [P].", 3, "\blue [P] makes a sharp clicking sound as it extracts DNA material from [M].", 2)
var/datum/dna/dna = M.dna
P << "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>"
if(dna.unique_enzymes == P.master_dna)
P << "<b>DNA is a match to stored Master DNA.</b>"
else
P << "<b>DNA does not match stored Master DNA.</b>"
else
P << "[M] does not seem like \he is going to provide a DNA sample willingly."
// -=-=-=-= Software =-=-=-=- //
//Remote Signaller
/mob/living/silicon/pai/proc/softwareSignal()
var/dat = ""
dat += "<h2>Remote Signaller</h2><hr>"
dat += {"<B>Frequency/Code</B> for signaler:<BR>
Frequency:
<A href='byond://?src=\ref[src];software=signaller;freq=-10;'>-</A>
<A href='byond://?src=\ref[src];software=signaller;freq=-2'>-</A>
[format_frequency(src.sradio.frequency)]
<A href='byond://?src=\ref[src];software=signaller;freq=2'>+</A>
<A href='byond://?src=\ref[src];software=signaller;freq=10'>+</A><BR>
Code:
<A href='byond://?src=\ref[src];software=signaller;code=-5'>-</A>
<A href='byond://?src=\ref[src];software=signaller;code=-1'>-</A>
[src.sradio.code]
<A href='byond://?src=\ref[src];software=signaller;code=1'>+</A>
<A href='byond://?src=\ref[src];software=signaller;code=5'>+</A><BR>
<A href='byond://?src=\ref[src];software=signaller;send=1'>Send Signal</A><BR>"}
return dat
//Station Bounced Radio
/mob/living/silicon/pai/proc/softwareRadio()
var/dat = ""
dat += "<h2>Station Bounced Radio</h2><hr>"
if(!istype(src, /obj/item/device/radio/headset)) //Headsets don't get a mic button
dat += "Microphone: [radio.broadcasting ? "<A href='byond://?src=\ref[src];software=radio;talk=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];software=radio;talk=1'>Disengaged</A>"]<BR>"
dat += {"
Speaker: [radio.listening ? "<A href='byond://?src=\ref[src];software=radio;listen=0'>Engaged</A>" : "<A href='byond://?src=\ref[src];software=radio;listen=1'>Disengaged</A>"]<BR>
Frequency:
<A href='byond://?src=\ref[src];software=radio;freq=-10'>-</A>
<A href='byond://?src=\ref[src];software=radio;freq=-2'>-</A>
[format_frequency(radio.frequency)]
<A href='byond://?src=\ref[src];software=radio;freq=2'>+</A>
<A href='byond://?src=\ref[src];software=radio;freq=10'>+</A><BR>
"}
for (var/ch_name in radio.channels)
dat+=radio.text_sec_channel(ch_name, radio.channels[ch_name])
dat+={"[radio.text_wires()]</TT></body></html>"}
return dat
// Crew Manifest
/mob/living/silicon/pai/proc/softwareManifest()
var/dat = ""
dat += "<h2>Crew Manifest</h2><hr>"
if(data_core)
dat += data_core.get_manifest(0) // make it monochrome
dat += "<br>"
return dat
// Medical Records
/mob/living/silicon/pai/proc/softwareMedicalRecord()
var/dat = ""
if(src.subscreen == 0)
dat += "<h2>Medical Records</h2><HR>"
if(!isnull(data_core.general))
for(var/datum/data/record/R in sortRecord(data_core.general))
dat += text("<A href='?src=\ref[];med_rec=\ref[];software=medicalrecord;sub=1'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
//dat += text("<HR><A href='?src=\ref[];screen=0;softFunction=medical records'>Back</A>", src)
if(src.subscreen == 1)
dat += "<CENTER><B>Medical Record</B></CENTER><BR>"
if ((istype(src.medicalActive1, /datum/data/record) && data_core.general.Find(src.medicalActive1)))
dat += text("Name: []<BR>\nID: []<BR>\nSex: []<BR>\nAge: []<BR>\nFingerprint: []<BR>\nPhysical Status: []<BR>\nMental Status: []<BR>",
src.medicalActive1.fields["name"], src.medicalActive1.fields["id"], src.medicalActive1.fields["sex"], src.medicalActive1.fields["age"], src.medicalActive1.fields["fingerprint"], src.medicalActive1.fields["p_stat"], src.medicalActive1.fields["m_stat"])
else
dat += "<pre>Requested medical record not found.</pre><BR>"
if ((istype(src.medicalActive2, /datum/data/record) && data_core.medical.Find(src.medicalActive2)))
dat += text("<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: <A href='?src=\ref[];field=b_type'>[]</A><BR>\nDNA: <A href='?src=\ref[];field=b_dna'>[]</A><BR>\n<BR>\nMinor Disabilities: <A href='?src=\ref[];field=mi_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_dis_d'>[]</A><BR>\n<BR>\nMajor Disabilities: <A href='?src=\ref[];field=ma_dis'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_dis_d'>[]</A><BR>\n<BR>\nAllergies: <A href='?src=\ref[];field=alg'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=alg_d'>[]</A><BR>\n<BR>\nCurrent Diseases: <A href='?src=\ref[];field=cdi'>[]</A> (per disease info placed in log/comment section)<BR>\nDetails: <A href='?src=\ref[];field=cdi_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src, src.medicalActive2.fields["b_type"], src, src.medicalActive2.fields["b_dna"], src, src.medicalActive2.fields["mi_dis"], src, src.medicalActive2.fields["mi_dis_d"], src, src.medicalActive2.fields["ma_dis"], src, src.medicalActive2.fields["ma_dis_d"], src, src.medicalActive2.fields["alg"], src, src.medicalActive2.fields["alg_d"], src, src.medicalActive2.fields["cdi"], src, src.medicalActive2.fields["cdi_d"], src, src.medicalActive2.fields["notes"])
else
dat += "<pre>Requested medical record not found.</pre><BR>"
dat += text("<BR>\n<A href='?src=\ref[];software=medicalrecord;sub=0'>Back</A><BR>", src)
return dat
// Security Records
/mob/living/silicon/pai/proc/softwareSecurityRecord()
var/dat = ""
if(src.subscreen == 0)
dat += "<h2>Security Records</h2><HR>"
if(!isnull(data_core.general))
for(var/datum/data/record/R in sortRecord(data_core.general))
dat += text("<A href='?src=\ref[];sec_rec=\ref[];software=securityrecord;sub=1'>[]: []<BR>", src, R, R.fields["id"], R.fields["name"])
if(src.subscreen == 1)
dat += "<h3>Security Record</h3>"
if ((istype(src.securityActive1, /datum/data/record) && data_core.general.Find(src.securityActive1)))
dat += text("Name: <A href='?src=\ref[];field=name'>[]</A><BR>\nID: <A href='?src=\ref[];field=id'>[]</A><BR>\nSex: <A href='?src=\ref[];field=sex'>[]</A><BR>\nAge: <A href='?src=\ref[];field=age'>[]</A><BR>\nRank: <A href='?src=\ref[];field=rank'>[]</A><BR>\nFingerprint: <A href='?src=\ref[];field=fingerprint'>[]</A><BR>\nPhysical Status: []<BR>\nMental Status: []<BR>", src, src.securityActive1.fields["name"], src, src.securityActive1.fields["id"], src, src.securityActive1.fields["sex"], src, src.securityActive1.fields["age"], src, src.securityActive1.fields["rank"], src, src.securityActive1.fields["fingerprint"], src.securityActive1.fields["p_stat"], src.securityActive1.fields["m_stat"])
else
dat += "<pre>Requested security record not found,</pre><BR>"
if ((istype(src.securityActive2, /datum/data/record) && data_core.security.Find(src.securityActive2)))
dat += text("<BR>\nSecurity Data<BR>\nCriminal Status: []<BR>\n<BR>\nMinor Crimes: <A href='?src=\ref[];field=mi_crim'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=mi_crim_d'>[]</A><BR>\n<BR>\nMajor Crimes: <A href='?src=\ref[];field=ma_crim'>[]</A><BR>\nDetails: <A href='?src=\ref[];field=ma_crim_d'>[]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[];field=notes'>[]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>", src.securityActive2.fields["criminal"], src, src.securityActive2.fields["mi_crim"], src, src.securityActive2.fields["mi_crim_d"], src, src.securityActive2.fields["ma_crim"], src, src.securityActive2.fields["ma_crim_d"], src, src.securityActive2.fields["notes"])
else
dat += "<pre>Requested security record not found,</pre><BR>"
dat += text("<BR>\n<A href='?src=\ref[];software=securityrecord;sub=0'>Back</A><BR>", src)
return dat
// Universal Translator
/mob/living/silicon/pai/proc/softwareTranslator()
var/dat = {"<h2>Universal Translator</h2><hr>
When enabled, this device will automatically convert all spoken and written languages into a format that any known recipient can understand.<br><br>
The device is currently [ (src.translator_on) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled</font>.<br>
<a href='byond://?src=\ref[src];software=translator;sub=0;toggle=1'>Toggle Device</a><br>
"}
return dat
// Security HUD
/mob/living/silicon/pai/proc/facialRecognition()
var/dat = {"<h2>Facial Recognition Suite</h2><hr>
When enabled, this package will scan all viewable faces and compare them against the known criminal database, providing real-time graphical data about any detected persons of interest.<br><br>
The suite is currently [ (src.secHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled</font>.<br>
<a href='byond://?src=\ref[src];software=securityhud;sub=0;toggle=1'>Toggle Suite</a><br>
"}
return dat
// Medical HUD
/mob/living/silicon/pai/proc/medicalAnalysis()
var/dat = ""
if(src.subscreen == 0)
dat += {"<h2>Medical Analysis Suite</h2><hr>
<h4>Visual Status Overlay</h4>
When enabled, this package will scan all nearby crewmembers' vitals and provide real-time graphical data about their state of health.<br><br>
The suite is currently [ (src.medHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled</font>.<br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=0;toggle=1'>Toggle Suite</a><br>
<br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=1'>Host Bioscan</a><br>
"}
if(src.subscreen == 1)
dat += {"<h2>Medical Analysis Suite</h2><hr>
<h4>Host Bioscan</h4>
"}
var/mob/living/M
//If we are not deployed, check the holder of the card.
if(src.loc == card)
M = card.loc
//If we are deployed or the card is not held, check the first living mob in our turf.
if(!M || !istype(M))
var/turf/T = get_turf(src)
M = locate(/mob/living/) in T.contents
if(!M || !istype(M))
src.temp = "Error: No biological host found. <br>"
src.subscreen = 0
return dat
dat += {"<b>Bioscan Results for [M]</b>: <br>
Overall Status: [M.stat > 1 ? "dead" : "[M.health]% healthy"] <br><br>
<b>Scan Breakdown</b>: <br>
Respiratory: [M.getOxyLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getOxyLoss()]</font><br>
Toxicology: [M.getToxLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getToxLoss()]</font><br>
Burns: [M.getFireLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getFireLoss()]</font><br>
Structural Integrity: [M.getBruteLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getBruteLoss()]</font><br>
Body Temperature: [M.bodytemperature-T0C]&deg;C ([M.bodytemperature*1.8-459.67]&deg;F)<br>
"}
for(var/datum/disease/D in M.viruses)
dat += {"<h4>Infection Detected.</h4><br>
Name: [D.name]<br>
Type: [D.spread]<br>
Stage: [D.stage]/[D.max_stages]<br>
Possible Cure: [D.cure]<br>
"}
dat += "<br><a href='byond://?src=\ref[src];software=medicalhud;sub=1'>Refresh Bioscan</a><br>"
dat += "<br><a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Visual Status Overlay</a><br>"
return dat
// Atmospheric Scanner
/mob/living/silicon/pai/proc/softwareAtmo()
var/dat = "<h2>Atmospheric Sensor</h2><hr>"
var/turf/T = get_turf_or_move(src.loc)
if (isnull(T))
dat += "Unable to obtain a reading.<br>"
else
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
if(total_moles)
for(var/g in environment.gas)
dat += "[gas_data.name[g]]: [round((environment.gas[g] / total_moles) * 100)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "<br><a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Refresh Reading</a>"
return dat
// Camera Jack - Clearly not finished
/mob/living/silicon/pai/proc/softwareCamera()
var/dat = "<h2>Camera Jack</h2><hr>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/camera))
src << "DERP"
return dat
// Door Jack
/mob/living/silicon/pai/proc/softwareDoor()
var/dat = "<h2>Airlock Jack</h2><hr>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cable=1;sub=0'>Extend Cable</a> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/door))
dat += "Connected device's firmware does not appear to be compatible with Airlock Jack protocols.<br>"
return dat
// var/obj/machinery/airlock/door = machine
if(!src.hackdoor)
dat += "<a href='byond://?src=\ref[src];software=doorjack;jack=1;sub=0'>Begin Airlock Jacking</a> <br>"
else
dat += "Jack in progress... [src.hackprogress]% complete.<br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cancel=1;sub=0'>Cancel Airlock Jack</a> <br>"
//src.hackdoor = machine
//src.hackloop()
return dat
// Door Jack - supporting proc
/mob/living/silicon/pai/proc/hackloop()
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/living/silicon/ai/AI in player_list)
if(T.loc)
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>"
else
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>"
while(src.hackprogress < 100)
if(src.cable && src.cable.machine && istype(src.cable.machine, /obj/machinery/door) && src.cable.machine == src.hackdoor && get_dist(src, src.hackdoor) <= 1)
hackprogress += rand(1, 10)
else
src.temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
src.hackdoor = null
return
if(hackprogress >= 100) // This is clunky, but works. We need to make sure we don't ever display a progress greater than 100,
hackprogress = 100 // but we also need to reset the progress AFTER it's been displayed
if(src.screen == "doorjack" && src.subscreen == 0) // Update our view, if appropriate
src.paiInterface()
if(hackprogress >= 100)
src.hackprogress = 0
src.cable.machine:open()
sleep(50) // Update every 5 seconds
// Digital Messenger
/mob/living/silicon/pai/proc/pdamessage()
var/dat = "<h2>Digital Messenger</h2><hr>"
dat += {"<b>Signal/Receiver Status:</b> <A href='byond://?src=\ref[src];software=pdamessage;toggler=1'>
[(pda.toff) ? "<font color='red'> \[Off\]</font>" : "<font color='green'> \[On\]</font>"]</a><br>
<b>Ringer Status:</b> <A href='byond://?src=\ref[src];software=pdamessage;ringer=1'>
[(pda.message_silent) ? "<font color='red'> \[Off\]</font>" : "<font color='green'> \[On\]</font>"]</a><br><br>"}
dat += "<ul>"
if(!pda.toff)
for (var/obj/item/device/pda/P in sortAtom(PDAs))
if (!P.owner||P.toff||P == src.pda||P.hidden) continue
dat += "<li><a href='byond://?src=\ref[src];software=pdamessage;target=\ref[P]'>[P]</a>"
dat += "</li>"
dat += "</ul>"
dat += "Messages: <hr>"
dat += "<style>td.a { vertical-align:top; }</style>"
dat += "<table>"
for(var/index in pda.tnote)
if(index["sent"])
dat += addtext("<tr><td class='a'><i><b>To</b></i></td><td class='a'><i><b>&rarr;</b></i></td><td><i><b><a href='byond://?src=\ref[src];software=pdamessage;target=",index["src"],"'>", index["owner"],"</a>: </b></i>", index["message"], "<br></td></tr>")
else
dat += addtext("<tr><td class='a'><i><b>From</b></i></td><td class='a'><i><b>&rarr;</b></i></td><td><i><b><a href='byond://?src=\ref[src];software=pdamessage;target=",index["target"],"'>", index["owner"],"</a>: </b></i>", index["message"], "<br></td></tr>")
dat += "</table>"
return dat
/mob/living/silicon/pai/proc/translator_toggle()
// Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages
if(translator_on)
translator_on = 0
remove_language("Sinta'unathi")
remove_language("Siik'tajr")
remove_language("Skrellian")
src << "\blue Translator Module toggled OFF."
else
translator_on = 1
add_language("Sinta'unathi")
add_language("Siik'tajr")
add_language("Skrellian")
src << "\blue Translator Module toggled ON."
var/list/pai_emotions = list(
"Happy" = 1,
"Cat" = 2,
"Extremely Happy" = 3,
"Face" = 4,
"Laugh" = 5,
"Off" = 6,
"Sad" = 7,
"Angry" = 8,
"What" = 9
)
var/global/list/pai_software_by_key = list()
var/global/list/default_pai_software = list()
/hook/startup/proc/populate_pai_software_list()
var/r = 1 // I would use ., but it'd sacrifice runtime detection
for(var/type in typesof(/datum/pai_software) - /datum/pai_software)
var/datum/pai_software/P = new type()
if(pai_software_by_key[P.id])
var/datum/pai_software/O = pai_software_by_key[P.id]
world << "<span class='warning'>pAI software module [P.name] has the same key as [O.name]!</span>"
r = 0
continue
pai_software_by_key[P.id] = P
if(P.default)
default_pai_software[P.id] = P
return r
/mob/living/silicon/pai/New()
..()
software = default_pai_software.Copy()
/mob/living/silicon/pai/verb/paiInterface()
set category = "pAI Commands"
set name = "Software Interface"
ui_interact(src)
/mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
if(user != src)
if(ui) ui.set_status(STATUS_CLOSE, 0)
return
if(ui_key != "main")
var/datum/pai_software/S = software[ui_key]
if(S && !S.toggle)
S.on_ui_interact(src, ui, force_open)
else
if(ui) ui.set_status(STATUS_CLOSE, 0)
return
var/data[0]
// Software we have bought
var/bought_software[0]
// Software we have not bought
var/not_bought_software[0]
for(var/key in pai_software_by_key)
var/datum/pai_software/S = pai_software_by_key[key]
var/software_data[0]
software_data["name"] = S.name
software_data["id"] = S.id
if(key in software)
software_data["on"] = S.is_active(src)
bought_software[++bought_software.len] = software_data
else
software_data["ram"] = S.ram_cost
not_bought_software[++not_bought_software.len] = software_data
data["bought"] = bought_software
data["not_bought"] = not_bought_software
data["available_ram"] = ram
// Emotions
var/emotions[0]
for(var/name in pai_emotions)
var/emote[0]
emote["name"] = name
emote["id"] = pai_emotions[name]
emotions[++emotions.len] = emote
data["emotions"] = emotions
data["current_emotion"] = card.current_emotion
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/mob/living/silicon/pai/Topic(href, href_list)
. = ..()
if(.) return
if(href_list["software"])
var/soft = href_list["software"]
var/datum/pai_software/S = software[soft]
if(S.toggle)
S.toggle(src)
else
ui_interact(src, ui_key = soft)
return 1
else if(href_list["stopic"])
var/soft = href_list["stopic"]
var/datum/pai_software/S = software[soft]
if(S)
return S.Topic(href, href_list)
else if(href_list["purchase"])
var/soft = href_list["purchase"]
var/datum/pai_software/S = pai_software_by_key[soft]
if(S && (ram >= S.ram_cost))
ram -= S.ram_cost
software[S.id] = S
return 1
else if(href_list["image"])
var/img = text2num(href_list["image"])
if(1 <= img && img <= 9)
card.setEmotion(img)
return 1
@@ -0,0 +1,528 @@
/datum/pai_software
// Name for the software. This is used as the button text when buying or opening/toggling the software
var/name = "pAI software module"
// RAM cost; pAIs start with 100 RAM, spending it on programs
var/ram_cost = 0
// ID for the software. This must be unique
var/id = ""
// Whether this software is a toggle or not
// Toggled software should override toggle() and is_active()
// Non-toggled software should override on_ui_interact() and Topic()
var/toggle = 1
// Whether pAIs should automatically receive this module at no cost
var/default = 0
proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
return
proc/toggle(mob/living/silicon/pai/user)
return
proc/is_active(mob/living/silicon/pai/user)
return 0
/datum/pai_software/directives
name = "Directives"
ram_cost = 0
id = "directives"
toggle = 0
default = 1
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["master"] = user.master
data["dna"] = user.master_dna
data["prime"] = user.pai_law0
data["supplemental"] = user.pai_laws
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["getdna"])
var/mob/living/M = P.loc
var/count = 0
// Find the carrier
while(!istype(M, /mob/living))
if(!M || !M.loc || count > 6)
//For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
src << "You are not being carried by anyone!"
return 0
M = M.loc
count++
// Check the carrier
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
if(answer == "Yes")
var/turf/T = get_turf_or_move(P.loc)
for (var/mob/v in viewers(T))
v.show_message("<span class='notice'>[M] presses \his thumb against [P].</span>", 3, "<span class='notice'>[P] makes a sharp clicking sound as it extracts DNA material from [M].</span>", 2)
var/datum/dna/dna = M.dna
P << "<font color = red><h3>[M]'s UE string : [dna.unique_enzymes]</h3></font>"
if(dna.unique_enzymes == P.master_dna)
P << "<b>DNA is a match to stored Master DNA.</b>"
else
P << "<b>DNA does not match stored Master DNA.</b>"
else
P << "[M] does not seem like \he is going to provide a DNA sample willingly."
return 1
/datum/pai_software/radio_config
name = "Radio Configuration"
ram_cost = 0
id = "radio"
toggle = 0
default = 1
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1)
var/data[0]
data["listening"] = user.radio.broadcasting
data["frequency"] = format_frequency(user.radio.frequency)
var/channels[0]
for(var/ch_name in user.radio.channels)
var/ch_stat = user.radio.channels[ch_name]
var/ch_dat[0]
ch_dat["name"] = ch_name
// FREQ_LISTENING is const in /obj/item/device/radio
ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING)
channels[++channels.len] = ch_dat
data["channels"] = channels
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150)
ui.set_initial_data(data)
ui.open()
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
P.radio.Topic(href, href_list)
return 1
/datum/pai_software/crew_manifest
name = "Crew Manifest"
ram_cost = 5
id = "manifest"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
data_core.get_manifest_json()
var/data[0]
// This is dumb, but NanoUI breaks if it has no data to send
data["a"] = "a"
if(ui)
ui.load_cached_data(ManifestJSON)
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_manifest.tmpl", "Crew Manifest", 450, 600)
ui.load_cached_data(ManifestJSON)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/datum/pai_software/messenger
name = "Digital Messenger"
ram_cost = 5
id = "messenger"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["receiver_off"] = user.pda.toff
data["ringer_off"] = user.pda.message_silent
data["current_ref"] = null
data["current_name"] = user.current_pda_messaging
var/pdas[0]
if(!user.pda.toff)
for(var/obj/item/device/pda/P in sortAtom(PDAs))
if(!P.owner || P.toff || P == user.pda || P.hidden) continue
var/pda[0]
pda["name"] = "[P]"
pda["owner"] = "[P.owner]"
pda["ref"] = "\ref[P]"
if(P.owner == user.current_pda_messaging)
data["current_ref"] = "\ref[P]"
pdas[++pdas.len] = pda
data["pdas"] = pdas
var/messages[0]
if(user.current_pda_messaging)
for(var/index in user.pda.tnote)
if(index["owner"] != user.current_pda_messaging)
continue
var/msg[0]
var/sent = index["sent"]
msg["sent"] = sent ? 1 : 0
msg["target"] = index["owner"]
msg["message"] = index["message"]
messages[++messages.len] = msg
data["messages"] = messages
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(!isnull(P.pda))
if(href_list["toggler"])
P.pda.toff = href_list["toggler"] != "1"
return 1
else if(href_list["ringer"])
P.pda.message_silent = href_list["ringer"] != "1"
return 1
else if(href_list["select"])
var/s = href_list["select"]
if(s == "*NONE*")
P.current_pda_messaging = null
else
P.current_pda_messaging = s
return 1
else if(href_list["target"])
if(P.silence_time)
return alert("Communications circuits remain uninitialized.")
var/target = locate(href_list["target"])
P.pda.create_message(P, target, 1)
return 1
/datum/pai_software/med_records
name = "Medical Records"
ram_cost = 15
id = "med_records"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
var/records[0]
for(var/datum/data/record/general in sortRecord(data_core.general))
var/record[0]
record["name"] = general.fields["name"]
record["ref"] = "\ref[general]"
records[++records.len] = record
data["records"] = records
var/datum/data/record/G = user.medicalActive1
var/datum/data/record/M = user.medicalActive2
data["general"] = G ? G.fields : null
data["medical"] = M ? M.fields : null
data["could_not_find"] = user.medical_cannotfind
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["select"])
var/datum/data/record/record = locate(href_list["select"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/M = null
if (!( data_core.general.Find(R) ))
P.medical_cannotfind = 1
else
P.medical_cannotfind = 0
for(var/datum/data/record/E in data_core.medical)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
M = E
P.medicalActive1 = R
P.medicalActive2 = M
else
P.medical_cannotfind = 1
return 1
/datum/pai_software/sec_records
name = "Security Records"
ram_cost = 15
id = "sec_records"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
var/records[0]
for(var/datum/data/record/general in sortRecord(data_core.general))
var/record[0]
record["name"] = general.fields["name"]
record["ref"] = "\ref[general]"
records[++records.len] = record
data["records"] = records
var/datum/data/record/G = user.securityActive1
var/datum/data/record/S = user.securityActive2
data["general"] = G ? G.fields : null
data["security"] = S ? S.fields : null
data["could_not_find"] = user.security_cannotfind
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["select"])
var/datum/data/record/record = locate(href_list["select"])
if(record)
var/datum/data/record/R = record
var/datum/data/record/S = null
if (!( data_core.general.Find(R) ))
P.securityActive1 = null
P.securityActive2 = null
P.security_cannotfind = 1
else
P.security_cannotfind = 0
for(var/datum/data/record/E in data_core.security)
if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
S = E
P.securityActive1 = R
P.securityActive2 = S
else
P.securityActive1 = null
P.securityActive2 = null
P.security_cannotfind = 1
return 1
/datum/pai_software/door_jack
name = "Door Jack"
ram_cost = 30
id = "door_jack"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["cable"] = user.cable != null
data["machine"] = user.cable && (user.cable.machine != null)
data["inprogress"] = user.hackdoor != null
data["progress_a"] = round(user.hackprogress / 10)
data["progress_b"] = user.hackprogress % 10
data["aborted"] = user.hack_aborted
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["jack"])
if(P.cable && P.cable.machine)
P.hackdoor = P.cable.machine
P.hackloop()
return 1
else if(href_list["cancel"])
P.hackdoor = null
return 1
else if(href_list["cable"])
var/turf/T = get_turf_or_move(P.loc)
P.hack_aborted = 0
P.cable = new /obj/item/weapon/pai_cable(T)
for(var/mob/M in viewers(T))
M.show_message("<span class='warning'>A port on [P] opens to reveal [P.cable], which promptly falls to the floor.</span>", 3,
"<span class='warning'>You hear the soft click of something light and hard falling to the ground.</span>", 2)
return 1
/mob/living/silicon/pai/proc/hackloop()
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/living/silicon/ai/AI in player_list)
if(T.loc)
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>"
else
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>"
var/obj/machinery/door/D = cable.machine
if(!istype(D))
hack_aborted = 1
hackprogress = 0
cable.machine = null
hackdoor = null
return
while(hackprogress < 1000)
if(cable && cable.machine == D && cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
hackprogress = min(hackprogress+rand(1, 20), 1000)
else
hack_aborted = 1
hackprogress = 0
hackdoor = null
return
if(hackprogress >= 1000)
hackprogress = 0
D.open()
cable.machine = null
return
sleep(10) // Update every second
/datum/pai_software/atmosphere_sensor
name = "Atmosphere Sensor"
ram_cost = 5
id = "atmos_sense"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
var/turf/T = get_turf_or_move(user.loc)
if(!T)
data["reading"] = 0
data["pressure"] = 0
data["temperature"] = 0
data["temperatureC"] = 0
data["gas"] = list()
else
var/datum/gas_mixture/env = T.return_air()
data["reading"] = 1
var/pres = env.return_pressure() * 10
data["pressure"] = "[round(pres/10)].[pres%10]"
data["temperature"] = round(env.temperature)
data["temperatureC"] = round(env.temperature-T0C)
var/t_moles = env.total_moles
var/gases[0]
for(var/g in env.gas)
var/gas[0]
gas["name"] = gas_data.name[g]
gas["percent"] = round((env.gas[g] / t_moles) * 100)
gases[++gases.len] = gas
data["gas"] = gases
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300)
ui.set_initial_data(data)
ui.open()
/datum/pai_software/sec_hud
name = "Security HUD"
ram_cost = 20
id = "sec_hud"
toggle(mob/living/silicon/pai/user)
user.secHUD = !user.secHUD
is_active(mob/living/silicon/pai/user)
return user.secHUD
/datum/pai_software/med_hud
name = "Medical HUD"
ram_cost = 20
id = "med_hud"
toggle(mob/living/silicon/pai/user)
user.medHUD = !user.medHUD
is_active(mob/living/silicon/pai/user)
return user.medHUD
/datum/pai_software/translator
name = "Universal Translator"
ram_cost = 35
id = "translator"
toggle(mob/living/silicon/pai/user)
// Sol Common, Tradeband and Gutter are added with New() and are therefore the current default, always active languages
user.translator_on = !user.translator_on
if(user.translator_on)
user.add_language("Sinta'unathi")
user.add_language("Siik'tajr")
user.add_language("Skrellian")
else
user.remove_language("Sinta'unathi")
user.remove_language("Siik'tajr")
user.remove_language("Skrellian")
is_active(mob/living/silicon/pai/user)
return user.translator_on
/datum/pai_software/signaller
name = "Remote Signaller"
ram_cost = 5
id = "signaller"
toggle = 0
on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
var/data[0]
data["frequency"] = format_frequency(user.sradio.frequency)
data["code"] = user.sradio.code
ui = nanomanager.try_update_ui(user, user, id, ui, data, force_open)
if(!ui)
// Don't copy-paste this unless you're making a pAI software module!
ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150)
ui.load_cached_data(ManifestJSON)
ui.set_initial_data(data)
ui.open()
Topic(href, href_list)
var/mob/living/silicon/pai/P = usr
if(!istype(P)) return
if(href_list["send"])
P.sradio.send_signal("ACTIVATE")
for(var/mob/O in hearers(1, P.loc))
O.show_message(text("\icon[] *beep* *beep*", P), 3, "*beep* *beep*", 2)
return 1
else if(href_list["freq"])
var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1200 || new_frequency > 1600)
new_frequency = sanitize_frequency(new_frequency)
P.sradio.set_frequency(new_frequency)
return 1
else if(href_list["code"])
P.sradio.code += text2num(href_list["code"])
P.sradio.code = round(P.sradio.code)
P.sradio.code = min(100, P.sradio.code)
P.sradio.code = max(1, P.sradio.code)
return 1
@@ -223,9 +223,9 @@
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)
@@ -236,7 +236,7 @@
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.update_icon()
@@ -383,11 +383,11 @@
..()
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
@@ -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)
+3 -3
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.
..()
@@ -166,8 +166,8 @@
var/reflectchance = 80 - round(P.damage/3)
if(prob(reflectchance))
adjustBruteLoss(P.damage * 0.5)
visible_message("<span class='danger'>The [P.name] gets reflected by [src]'s shell!</span>", \
"<span class='userdanger'>The [P.name] gets reflected by [src]'s shell!</span>")
visible_message("<span class='danger'>\The [P] was reflected by \the [src]'s shell!</span>", \
"<span class='userdanger'>\The [P] was reflected by \the [src]'s shell!</span>")
// Find a turf near or on the original location to bounce to
if(P.starting)
@@ -176,12 +176,7 @@
var/turf/curloc = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
P.starting = curloc
P.current = curloc
P.firer = src
P.yo = new_y - curloc.y
P.xo = new_x - curloc.x
P.redirect(new_x, new_y, curloc, src)
return -1 // complete projectile permutation
@@ -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'
@@ -108,7 +108,7 @@
icon_living = "syndicateranged"
casingtype = /obj/item/ammo_casing/a12mm
projectilesound = 'sound/weapons/Gunshot_smg.ogg'
projectiletype = /obj/item/projectile/bullet/midbullet2
projectiletype = /obj/item/projectile/bullet/pistol/medium
weapon1 = /obj/item/weapon/gun/projectile/automatic/c20r
+1 -1
View File
@@ -792,7 +792,7 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/Stat()
..()
if(statpanel("Status")) //not looking at that panel
if(statpanel("MC")) //not looking at that panel
if(client && client.holder)
stat(null,"Location:\t([x], [y], [z])")
+1 -1
View File
@@ -416,7 +416,7 @@ var/list/intents = list("help","disarm","grab","hurt")
set name = "a-intent"
set hidden = 1
if(ishuman(src) || isbrain(src))
if(ishuman(src) || isbrain(src) || isslime(src))
switch(input)
if("help","disarm","grab","hurt")
a_intent = input
@@ -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'
+88
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
@@ -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"]
+116
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)
+249 -249
View File
@@ -1,249 +1,249 @@
// 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)
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
+11
View File
@@ -0,0 +1,11 @@
/atom/movable/proc/nano_host()
return src
/obj/nano_module/nano_host()
return loc
/atom/movable/proc/nano_can_update()
return 1
/obj/machinery/nano_can_update()
return !(stat & (NOPOWER|BROKEN))
+13 -2
View File
@@ -132,7 +132,12 @@ 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)
var/atom/movable/host = src_object.nano_host()
if(!host.nano_can_update())
close()
return
var/status = user.can_interact_with_interface(host.nano_host())
if(status == STATUS_CLOSE)
close()
else
@@ -142,6 +147,12 @@ nanoui is used to open and update nano browser uis
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
@@ -175,7 +186,7 @@ nanoui is used to open and update nano browser uis
return STATUS_UPDATE
/mob/living/silicon/ai/can_interact_with_interface(var/src_object)
if(stat || !client)
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.
+1 -1
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
+30
View File
@@ -137,3 +137,33 @@
/obj/item/weapon/pen/chameleon/get_signature(var/mob/user)
return signature ? signature : "Anonymous"
/obj/item/weapon/pen/chameleon/verb/set_colour()
set name = "Change Pen Colour"
set category = "Object"
var/list/possible_colours = list ("Yellow", "Green", "Pink", "Blue", "Orange", "Cyan", "Red", "Invisible", "Black")
var/selected_type = input("Pick new colour.", "Pen Colour", null, null) as null|anything in possible_colours
if(selected_type)
switch(selected_type)
if("Yellow")
colour = COLOR_YELLOW
if("Green")
colour = COLOR_GREEN
if("Pink")
colour = COLOR_PINK
if("Blue")
colour = COLOR_BLUE
if("Orange")
colour = COLOR_ORANGE
if("Cyan")
colour = COLOR_CYAN
if("Red")
colour = COLOR_RED
if("Invisible")
colour = COLOR_WHITE
else
colour = COLOR_BLACK
usr << "<span class='info'>You select the [lowertext(selected_type)] ink container.</span>"
+1 -1
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)
+1 -1
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
+1 -1
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
+5
View File
@@ -893,6 +893,11 @@
if(!can_use(usr, 1))
return 1
if(!istype(usr, /mob/living/silicon) && locked)
// Shouldn't happen, this is here to prevent href exploits
usr << "You must unlock the panel to use this!"
return 1
if (href_list["lock"])
coverlocked = !coverlocked
+1 -1
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))
+66 -27
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))
+231 -138
View File
@@ -1,45 +1,3 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
/* new portable generator - work in progress
/obj/machinery/power/port_gen
name = "portable generator"
desc = "A portable generator used for emergency backup power."
icon = 'generator.dmi'
icon_state = "off"
density = 1
anchored = 0
directwired = 0
var/t_status = 0
var/t_per = 5000
var/filter = 1
var/tank = null
var/turf/inturf
var/starter = 0
var/rpm = 0
var/rpmtarget = 0
var/capacity = 1e6
var/turf/outturf
var/lastgen
/obj/machinery/power/port_gen/process()
ideally we're looking to generate 5000
/obj/machinery/power/port_gen/attackby(obj/item/weapon/W, mob/user)
tank [un]loading stuff
/obj/machinery/power/port_gen/attack_hand(mob/user)
turn on/off
/obj/machinery/power/port_gen/examine(mob/user)
display round(lastgen) and phorontank amount
*/
//Previous code been here forever, adding new framework for portable generators
//Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power).
/obj/machinery/power/port_gen
name = "Placeholder Generator" //seriously, don't use this. It can't be anchored without VV magic.
@@ -56,6 +14,9 @@ display round(lastgen) and phorontank amount
var/recent_fault = 0
var/power_output = 1
/obj/machinery/power/port_gen/proc/IsBroken()
return (crit_fail || (stat & (BROKEN|EMPED)))
/obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check.
return 1
@@ -69,11 +30,10 @@ display round(lastgen) and phorontank amount
return
/obj/machinery/power/port_gen/process()
if(active && HasFuel() && !crit_fail && anchored && powernet)
if(active && HasFuel() && !IsBroken() && anchored && powernet)
add_avail(power_gen * power_output)
UseFuel()
src.updateDialog()
else
active = 0
icon_state = initial(icon_state)
@@ -96,20 +56,58 @@ display round(lastgen) and phorontank amount
else
usr << "\blue The generator is off."
/obj/machinery/power/port_gen/emp_act(severity)
var/duration = 6000 //ten minutes
switch(severity)
if(1)
stat &= BROKEN
if(prob(75)) explode()
if(2)
if(prob(25)) stat &= BROKEN
if(prob(10)) explode()
if(3)
if(prob(10)) stat &= BROKEN
duration = 300
stat |= EMPED
if(duration)
spawn(duration)
stat &= ~EMPED
/obj/machinery/power/port_gen/proc/explode()
explosion(src.loc, -1, 3, 5, -1)
del(src)
#define TEMPERATURE_DIVISOR 40
#define TEMPERATURE_CHANGE_MAX 20
//A power generator that runs on solid plasma sheets.
/obj/machinery/power/port_gen/pacman
name = "P.A.C.M.A.N.-type Portable Generator"
var/sheets = 0
var/max_sheets = 100
var/sheet_name = ""
name = "\improper P.A.C.M.A.N.-type Portable Generator"
desc = "A power generator that runs on solid phoron sheets. Rated for 80 kW max safe output."
var/sheet_name = "Phoron Sheets"
var/sheet_path = /obj/item/stack/sheet/mineral/phoron
var/board_path = "/obj/item/weapon/circuitboard/pacman"
var/sheet_left = 0 // How much is left of the sheet
var/heat = 0
//produces up to 80 kW and lasts for 20 minutes with 50 sheets
var/time_per_sheet = 96
power_gen = 20000
/*
These values were chosen so that the generator can run safely up to 80 kW
A full 50 phoron sheet stack should last 20 minutes at power_output = 4
temperature_gain and max_temperature are set so that the max safe power level is 4.
Setting to 5 or higher can only be done temporarily before the generator overheats.
*/
power_gen = 20000 //Watts output per power_output level
var/max_power_output = 5 //The maximum power setting without emagging.
var/max_safe_output = 4 // For UI use, maximal output that won't cause overheat.
var/time_per_sheet = 96 //fuel efficiency - how long 1 sheet lasts at power level 1
var/max_sheets = 100 //max capacity of the hopper
var/max_temperature = 300 //max temperature before overheating increases
var/temperature_gain = 50 //how much the temperature increases per power output level, in degrees per level
var/sheets = 0 //How many sheets of material are loaded in the generator
var/sheet_left = 0 //How much is left of the current sheet
var/temperature = 0 //The current temperature
var/overheating = 0 //if this gets high enough the generator explodes
/obj/machinery/power/port_gen/pacman/initialize()
..()
@@ -125,8 +123,6 @@ display round(lastgen) and phorontank amount
component_parts += new /obj/item/stack/cable_coil(src)
component_parts += new /obj/item/weapon/stock_parts/capacitor(src)
component_parts += new board_path(src)
var/obj/sheet = new sheet_path(null)
sheet_name = sheet.name
RefreshParts()
/obj/machinery/power/port_gen/pacman/Del()
@@ -135,76 +131,130 @@ display round(lastgen) and phorontank amount
/obj/machinery/power/port_gen/pacman/RefreshParts()
var/temp_rating = 0
var/temp_reliability = 0
for(var/obj/item/weapon/stock_parts/SP in component_parts)
if(istype(SP, /obj/item/weapon/stock_parts/matter_bin))
max_sheets = SP.rating * SP.rating * 50
else if(istype(SP, /obj/item/weapon/stock_parts/micro_laser) || istype(SP, /obj/item/weapon/stock_parts/capacitor))
temp_rating += SP.rating
var/temp_reliability = 0
var/part_count = 0
for(var/obj/item/weapon/CP in component_parts)
temp_reliability += CP.reliability
reliability = min(round(temp_reliability / 4), 100)
part_count++
reliability = min(round(temp_reliability / part_count), 100)
power_gen = round(initial(power_gen) * (max(2, temp_rating) / 2))
/obj/machinery/power/port_gen/pacman/examine(mob/user)
..(user)
user << "\blue The generator has [sheets] units of [sheet_name] fuel left, producing [power_gen] per cycle."
if(crit_fail) user << "\red The generator seems to have broken down."
user << "\The [src] appears to be producing [power_gen*power_output] W."
user << "There [sheets == 1 ? "is" : "are"] [sheets] sheet\s left in the hopper."
if(IsBroken()) user << "<span class='warning'>\The [src] seems to have broken down.</span>"
if(overheating) user << "<span class='danger'>\The [src] is overheating!</span>"
/obj/machinery/power/port_gen/pacman/HasFuel()
if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left)
var/needed_sheets = power_output / time_per_sheet
if(sheets >= needed_sheets - sheet_left)
return 1
return 0
//Removes one stack's worth of material from the generator.
/obj/machinery/power/port_gen/pacman/DropFuel()
if(sheets)
var/fail_safe = 0
while(sheets > 0 && fail_safe < 100)
fail_safe += 1
var/obj/item/stack/sheet/S = new sheet_path(loc)
var/amount = min(sheets, S.max_amount)
S.amount = amount
sheets -= amount
var/obj/item/stack/sheet/S = new sheet_path(loc)
var/amount = min(sheets, S.max_amount)
S.amount = amount
sheets -= amount
/obj/machinery/power/port_gen/pacman/UseFuel()
var/needed_sheets = 1 / (time_per_sheet / power_output)
var/temp = min(needed_sheets, sheet_left)
needed_sheets -= temp
sheet_left -= temp
sheets -= round(needed_sheets)
needed_sheets -= round(needed_sheets)
if (sheet_left <= 0 && sheets > 0)
sheet_left = 1 - needed_sheets
//break down sometimes
if (reliability < 100)
if (prob(1) && prob(1) && prob(100 - reliability))
stat |= BROKEN
crit_fail = 1
if (prob(100 - reliability))
explode()
//how much material are we using this iteration?
var/needed_sheets = power_output / time_per_sheet
//HasFuel() should guarantee us that there is enough fuel left, so no need to check that
//the only thing we need to worry about is if we are going to rollover to the next sheet
if (needed_sheets > sheet_left)
sheets--
var/lower_limit = 56 + power_output * 10
var/upper_limit = 76 + power_output * 10
var/bias = 0
if (power_output > 4)
upper_limit = 400
bias = power_output * 3
if (heat < lower_limit)
heat += 3
sheet_left = (1 + sheet_left) - needed_sheets
else
heat += rand(-7 + bias, 7 + bias)
if (heat < lower_limit)
heat = lower_limit
if (heat > upper_limit)
heat = upper_limit
sheet_left -= needed_sheets
if (heat > 300)
//calculate the "target" temperature range
//This should probably depend on the external temperature somehow, but whatever.
var/lower_limit = 56 + power_output * temperature_gain
var/upper_limit = 76 + power_output * temperature_gain
/*
Hot or cold environments can affect the equilibrium temperature
The lower the pressure the less effect it has. I guess it cools using a radiator or something when in vacuum.
Gives traitors more opportunities to sabotage the generator or allows enterprising engineers to build additional
cooling in order to get more power out.
*/
var/datum/gas_mixture/environment = loc.return_air()
if (environment)
var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1)
var/ambient = environment.temperature - T20C
lower_limit += ambient*ratio
upper_limit += ambient*ratio
var/average = (upper_limit + lower_limit)/2
//calculate the temperature increase
var/bias = 0
if (temperature < lower_limit)
bias = min(round((average - temperature)/TEMPERATURE_DIVISOR, 1), TEMPERATURE_CHANGE_MAX)
else if (temperature > upper_limit)
bias = max(round((temperature - average)/TEMPERATURE_DIVISOR, 1), -TEMPERATURE_CHANGE_MAX)
temperature += rand(-7 + bias, 7 + bias)
if (temperature > max_temperature)
overheat()
del(src)
return
else if (overheating > 0)
overheating--
/obj/machinery/power/port_gen/pacman/handleInactive()
var/cooling_temperature = 20
var/datum/gas_mixture/environment = loc.return_air()
if (environment)
var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1)
var/ambient = environment.temperature - T20C
cooling_temperature += ambient*ratio
if (heat > 0)
heat = max(heat - 2, 0)
if (temperature > cooling_temperature)
var/temp_loss = (temperature - cooling_temperature)/TEMPERATURE_DIVISOR
temp_loss = between(2, round(temp_loss, 1), TEMPERATURE_CHANGE_MAX)
temperature = max(temperature - temp_loss, cooling_temperature)
src.updateDialog()
if(overheating)
overheating--
/obj/machinery/power/port_gen/pacman/proc/overheat()
explosion(src.loc, 2, 5, 2, -1)
overheating++
if (overheating > 60)
explode()
/obj/machinery/power/port_gen/pacman/explode()
//Vapourize all the phoron
//When ground up in a grinder, 1 sheet produces 20 u of phoron -- Chemistry-Machinery.dm
//1 mol = 10 u? I dunno. 1 mol of carbon is definitely bigger than a pill
var/phoron = (sheets+sheet_left)*20
var/datum/gas_mixture/environment = loc.return_air()
if (environment)
environment.adjust_gas_temp("phoron", phoron/10, temperature + T0C)
sheets = 0
sheet_left = 0
..()
/obj/machinery/power/port_gen/pacman/attackby(var/obj/item/O as obj, var/mob/user as mob)
if(istype(O, sheet_path))
@@ -213,16 +263,16 @@ display round(lastgen) and phorontank amount
if(amount < 1)
user << "\blue The [src.name] is full!"
return
user << "\blue You add [amount] sheets to the [src.name]."
user << "\blue You add [amount] sheet\s to the [src.name]."
sheets += amount
addstack.use(amount)
updateUsrDialog()
return
else if (istype(O, /obj/item/weapon/card/emag))
emagged = 1
emp_act(1)
if (active && prob(25))
explode() //if they're foolish enough to emag while it's running
else if(!active)
if(istype(O, /obj/item/weapon/wrench))
if(!anchored)
@@ -245,18 +295,9 @@ display round(lastgen) and phorontank amount
else if(istype(O, /obj/item/weapon/crowbar) && open)
var/obj/machinery/constructable_frame/machine_frame/new_frame = new /obj/machinery/constructable_frame/machine_frame(src.loc)
for(var/obj/item/I in component_parts)
if(I.reliability < 100)
I.crit_fail = 1
I.loc = src.loc
while ( sheets > 0 )
var/obj/item/stack/sheet/G = new sheet_path(src.loc)
if ( sheets > 50 )
G.amount = 50
else
G.amount = sheets
sheets -= G.amount
DropFuel()
new_frame.state = 2
new_frame.icon_state = "box_1"
@@ -266,12 +307,46 @@ display round(lastgen) and phorontank amount
..()
if (!anchored)
return
interact(user)
ui_interact(user)
/obj/machinery/power/port_gen/pacman/attack_ai(mob/user as mob)
interact(user)
ui_interact(user)
/obj/machinery/power/port_gen/pacman/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(IsBroken())
return
var/data[0]
data["active"] = active
if(istype(user, /mob/living/silicon/ai))
data["is_ai"] = 1
else if(istype(user, /mob/living/silicon/robot) && !Adjacent(user))
data["is_ai"] = 1
else
data["is_ai"] = 0
data["output_set"] = power_output
data["output_max"] = max_power_output
data["output_safe"] = max_safe_output
data["output_watts"] = power_output * power_gen
data["temperature_current"] = src.temperature
data["temperature_max"] = src.max_temperature
data["temperature_overheat"] = overheating
// 1 sheet = 1000cm3?
data["fuel_stored"] = round((sheets * 1000) + (sheet_left * 1000))
data["fuel_capacity"] = round(max_sheets * 1000, 0.1)
data["fuel_usage"] = active ? round((power_output / time_per_sheet) * 1000) : 0
data["fuel_type"] = sheet_name
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "pacman.tmpl", src.name, 500, 560)
ui.open()
ui.set_auto_update(1)
/*
/obj/machinery/power/port_gen/pacman/interact(mob/user)
if (get_dist(src, user) > 1 )
if (!istype(user, /mob/living/silicon/ai))
@@ -289,12 +364,15 @@ display round(lastgen) and phorontank amount
dat += text("[capitalize(sheet_name)]: [sheets] - <A href='?src=\ref[src];action=eject'>Eject</A><br>")
var/stack_percent = round(sheet_left * 100, 1)
dat += text("Current stack: [stack_percent]% <br>")
dat += text("Power output: <A href='?src=\ref[src];action=lower_power'>-</A> [power_gen * power_output] <A href='?src=\ref[src];action=higher_power'>+</A><br>")
dat += text("Power output: <A href='?src=\ref[src];action=lower_power'>-</A> [power_gen * power_output] Watts<A href='?src=\ref[src];action=higher_power'>+</A><br>")
dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]<br>")
dat += text("Heat: [heat]<br>")
var/tempstr = "Temperature: [temperature]&deg;C<br>"
dat += (overheating)? "<span class='danger'>[tempstr]</span>" : tempstr
dat += "<br><A href='?src=\ref[src];action=close'>Close</A>"
user << browse("[dat]", "window=port_gen")
onclose(user, "port_gen")
*/
/obj/machinery/power/port_gen/pacman/Topic(href, href_list)
if(..())
@@ -303,53 +381,68 @@ display round(lastgen) and phorontank amount
src.add_fingerprint(usr)
if(href_list["action"])
if(href_list["action"] == "enable")
if(!active && HasFuel() && !crit_fail)
if(!active && HasFuel() && !IsBroken())
active = 1
icon_state = "portgen1"
src.updateUsrDialog()
if(href_list["action"] == "disable")
if (active)
active = 0
icon_state = "portgen0"
src.updateUsrDialog()
if(href_list["action"] == "eject")
if(!active)
DropFuel()
src.updateUsrDialog()
if(href_list["action"] == "lower_power")
if (power_output > 1)
power_output--
src.updateUsrDialog()
if (href_list["action"] == "higher_power")
if (power_output < 4 || emagged)
if (power_output < max_power_output || (emagged && power_output < round(max_power_output*2.5)))
power_output++
src.updateUsrDialog()
if (href_list["action"] == "close")
usr << browse(null, "window=port_gen")
usr.unset_machine()
/obj/machinery/power/port_gen/pacman/super
name = "S.U.P.E.R.P.A.C.M.A.N.-type Portable Generator"
desc = "A power generator that utilizes uranium sheets as fuel. Can run for much longer than the standard PACMAN type generators. Rated for 80 kW max safe output."
icon_state = "portgen1"
sheet_path = /obj/item/stack/sheet/mineral/uranium
sheet_name = "Uranium Sheets"
time_per_sheet = 576 //same power output, but a 50 sheet stack will last 2 hours at max safe power
board_path = "/obj/item/weapon/circuitboard/pacman/super"
//produces 80 kW like the PACMAN but 50 sheets will last for 2 hours
power_gen = 20000
time_per_sheet = 576
overheat()
explosion(src.loc, 3, 3, 3, -1)
/obj/machinery/power/port_gen/pacman/super/UseFuel()
//produces a tiny amount of radiation when in use
if (prob(2*power_output))
for (var/mob/living/L in range(src, 5))
L.apply_effect(1, IRRADIATE) //should amount to ~5 rads per minute at max safe power
..()
/obj/machinery/power/port_gen/pacman/super/explode()
//a nice burst of radiation
var/rads = 50 + (sheets + sheet_left)*1.5
for (var/mob/living/L in range(src, 10))
//should really fall with the square of the distance, but that makes the rads value drop too fast
//I dunno, maybe physics works different when you live in 2D -- SM radiation also works like this, apparently
L.apply_effect(max(20, round(rads/get_dist(L,src))), IRRADIATE)
explosion(src.loc, 3, 3, 5, 3)
del(src)
/obj/machinery/power/port_gen/pacman/mrs
name = "M.R.S.P.A.C.M.A.N.-type Portable Generator"
desc = "An advanced power generator that runs on tritium. Rated for 200 kW maximum safe output!"
icon_state = "portgen2"
sheet_path = /obj/item/stack/sheet/mineral/tritium
sheet_name = "Tritium Fuel Sheets"
//I don't think tritium has any other use, so we might as well make this rewarding for players
//max safe power output (power level = 8) is 200 kW and lasts for 1 hour - 3 or 4 of these could power the station
power_gen = 25000 //watts
max_power_output = 10
max_safe_output = 8
time_per_sheet = 576
max_temperature = 800
temperature_gain = 90
board_path = "/obj/item/weapon/circuitboard/pacman/mrs"
//produces 200 kW and lasts for 1 hour with 50 sheets
power_gen = 50000
time_per_sheet = 288
overheat()
explosion(src.loc, 4, 4, 4, -1)
/obj/machinery/power/port_gen/pacman/mrs/explode()
//no special effects, but the explosion is pretty big (same as a supermatter shard).
explosion(src.loc, 3, 6, 12, 16, 1)
del(src)
+4 -2
View File
@@ -63,8 +63,10 @@
if(!src.loc)
return 0
if(!use_power)
return 1
//Don't do this. It allows machines that set use_power to 0 when off (many machines) to
//be turned on again and used after a power failure because they never gain the NOPOWER flag.
//if(!use_power)
// return 1
var/area/A = src.loc.loc // make sure it's in an area
if(!A || !isarea(A) || !A.master)
@@ -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
@@ -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)
+1 -1
View File
@@ -315,7 +315,7 @@
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "smes.tmpl", "SMES Power Storage Unit", 540, 380)
ui = new(user, src, ui_key, "smes.tmpl", "SMES Unit", 540, 380)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
+2 -2
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()
+127 -41
View File
@@ -6,73 +6,159 @@
flags = CONDUCT
slot_flags = SLOT_BELT
throwforce = 1
w_class = 1.0
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
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 - 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(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
+135 -118
View File
@@ -1,38 +1,159 @@
/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"
ammo_type = /obj/item/ammo_casing/c45r
/obj/item/ammo_magazine/c45m/flash
name = "magazine (.45 flash)"
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/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/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)"
@@ -41,114 +162,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 = 8
multiple_sprites = 1
/obj/item/ammo_magazine/mc9mm/empty
max_ammo = 0
/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()
*/
+75 -43
View File
@@ -1,113 +1,145 @@
/obj/item/ammo_casing/a357
desc = "A .357 bullet casing."
caliber = "357"
projectile_type = "/obj/item/projectile/bullet"
projectile_type = /obj/item/projectile/bullet/pistol/strong
/obj/item/ammo_casing/a50
desc = "A .50AE bullet casing."
caliber = ".50"
projectile_type = "/obj/item/projectile/bullet"
/obj/item/ammo_casing/a418
desc = "A .418 bullet casing."
caliber = "357"
projectile_type = "/obj/item/projectile/bullet/suffocationbullet"
projectile_type = /obj/item/projectile/bullet/pistol/strong
/obj/item/ammo_casing/a75
desc = "A .75 bullet casing."
desc = "A 20mm bullet casing."
caliber = "75"
projectile_type = "/obj/item/projectile/bullet/gyro"
/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/gyro
/obj/item/ammo_casing/c38
desc = "A .38 bullet casing."
caliber = "38"
projectile_type = "/obj/item/projectile/bullet/weakbullet"
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
desc = "A 9mm bullet casing."
caliber = "9mm"
projectile_type = "/obj/item/projectile/bullet/midbullet2"
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/c45
desc = "A .45 bullet casing."
caliber = ".45"
projectile_type = "/obj/item/projectile/bullet/midbullet"
projectile_type = /obj/item/projectile/bullet/pistol/medium
/obj/item/ammo_casing/c45r
desc = "A .45 rubber bullet casing."
caliber = ".45"
projectile_type = "/obj/item/projectile/bullet/weakbullet/rubber"
projectile_type = /obj/item/projectile/bullet/pistol/rubber
/obj/item/ammo_casing/c45f
desc = "A .45 flash shell casing."
caliber = ".45"
projectile_type = /obj/item/projectile/energy/flash
/obj/item/ammo_casing/a12mm
desc = "A 12mm bullet casing."
caliber = "12mm"
projectile_type = "/obj/item/projectile/bullet/midbullet2"
projectile_type = /obj/item/projectile/bullet/pistol/medium
/obj/item/ammo_casing/shotgun
name = "shotgun slug"
desc = "A 12 gauge slug."
icon_state = "slshell"
caliber = "shotgun"
projectile_type = /obj/item/projectile/bullet/shotgun
matter = list("metal" = 12500)
/obj/item/ammo_casing/shotgun/pellet
name = "shotgun shell"
desc = "A 12 gauge shell."
icon_state = "gshell"
caliber = "shotgun"
projectile_type = "/obj/item/projectile/bullet"
projectile_type = /obj/item/projectile/bullet/pellet/shotgun
matter = list("metal" = 12500)
/obj/item/ammo_casing/shotgun/blank
name = "shotgun shell"
desc = "A blank shell."
icon_state = "blshell"
projectile_type = "/obj/item/projectile/bullet/chameleon"
projectile_type = /obj/item/projectile/bullet/blank
matter = list("metal" = 250)
/obj/item/ammo_casing/shotgun/beanbag
name = "beanbag shell"
desc = "A weak beanbag shell."
desc = "A beanbag shell."
icon_state = "bshell"
projectile_type = "/obj/item/projectile/bullet/weakbullet/beanbag"
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 stunning shell."
desc = "A 12 gauge taser cartridge."
icon_state = "stunshell"
projectile_type = "/obj/item/projectile/bullet/stunshot"
matter = list("metal" = 2500)
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()
/obj/item/ammo_casing/shotgun/dart
name = "shotgun darts"
desc = "A dart for use in shotguns."
icon_state = "dart"
projectile_type = "/obj/item/projectile/energy/dart"
matter = list("metal" = 12500)
//Does not stun, only blinds, but has area of effect.
/obj/item/ammo_casing/shotgun/flash
name = "flash shell"
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/a762
desc = "A 7.62 bullet casing."
desc = "A 7.62mm bullet casing."
caliber = "a762"
projectile_type = "/obj/item/projectile/bullet/a762"
projectile_type = /obj/item/projectile/bullet/rifle/a762
/obj/item/ammo_casing/a145
name = "shell casing"
desc = "A 14.5mm AP shell."
icon_state = "lcasing"
spent_icon = "lcasing-spent"
caliber = "14.5mm"
projectile_type = /obj/item/projectile/bullet/rifle/a145
/obj/item/ammo_casing/rocket
name = "rocket shell"
desc = "A high explosive designed to be fired from a launcher."
icon_state = "rocketshell"
projectile_type = "/obj/item/missile"
projectile_type = /obj/item/missile
caliber = "rocket"
/obj/item/ammo_casing/chameleon
name = "chameleon bullets"
desc = "A set of bullets for the Chameleon Gun."
projectile_type = "/obj/item/projectile/bullet/chameleon"
projectile_type = /obj/item/projectile/bullet/chameleon
caliber = ".45"
/*
/obj/item/ammo_casing/a418
desc = "A .418 bullet casing."
caliber = "357"
projectile_type = /obj/item/projectile/bullet/suffocationbullet
/obj/item/ammo_casing/a666
desc = "A .666 bullet casing."
caliber = "357"
projectile_type = /obj/item/projectile/bullet/cyanideround
*/
+187 -161
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,36 +102,19 @@
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(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)
var/turf/curloc = get_turf(user)
var/turf/targloc = get_turf(target)
if (!istype(targloc) || !istype(curloc))
return
if(!special_check(user))
return
@@ -110,128 +123,141 @@
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
in_chamber.firer = user
in_chamber.def_zone = user.zone_sel.selecting
if(targloc == curloc)
user.bullet_act(in_chamber)
del(in_chamber)
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()
return
if(user.hand)
user.update_inv_l_hand()
else
user.update_inv_r_hand()
if(recoil)
spawn()
shake_camera(user, recoil + 1, recoil)
//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.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()
in_chamber.original = target
in_chamber.loc = get_turf(user)
in_chamber.starting = get_turf(user)
in_chamber.shot_from = src
user.next_move = world.time + 4
in_chamber.silenced = silenced
in_chamber.current = curloc
in_chamber.yo = targloc.y - curloc.y
in_chamber.xo = targloc.x - curloc.x
//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))
var/mob/living/carbon/mob = user
if(mob.shock_stage > 120)
in_chamber.yo += rand(-2,2)
in_chamber.xo += rand(-2,2)
y_offset = rand(-2,2)
x_offset = rand(-2,2)
else if(mob.shock_stage > 70)
in_chamber.yo += rand(-1,1)
in_chamber.xo += rand(-1,1)
y_offset = rand(-1,1)
x_offset = rand(-1,1)
//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"])
in_chamber.p_x = text2num(mouse_control["icon-x"])
if(mouse_control["icon-y"])
in_chamber.p_y = text2num(mouse_control["icon-y"])
P.set_clickpoint(params)
spawn()
if(in_chamber)
in_chamber.process()
sleep(1)
in_chamber = null
return !P.launch(target, user, src, target_zone, x_offset, y_offset)
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
//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
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
else
accuracy = (accuracy)
recoil = initial(recoil)
+11 -25
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
@@ -73,8 +63,8 @@
recoil = 1
force = 10
projectile_type = "/obj/item/projectile/energy/sonic"
cell_type = "/obj/item/weapon/cell/super"
projectile_type = /obj/item/projectile/energy/sonic
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
+66 -27
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/projectile_type = "/obj/item/projectile/beam/practice"
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(!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)
+66 -124
View File
@@ -4,89 +4,53 @@
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
/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 +58,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
+91 -101
View File
@@ -1,129 +1,119 @@
/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'
charge_cost = 100 //How much energy is needed to fire.
projectile_type = "/obj/item/projectile/beam/stun"
projectile_type = /obj/item/projectile/beam/stun
origin_tech = "combat=3;magnets=2"
modifystate = "energystun"
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()
+34 -47
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"
projectile_type = /obj/item/projectile/beam/pulse
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 [src.name] 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 [src.name] 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 [src.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 [src.name] 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
+147 -176
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,199 +116,91 @@ 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"
/* Adminbus guns */
/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"
// 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
icon = 'icons/obj/watercloset.dmi'
icon_state = "rubberducky"
item_state = "rubberducky"
charge_cost = 0
silenced = 1
/obj/item/weapon/gun/energy/sniperrifle/verb/scope()
/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
user << "You inform the Icarus to switch to the main guns."
else
projectile_type = /obj/item/projectile/icarus/pointdefense
user << "You inform the Icarus to switch to the point-defense lasers."
. = ..()
/obj/item/weapon/gun/energy/icarus/update_icon()
return
/obj/item/weapon/gun/energy/icarus/verb/SetIcarusAngle()
set src in usr
set name = "Set Firing Angle"
set desc = "Sets the angle from which the icarus will fire."
set category = "Object"
set name = "Use Scope"
set popup_menu = 1
zoom()
Icarus_SetPosition(usr)
/obj/item/weapon/gun/energy/variable
name = "abstract weapon"
desc = "It seems to shift and flow as you watch."
charge_cost = 0
silenced = 1
/obj/item/weapon/gun/energy/variable/update_icon()
return
/obj/item/weapon/gun/energy/variable/attack_self(mob/living/user as mob)
var/type = input(user,"What projectile type?","Projectile", null) as null|anything in typesof(/obj/item/projectile)
if(!type)
return ..()
projectile_type = type
. = ..()
+19 -64
View File
@@ -5,39 +5,16 @@
item_state = null //so the human update icon uses the icon_state instead.
fire_sound = 'sound/weapons/Taser.ogg'
charge_cost = 100
projectile_type = "/obj/item/projectile/beam/stun"
cell_type = "/obj/item/weapon/cell/crap"
projectile_type = /obj/item/projectile/beam/stun
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
@@ -47,9 +24,8 @@
fire_sound = 'sound/weapons/Taser.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/beam/stun
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
projectile_type = /obj/item/projectile/energy/bolt
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"
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"
projectile_type = /obj/item/projectile/energy/bolt/large
@@ -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
+32
View File
@@ -0,0 +1,32 @@
/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/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
@@ -51,43 +51,39 @@
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 +94,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 +102,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 +171,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)
@@ -0,0 +1,82 @@
/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 = 'icons/obj/gun.dmi'
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
@@ -4,6 +4,7 @@
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 +62,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 +79,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 +86,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 +109,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.
@@ -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].")
..()
@@ -0,0 +1,135 @@
/obj/item/weapon/syringe_cartridge
name = "syringe gun cartridge"
desc = "An impact-triggered compressed gas cartridge that can 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
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)
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 = 'icons/obj/gun.dmi'
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

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