"
if(user.mind in (ticker.mode.A_bosses | ticker.mode.B_bosses))
- dat += "Give this device to another member of your organization to use. "
- else
+ dat += "Give this device to another member of your organization to use to promote them."
+ dat += "If this is meant as a spare device for yourself: "
dat += "Register Device "
+ else if (gang_bosses < 3)
+ dat += "You have been selected for a promotion! "
+ dat += "Register Device "
+ else
+ dat += "No promotions available: All positions filled."
else
var/datum/game_mode/gang/gangmode
if(istype(ticker.mode, /datum/game_mode/gang))
gangmode = ticker.mode
- var/gang_size = ((gang == "A")? (ticker.mode.A_gang.len + ticker.mode.A_bosses.len) : (ticker.mode.B_gang.len + ticker.mode.B_bosses.len))
+ var/gang_size = gang_bosses + ((gang == "A")? ticker.mode.A_gang.len : ticker.mode.B_gang.len)
var/gang_territory = ((gang == "A")? ticker.mode.A_territory.len : ticker.mode.B_territory.len)
var/points = ((gang == "A") ? ticker.mode.gang_points.A : ticker.mode.gang_points.B)
var/timer
if(gangmode)
timer = ((gang == "A") ? gangmode.A_timer : gangmode.B_timer)
if(isnum(timer))
- dat += "
Takeover In Progress: [timer] seconds remain
"
+ dat += "
Takeover In Progress: [timer] seconds remain
"
dat += "Registration: [(gang == "A")? gang_name("A") : gang_name("B")] Gang [boss ? "Administrator" : "Lieutenant"] "
dat += "Organization Size: [gang_size] | Station Control: [round((gang_territory/start_state.num_territories)*100, 1)]% "
+ dat += "Influence: [points] "
+ dat += "Time until Influence grows: [(points >= 999) ? ("--:--") : (time2text(ticker.mode.gang_points.next_point_time - world.time, "mm:ss"))] "
+ dat += ""
+ dat += "Gangtool Functions: "
+
+ dat += "Send Message to Gang "
if(outfits > 0)
- dat += "Create Gang Outfit "
+ dat += "Create Armored Gang Outfit "
else
dat += "Create Gang Outfit (Restocking) "
- dat += "Send Gang-wide Message "
if(gangmode)
dat += "Recall Emergency Shuttle "
dat += " "
-
- dat += "Influence: [points] "
- dat += "Time until Influence grows: [(points >= 999) ? ("--:--") : (time2text(ticker.mode.gang_points.next_point_time - world.time, "mm:ss"))] "
- dat += ""
dat += "Purchase Weapons: "
- dat += "(10 Influence) "
- if(points >= 10)
- dat += "Switchblade "
- else
- dat += "Switchblade "
+ /////////////////
+ // NORMAL GANG //
+ /////////////////
- dat += "(20 Influence) "
- if(points >= 20)
- dat += "10mm Pistol "
- else
- dat += "10mm Pistol "
+ if(!gangmode || (gang == "A" && gangmode.A_fighting_style == "normal") || (gang == "B" && gangmode.B_fighting_style == "normal")) //If the gamemode is not gang, always use standard loadout.
+ dat += "(10 Influence) "
+ if(points >= 10)
+ dat += "Switchblade "
+ else
+ dat += "Switchblade "
- dat += "(10 Influence) "
- if(points >= 10)
- dat += "10mm Ammo "
- else
- dat += "10mm Ammo "
+ dat += "(25 Influence) "
+ if(points >= 25)
+ dat += "10mm Pistol "
+ else
+ dat += "10mm Pistol "
- dat += "(40 Influence) "
- if(points >= 40)
- dat += "Mini Uzi "
- else
- dat += "Mini Uzi "
+ dat += "(10 Influence) "
+ if(points >= 10)
+ dat += "10mm Ammo "
+ else
+ dat += "10mm Ammo "
- dat += "(25 Influence) "
- if(points >= 25)
- dat += "Uzi Ammo "
- else
- dat += "Uzi Magazine "
+ dat += "(50 Influence) "
+ if(points >= 50)
+ dat += "Mini Uzi "
+ else
+ dat += "Mini Uzi "
+
+ dat += "(20 Influence) "
+ if(points >= 20)
+ dat += "Uzi Ammo "
+ else
+ dat += "Uzi Magazine "
+
+ dat += " "
+
+ //////////////////
+ // MARTIAL ARTS //
+ //////////////////
+
+ else if((gang == "A" && gangmode.A_fighting_style == "martial") || (gang == "B" && gangmode.B_fighting_style == "martial"))
+ dat += "(10 Influence) "
+ if(points >= 10)
+ dat += "Bo Staff "
+ else
+ dat += "Bo Staff "
+
+ dat += "(20 Influence) "
+ if(points >= 20)
+ dat += "Wrestling Belt "
+ else
+ dat += "Wrestling Belt "
+
+ dat += "(30 Influence) "
+ if(points >= 30)
+ dat += "Sleeping Carp Scroll (one-use) "
+ else
+ dat += "Sleeping Carp Scroll (one-use) "
+ dat += " "
+
+ ////////////////////////
+ // STANDARD EQUIPMENT //
+ ////////////////////////
- dat += " "
dat += "Purchase Equipment: "
dat += "(5 Influence) "
if(points >= 5)
- dat += "Territory Spraycan "
+ dat += "Territory Spraycan "
else
- dat += "Territory Spraycan "
+ dat += "Territory Spraycan "
dat += "(10 Influence) "
if(points >= 10)
- dat += "Bulletproof Vest "
+ dat += "C4 Explosive "
else
- dat += "Bulletproof Vest "
+ dat += "C4 Explosive "
- dat += "(30 Influence) "
- if(points >= 30)
+ if(free_pen)
+ dat += "(ONE FREE) "
+ else
+ dat += "(50 Influence) "
+ if(free_pen || (points >= 50))
dat += "Recruitment Pen "
else
dat += "Recruitment Pen "
- if(boss)
- if(promotions >= 3)
- dat += "(Out of stock) Promote a Gangster "
- else
- dat += "([(promotions*10)+10] Influence, [3-promotions] left) "
- if(points >= (promotions*10)+10)
- dat += "Promote a Gangster "
- else
- dat += "Promote a Gangster "
+ var/tool_cost = (boss ? 10 : 30)
+ var/gangtooldesc = "Promote a Gangster ([3-gang_bosses] left)"
+ if(gang_bosses >= 3)
+ gangtooldesc = "Additional Gangtools"
+ dat += "([tool_cost] Influence) "
+ if(points >= tool_cost)
+ dat += "[gangtooldesc] "
+ else
+ dat += "[gangtooldesc] "
+
if(gangmode)
- dat += "(30 Influence) "
- if(points >= 30)
- dat += "Station Dominator "
+ if(gang == "A" ? !gangmode.A_dominations : !gangmode.B_dominations)
+ dat += "(Out of stock) Station Dominator"
else
- dat += "Station Dominator "
- dat += "(Estimated Takeover Time: [round(max(300,900 - ((round((gang_territory/start_state.num_territories)*200, 10) - 60) * 15))/60,1)] minutes) "
+ dat += "(30 Influence) "
+ if(points >= 30)
+ dat += "Station Dominator "
+ else
+ dat += "Station Dominator "
+ dat += "(Estimated Takeover Time: [round(max(300,900 - ((round((gang_territory/start_state.num_territories)*200, 10) - 60) * 15))/60,1)] minutes) "
dat += " "
dat += "Refresh "
- var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v0.4", 340, 600)
+ var/datum/browser/popup = new(user, "gangtool", "Welcome to GangTool v2.1", 340, 600)
popup.set_content(dat)
popup.open()
@@ -147,6 +196,10 @@
add_fingerprint(usr)
+ if(recalling)
+ usr << "Device is busy. Shuttle recall in progress."
+ return
+
if(href_list["register"])
register_device(usr)
@@ -166,43 +219,62 @@
item_type = /obj/item/weapon/switchblade
points = 10
if("pistol")
- if(points >= 20)
+ if(points >= 25)
item_type = /obj/item/weapon/gun/projectile/automatic/pistol
- points = 20
+ points = 25
if("10mmammo")
if(points >= 10)
item_type = /obj/item/ammo_box/magazine/m10mm
points = 10
if("uzi")
- if(points >= 40)
+ if(points >= 50)
item_type = /obj/item/weapon/gun/projectile/automatic/mini_uzi
- points = 40
- if("9mmammo")
- if(points >= 25)
- item_type = /obj/item/ammo_box/magazine/uzim9mm
- points = 25
- if("vest")
+ points = 50
+ if("scroll")
+ if(points >= 30)
+ item_type = /obj/item/weapon/sleeping_carp_scroll
+ points = 30
+ if("wrestlingbelt")
+ if(points >= 20)
+ item_type = /obj/item/weapon/storage/belt/champion/wrestling
+ points = 20
+ if("bostaff")
if(points >= 10)
- item_type = /obj/item/clothing/suit/armor/bulletproof
+ item_type = /obj/item/weapon/twohanded/bostaff
+ points = 10
+ if("9mmammo")
+ if(points >= 20)
+ item_type = /obj/item/ammo_box/magazine/uzim9mm
+ points = 20
+ if("C4")
+ if(points >= 10)
+ item_type = /obj/item/weapon/c4
points = 10
if("pen")
- if(points >= 30)
+ if(free_pen)
item_type = /obj/item/weapon/pen/gang
- points = 30
+ free_pen = 0
+ points = 0
+ else if(points >= 50)
+ item_type = /obj/item/weapon/pen/gang
+ points = 50
if("gangtool")
- if((promotions < 3) && (points >= (promotions*10)+10))
+ var/tool_cost = (boss ? 10 : 30)
+ if(points >= tool_cost)
item_type = /obj/item/device/gangtool/lt
- points = (promotions*10)+10
- promotions++
+ points = tool_cost
if("dominator")
if(istype(ticker.mode, /datum/game_mode/gang))
var/datum/game_mode/gang/mode = ticker.mode
if(isnum((gang == "A") ? mode.A_timer : mode.B_timer))
return
- var/usrarea = get_area(usr.loc)
+ if(gang == "A" ? !mode.A_dominations : !mode.B_dominations)
+ return
+
+ var/area/usrarea = get_area(usr.loc)
var/usrturf = get_turf(usr.loc)
- if(istype(usrarea,/area/space) || istype(usrturf,/turf/space) || usr.z != 1)
+ if(initial(usrarea.name) == "Space" || istype(usrturf,/turf/space) || usr.z != 1)
usr << "You can only use this on the station!"
return
@@ -224,17 +296,21 @@
var/obj/purchased = new item_type(get_turf(usr))
var/mob/living/carbon/human/H = usr
H.put_in_any_hand_if_possible(purchased)
- ticker.mode.message_gangtools(((gang=="A")? ticker.mode.A_tools : ticker.mode.B_tools), "A [href_list["purchase"]] was purchased by [usr] for [points] Influence.")
+ if(points)
+ ticker.mode.message_gangtools(((gang=="A")? ticker.mode.A_tools : ticker.mode.B_tools), "A [href_list["purchase"]] was purchased by [usr] for [points] Influence.")
log_game("A [href_list["purchase"]] was purchased by [key_name(usr)] for [points] Influence.")
+ else
+ usr << "Not enough influence."
+
else if(href_list["choice"])
switch(href_list["choice"])
+ if("recall")
+ recall(usr)
if("outfit")
if(outfits > 0)
ticker.mode.gang_outfit(usr,src,gang)
outfits -= 1
- if("recall")
- recall(usr)
if("ping")
ping_gang(usr)
attack_self(usr)
@@ -244,7 +320,7 @@
if(!user)
return
var/message = stripped_input(user,"Discreetly send a gang-wide message.","Send Message") as null|text
- if(!message || (message == "") || !can_use(user))
+ if(!message || !can_use(user))
return
if(user.z > 2)
user << "\icon[src]Error: Station out of range."
@@ -257,7 +333,7 @@
if(members.len)
var/ping = "[gang_name(gang)] [boss ? "Gang Boss" : "Gang Lieutenant"]: [message]"
for(var/datum/mind/ganger in members)
- if(ganger.current.z <= 2)
+ if((ganger.current.z <= 2) && (ganger.current.stat == CONSCIOUS))
ganger.current << ping
for(var/mob/M in dead_mob_list)
M << ping
@@ -265,6 +341,12 @@
/obj/item/device/gangtool/proc/register_device(var/mob/user)
+ if(!(user.mind in (ticker.mode.A_bosses|ticker.mode.B_bosses)))
+ var/gang_bosses = ((gang == "A")? ticker.mode.A_bosses.len : ticker.mode.B_bosses.len)
+ if(gang_bosses >= 3)
+ user << "\icon[src] Error: All positions filled."
+ return
+
if(jobban_isbanned(user, "gangster") || jobban_isbanned(user, "Syndicate"))
user << "\icon[src] ACCESS DENIED: Blacklisted user."
return 0
@@ -298,50 +380,61 @@
ticker.mode.forge_gang_objectives(user.mind)
ticker.mode.greet_gang(user.mind,0)
user << "The Gangtool you registered will allow you to purchase items, send messages to your gangsters and to recall the emergency shuttle from anywhere on the station."
- user << "You may also now use recruitment pens to grow your gang membership. Use them on unsuspecting crew members to recruit them."
+ user << "Unlike regular gangsters, you may use recruitment pens to add recruits to your gang. Use them on unsuspecting crew members to recruit them. Don't forget to get your one free pen from the gangtool."
if(!gang)
usr << "ACCESS DENIED: Unauthorized user."
/obj/item/device/gangtool/proc/recall(mob/user)
- if(recalling || !can_use(user))
- return
+ if(!can_use(user))
+ return 0
if(!istype(ticker.mode, /datum/game_mode/gang))
- return
+ return 0
+ var/datum/game_mode/gang/mode = ticker.mode
recalling = 1
loc << "\icon[src]Generating shuttle recall order with codes retrieved from last call signal..."
- sleep(rand(10,30))
+ sleep(rand(100,300))
if(SSshuttle.emergency.mode != SHUTTLE_CALL) //Shuttle can only be recalled when it's moving to the station
user << "\icon[src]Emergency shuttle cannot be recalled at this time."
recalling = 0
- return
+ return 0
loc << "\icon[src]Shuttle recall order generated. Accessing station long-range communication arrays..."
- sleep(rand(10,30))
+ sleep(rand(100,300))
+
+ if(gang == "A" ? !mode.A_dominations : !mode.B_dominations)
+ user << "\icon[src]Error: Unable to access communication arrays. Firewall has logged our signature and is blocking all further attempts."
+ recalling = 0
+ return 0
var/turf/userturf = get_turf(user)
if(userturf.z != 1) //Shuttle can only be recalled while on station
user << "\icon[src]Error: Device out of range of station communication arrays."
recalling = 0
- return
+ return 0
var/datum/station_state/end_state = new /datum/station_state()
end_state.count()
if((100 * start_state.score(end_state)) < 70) //Shuttle cannot be recalled if the station is too damaged
user << "\icon[src]Error: Station communication systems compromised. Unable to establish connection."
recalling = 0
- return
+ return 0
loc << "\icon[src]Comm arrays accessed. Broadcasting recall signal..."
- sleep(rand(10,30))
+ sleep(rand(100,300))
recalling = 0
log_game("[key_name(user)] has tried to recall the shuttle with a gangtool.")
message_admins("[key_name_admin(user)] has tried to recall the shuttle with a gangtool.", 1)
- if(!SSshuttle.cancelEvac(user))
- loc << "\icon[src]No response recieved. Emergency shuttle cannot be recalled at this time."
+ userturf = get_turf(user)
+ if(userturf.z == 1) //Check one more time that they are on station.
+ if(SSshuttle.cancelEvac(user))
+ return 1
+
+ loc << "\icon[src]No response recieved. Emergency shuttle cannot be recalled at this time."
+ return 0
/obj/item/device/gangtool/proc/can_use(mob/living/carbon/human/user)
if(!istype(user))
@@ -368,3 +461,4 @@
/obj/item/device/gangtool/lt
boss = 0
outfits = 1
+ free_pen = 1
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 7d8a51b32eb..251a562fe3c 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -180,7 +180,11 @@
U.hidden_uplink.uses = 20
synd_mob.equip_to_slot_or_del(U, slot_in_backpack)
- var/obj/item/weapon/implant/weapons_auth/E = new/obj/item/weapon/implant/weapons_auth(synd_mob)
+ var/obj/item/weapon/implant/weapons_auth/W = new/obj/item/weapon/implant/weapons_auth(synd_mob)
+ W.imp_in = synd_mob
+ W.implanted = 1
+ W.implanted(synd_mob)
+ var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(synd_mob)
E.imp_in = synd_mob
E.implanted = 1
E.implanted(synd_mob)
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 3255f82ba34..7d06cc079ba 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -1,11 +1,25 @@
+#define NUKESTATE_INTACT 6
+#define NUKESTATE_OPEN 5
+#define NUKESTATE_OPEN_TRAP 4
+#define NUKESTATE_WIRES_TIED 3
+#define NUKESTATE_CUT_LINES 2
+#define NUKESTATE_CORE_EXPOSED 1
+#define NUKESTATE_CORE_REMOVED 0
+
+#define NUKE_OFF_LOCKED 0
+#define NUKE_OFF_UNLOCKED 1
+#define NUKE_ON_TIMING 2
+#define NUKE_ON_EXPLODING 3
+
var/bomb_set
/obj/machinery/nuclearbomb
name = "nuclear fission explosive"
desc = "You probably shouldn't stick around to see if this is armed."
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "nuclearbomb_off"
+ icon = 'icons/obj/machines/nuke.dmi'
+ icon_state = "nuclearbomb_base"
density = 1
+
var/timeleft = 60
var/timing = 0
var/r_code = "ADMIN"
@@ -16,65 +30,209 @@ var/bomb_set
use_power = 0
var/previous_level = ""
var/lastentered = ""
+ var/obj/item/nuke_core/core = null
+ var/deconstruction_state = NUKESTATE_INTACT
+ var/image/lights = null
+ var/image/panel = null
+ var/image/interior = null
+ var/image/glow = null
/obj/machinery/nuclearbomb/New()
..()
nuke_list += src
+ core = new /obj/item/nuke_core(src)
+ update_icon()
previous_level = get_security_level()
/obj/machinery/nuclearbomb/selfdestruct
name = "station self-destruct terminal"
desc = "For when it all gets too much to bear. Do not taunt."
icon = 'icons/obj/machines/bignuke.dmi'
+ icon_state = "nuclearbomb_base"
anchored = 1 //stops it being moved
layer = 4
+/obj/machinery/nuclearbomb/attackby(obj/item/I, mob/user, params)
+ if (istype(I, /obj/item/weapon/disk/nuclear))
+ if(!user.drop_item())
+ return
+ I.loc = src
+ auth = I
+ add_fingerprint(user)
+ return
+
+ switch(deconstruction_state)
+ if(NUKESTATE_INTACT)
+ if(istype(I, /obj/item/weapon/screwdriver/nuke))
+ playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
+ user << "You start removing the front panel's screws..."
+ if(do_after(user, 100,target=src))
+ deconstruction_state = NUKESTATE_OPEN
+ user << "You remove the screws and the front panel slides open."
+ update_icon()
+ return
+ if(NUKESTATE_OPEN,NUKESTATE_OPEN_TRAP)
+ if((deconstruction_state == NUKESTATE_OPEN) && istype(I, /obj/item/weapon/wirecutters))
+ playsound(loc, 'sound/effects/sparks4.ogg', 100, 1)
+ playsound(loc, 'sound/effects/EMPulse.ogg', 100, 1)
+ user << "You must have cut the wrong wire!"
+ for(var/mob/living/L in range(5,src))
+ L.irradiate(200)
+ deconstruction_state = NUKESTATE_OPEN_TRAP //cant cut wires no more
+ else
+ if(istype(I, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/S = I
+ user << "You start tying the uncountable wires..."
+ if(do_after(user,30,target=src))
+ if(S.use(15))
+ user << "You tie the uncountable wires with some cable, clearing the insides of [src]."
+ deconstruction_state = NUKESTATE_WIRES_TIED
+ update_icon()
+ else
+ user << "You need more cable to do that."
+ return
+ if(NUKESTATE_WIRES_TIED)
+ if(istype(I, /obj/item/weapon/pen))
+ user << "You start drawing cut lines..."
+ if(do_after(user,30,target=src))
+ user << "You draw cut lines inside [src]."
+ deconstruction_state = NUKESTATE_CUT_LINES
+ update_icon()
+ return
+ if(NUKESTATE_CUT_LINES)
+ if(istype(I, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/welder = I
+ playsound(loc, 'sound/items/Welder.ogg', 100, 1)
+ user << "You start cutting into [src]'s warhead..."
+ if(welder.remove_fuel(1,user))
+ if(do_after(user,50,target=src))
+ playsound(loc, 'sound/items/Deconstruct.ogg', 100, 1)
+ user << "You cut into [src]'s warhead. You can see the core's green glow."
+ deconstruction_state = NUKESTATE_CORE_EXPOSED
+ update_icon()
+ SSobj.processing += core
+ return
+ if(NUKESTATE_CORE_EXPOSED)
+ if(istype(I, /obj/item/nuke_core_container))
+ var/obj/item/nuke_core_container/core_box = I
+ user << "You start loading the plutonium core into [core_box]..."
+ if(do_after(user,50,target=src))
+ if(core_box.load(core,src))
+ user << "You load the plutonium core into [core_box]."
+ deconstruction_state = NUKESTATE_CORE_REMOVED
+ update_icon()
+ else
+ user << "You fail to load the plutonium core into [core_box]. [core_box] has already been used!"
+ return
+ else
+ ..()
+
+/obj/machinery/nuclearbomb/proc/get_nuke_state()
+ if(timing < 0)
+ return NUKE_ON_EXPLODING
+ if(timing > 0)
+ return NUKE_ON_TIMING
+ if(safety)
+ return NUKE_OFF_LOCKED
+ else
+ return NUKE_OFF_UNLOCKED
+
+/obj/machinery/nuclearbomb/update_icon()
+ if(deconstruction_state == NUKESTATE_INTACT)
+ switch(get_nuke_state())
+ if(NUKE_OFF_LOCKED, NUKE_OFF_UNLOCKED)
+ update_icon_interior()
+ update_icon_lights()
+ if(NUKE_ON_TIMING)
+ overlays.Cut()
+ icon_state = "nuclearbomb_timing"
+ if(NUKE_ON_EXPLODING)
+ overlays.Cut()
+ icon_state = "nuclearbomb_exploding"
+ else
+ update_icon_interior()
+ update_icon_lights()
+
+/obj/machinery/nuclearbomb/proc/update_icon_interior()
+ overlays -= interior
+ overlays -= glow
+ switch(deconstruction_state)
+ if(NUKESTATE_OPEN_TRAP,NUKESTATE_OPEN)
+ glow = null
+ interior = image(icon,"panel-removed")
+ if(NUKESTATE_CORE_REMOVED,NUKESTATE_CUT_LINES,NUKESTATE_WIRES_TIED)
+ glow = null
+ interior = image(icon,"wires-sorted")
+ if(NUKESTATE_CORE_EXPOSED)
+ glow = image(icon,"core-exposed")
+ interior = image(icon,"wires-sorted")
+ if(NUKESTATE_INTACT)
+ glow = null
+ interior = image(icon,"panel-overlay")
+ overlays += interior
+ overlays += glow
+
+/obj/machinery/nuclearbomb/proc/update_icon_lights()
+ overlays -= lights
+ overlays -= panel
+ panel = null
+ switch(get_nuke_state())
+ if(NUKE_OFF_LOCKED)
+ lights = image(icon,"lights-off")
+ if(deconstruction_state != NUKESTATE_INTACT)
+ panel = image(icon,"panel-removed-blue")
+ if(NUKE_OFF_UNLOCKED)
+ lights = image(icon,"lights-safety")
+ if(deconstruction_state != NUKESTATE_INTACT)
+ panel = image(icon,"panel-removed-blue")
+ if(NUKE_ON_TIMING)
+ lights = image(icon,"lights-timing")
+ if(deconstruction_state != NUKESTATE_INTACT)
+ panel = image(icon,"panel-removed-timing")
+ if(NUKE_ON_EXPLODING)
+ lights = image(icon,"lights-exploding")
+ if(deconstruction_state != NUKESTATE_INTACT)
+ panel = image(icon,"panel-removed-exploding")
+ overlays += lights
+ overlays += panel
+
/obj/machinery/nuclearbomb/process()
- if (src.timing)
+ if (timing > 0)
bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed.
- src.timeleft--
- if (src.timeleft <= 0)
+ timeleft--
+ if (timeleft <= 0)
explode()
else
var/volume = (timeleft <= 20 ? 30 : 5)
playsound(loc, 'sound/items/timer.ogg', volume, 0)
for(var/mob/M in viewers(1, src))
if ((M.client && M.machine == src))
- src.attack_hand(M)
+ attack_hand(M)
return
-/obj/machinery/nuclearbomb/attackby(obj/item/weapon/I as obj, mob/user as mob, params)
- if (istype(I, /obj/item/weapon/disk/nuclear))
- usr.drop_item()
- I.loc = src
- src.auth = I
- src.add_fingerprint(user)
- return
- ..()
-
/obj/machinery/nuclearbomb/attack_paw(mob/user as mob)
- return src.attack_hand(user)
+ return attack_hand(user)
/obj/machinery/nuclearbomb/attack_ai(mob/user as mob)
return
/obj/machinery/nuclearbomb/attack_hand(mob/user as mob)
user.set_machine(src)
- var/dat = text("\nAuth. Disk: []", src, (src.auth ? "++++++++++" : "----------"))
- if (src.auth)
- if (src.yes_code)
- dat += text("\nStatus: []-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: -- [] ++ \n \nSafety: [] Toggle \nAnchor: [] Toggle \n", (src.timing ? "Func/Set" : "Functional"), (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src, src, src, src.timeleft, src, src, (src.safety ? "On" : "Off"), src, (src.anchored ? "Engaged" : "Off"), src)
+ var/dat = text("\nAuth. Disk: []", src, (auth ? "++++++++++" : "----------"))
+ if (auth)
+ if (yes_code)
+ dat += text("\nStatus: []-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: -- [] ++ \n \nSafety: [] Toggle \nAnchor: [] Toggle \n", (timing ? "Func/Set" : "Functional"), (safety ? "Safe" : "Engaged"), timeleft, (timing ? "On" : "Off"), src, src, src, timeleft, src, src, (safety ? "On" : "Off"), src, (anchored ? "Engaged" : "Off"), src)
else
- dat += text("\nStatus: Auth. S2-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: - - [] + + \n \n[] Safety: Toggle \nAnchor: [] Toggle \n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off"))
+ dat += text("\nStatus: Auth. S2-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: - - [] + + \n \n[] Safety: Toggle \nAnchor: [] Toggle \n", (safety ? "Safe" : "Engaged"), timeleft, (timing ? "On" : "Off"), timeleft, (safety ? "On" : "Off"), (anchored ? "Engaged" : "Off"))
else
- if (src.timing)
- dat += text("\nStatus: Set-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: - - [] + + \n \nSafety: [] Toggle \nAnchor: [] Toggle \n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off"))
+ if (timing)
+ dat += text("\nStatus: Set-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: - - [] + + \n \nSafety: [] Toggle \nAnchor: [] Toggle \n", (safety ? "Safe" : "Engaged"), timeleft, (timing ? "On" : "Off"), timeleft, (safety ? "On" : "Off"), (anchored ? "Engaged" : "Off"))
else
- dat += text("\nStatus: Auth. S1-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: - - [] + + \n \nSafety: [] Toggle \nAnchor: [] Toggle \n", (src.safety ? "Safe" : "Engaged"), src.timeleft, (src.timing ? "On" : "Off"), src.timeleft, (src.safety ? "On" : "Off"), (src.anchored ? "Engaged" : "Off"))
+ dat += text("\nStatus: Auth. S1-[] \nTimer: [] \n \nTimer: [] Toggle \nTime: - - [] + + \n \nSafety: [] Toggle \nAnchor: [] Toggle \n", (safety ? "Safe" : "Engaged"), timeleft, (timing ? "On" : "Off"), timeleft, (safety ? "On" : "Off"), (anchored ? "Engaged" : "Off"))
var/message = "AUTH"
- if (src.auth)
- message = text("[]", src.code)
- if (src.yes_code)
+ if (auth)
+ message = text("[]", code)
+ if (yes_code)
message = "*****"
dat += text("\n>[] \n123 \n456 \n789 \nR0E \n", message, src, src, src, src, src, src, src, src, src, src, src, src)
var/datum/browser/popup = new(user, "nuclearbomb", name, 300, 400)
@@ -87,28 +245,28 @@ var/bomb_set
return
usr.set_machine(src)
if (href_list["auth"])
- if (src.auth)
- src.auth.loc = src.loc
- src.yes_code = 0
- src.auth = null
+ if (auth)
+ auth.loc = loc
+ yes_code = 0
+ auth = null
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/disk/nuclear))
usr.drop_item()
I.loc = src
- src.auth = I
- if (src.auth)
+ auth = I
+ if (auth)
if (href_list["type"])
if (href_list["type"] == "E")
- if (src.code == src.r_code)
- src.yes_code = 1
- src.code = null
+ if (code == r_code)
+ yes_code = 1
+ code = null
else
- src.code = "ERROR"
+ code = "ERROR"
else
if (href_list["type"] == "R")
- src.yes_code = 0
- src.code = null
+ yes_code = 0
+ code = null
else
lastentered = text("[]", href_list["type"])
if (text2num(lastentered) == null)
@@ -116,24 +274,24 @@ var/bomb_set
message_admins("[key_name_admin(usr)] (FLW) tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered] ! ([LOC ? "JMP" : "null"])", 0)
log_admin("EXPLOIT : [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered] !")
else
- src.code += lastentered
- if (length(src.code) > 5)
- src.code = "ERROR"
- if (src.yes_code)
+ code += lastentered
+ if (length(code) > 5)
+ code = "ERROR"
+ if (yes_code)
if (href_list["time"])
var/time = text2num(href_list["time"])
- src.timeleft += time
- src.timeleft = min(max(round(src.timeleft), 60), 600)
+ timeleft += time
+ timeleft = min(max(round(timeleft), 60), 600)
if (href_list["timer"])
set_active()
if (href_list["safety"])
set_safety()
if (href_list["anchor"])
set_anchor()
- src.add_fingerprint(usr)
+ add_fingerprint(usr)
for(var/mob/M in viewers(1, src))
if ((M.client && M.machine == src))
- src.attack_hand(M)
+ attack_hand(M)
/obj/machinery/nuclearbomb/proc/set_anchor()
if(!isinspace())
@@ -143,18 +301,17 @@ var/bomb_set
/obj/machinery/nuclearbomb/proc/set_safety()
safety = !safety
- icon_state = (safety ? "nuclearbomb_off" : "nuclearbomb_on")
if(safety)
timing = 0
bomb_set = 0
set_security_level(previous_level)
+ update_icon()
/obj/machinery/nuclearbomb/proc/set_active()
if(safety)
usr << "The safety is still on."
return
timing = !timing
- icon_state = (timing ? "nuclearbomb_active" : "nuclearbomb_on")
previous_level = get_security_level()
if(timing)
bomb_set = 1
@@ -162,13 +319,13 @@ var/bomb_set
else
bomb_set = 0
set_security_level(previous_level)
-
+ update_icon()
/obj/machinery/nuclearbomb/ex_act(severity, target)
return
/obj/machinery/nuclearbomb/blob_act()
- if (src.timing == -1.0)
+ if (timing == -1.0)
return
else
return ..()
@@ -177,19 +334,25 @@ var/bomb_set
#define NUKERANGE 80
/obj/machinery/nuclearbomb/proc/explode()
- if (src.safety)
- src.timing = 0
+ if (safety)
+ timing = 0
return
- src.timing = -1.0
- src.yes_code = 0
- src.safety = 1
- src.icon_state = "nuclearbomb_exploding"
+
+ timing = -1
+ yes_code = 0
+ safety = 1
+ update_icon()
for(var/mob/M in player_list)
M << 'sound/machines/Alarm.ogg'
if (ticker && ticker.mode)
ticker.mode.explosion_in_progress = 1
sleep(100)
+ if(!core)
+ ticker.station_explosion_cinematic(3,"no_core")
+ ticker.mode.explosion_in_progress = 0
+ return
+
enter_allowed = 0
var/off_station = 0
@@ -218,6 +381,7 @@ var/bomb_set
return
return
+
/*
This is here to make the tiles around the station mininuke change when it's armed.
*/
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 34097634102..82c7ac9c296 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -43,7 +43,7 @@
/datum/objective/proc/update_explanation_text()
//Default does nothing, override where needed
-
+/datum/objective/proc/give_special_equipment()
/datum/objective/assassinate
var/target_role_type=0
@@ -348,7 +348,7 @@ var/global/list/possible_items = list()
/datum/objective/steal/find_target()
var/approved_targets = list()
for(var/datum/objective_item/possible_item in possible_items)
- if(is_unique_objective(possible_item.targetitem))
+ if(is_unique_objective(possible_item.targetitem) && !(owner.current.mind.assigned_role in possible_item.excludefromjob))
approved_targets += possible_item
return set_target(safepick(possible_items))
@@ -359,6 +359,7 @@ var/global/list/possible_items = list()
steal_target = targetinfo.targetitem
explanation_text = "Steal [targetinfo.name]."
dangerrating = targetinfo.difficulty
+ give_special_equipment()
return steal_target
else
explanation_text = "Free objective"
@@ -401,6 +402,15 @@ var/global/list/possible_items = list()
return 1
return 0
+/datum/objective/steal/give_special_equipment()
+ if(owner && owner.current && targetinfo)
+ if(istype(owner.current, /mob/living/carbon/human))
+ var/mob/living/carbon/human/H = owner.current
+ var/list/slots = list ("backpack" = slot_in_backpack)
+ for(var/obj/item/I in targetinfo.special_equipment)
+ H.equip_in_one_of_slots(I, slots)
+ H.update_icons()
+
var/global/list/possible_items_special = list()
/datum/objective/steal/special //ninjas are so special they get their own subtype good for them
@@ -576,3 +586,21 @@ var/global/list/possible_items_special = list()
explanation_text = "Destroy [target.name], the experimental AI."
else
explanation_text = "Free Objective"
+
+/datum/objective/summon_guns
+ explanation_text = "Steal at least five guns!"
+
+/datum/objective/summon_guns/check_completion()
+ if(!isliving(owner.current)) return 0
+ var/guncount = 0
+ var/list/all_items = owner.current.GetAllContents() //this should get things in cheesewheels, books, etc.
+ for(var/obj/I in all_items) //Check for guns
+ if(istype(I, /obj/item/weapon/gun))
+ guncount++
+ if(guncount >= 5)
+ return 1
+ else
+ return 0
+ return 0
+
+
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index 981fba6a7d7..63d9cdea7ad 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -6,11 +6,11 @@
var/difficulty = 9001 //vaguely how hard it is to do this objective
var/list/excludefromjob = list() //If you don't want a job to get a certain objective (no captain stealing his own medal, etcetc)
var/list/altitems = list() //Items which can serve as an alternative to the objective (darn you blueprints)
+ var/list/special_equipment = list()
/datum/proc/check_special_completion() //for objectives with special checks (is that slime extract unused? does that intellicard have an ai in it? etcetc)
return 1
-
/datum/objective_item/steal/caplaser
name = "the captain's antique laser gun"
targetitem = /obj/item/weapon/gun/energy/laser/captain
@@ -82,6 +82,14 @@
targetitem = /obj/item/documents //Any set of secret documents. Doesn't have to be NT's
difficulty = 5
+/datum/objective_item/steal/nuke_core
+ name = "the plutonium core from the onboard self-destruct"
+ targetitem = /obj/item/nuke_core
+ difficulty = 15
+
+/datum/objective_item/steal/nuke_core/New()
+ special_equipment += new /obj/item/weapon/storage/box/syndie_kit/nuke()
+
//Items with special checks!
/datum/objective_item/steal/plasma
name = "28 moles of plasma (full tank)"
diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm
index d6abcab574f..e88fa9dc3e7 100644
--- a/code/game/gamemodes/shadowling/shadowling_abilities.dm
+++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm
@@ -285,7 +285,7 @@
thralls++
M << "You feel hooks sink into your mind and pull."
- if(!do_after(user, 30))
+ if(!do_after(user, 30, target = user))
user << "Your concentration has been broken. The mental hooks you have sent out now retract into your mind."
return
@@ -346,7 +346,7 @@
B.reagents.clear_reagents() //Just in case!
B.icon_state = null //Invisible
B.reagents.add_reagent("blindness_smoke", 10)
- var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread
+ var/datum/effect/effect/system/smoke_spread/chem/S = new
S.attach(B)
if(S)
S.set_up(B.reagents, 10, 0, B.loc)
diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm
index 2a38c519a77..7d1a612ecfc 100644
--- a/code/game/gamemodes/wizard/rightandwrong.dm
+++ b/code/game/gamemodes/wizard/rightandwrong.dm
@@ -12,15 +12,18 @@
for(var/mob/living/carbon/human/H in player_list)
if(H.stat == 2 || !(H.client)) continue
if(H.mind)
- if(H.mind.special_role == "Wizard" || H.mind.special_role == "apprentice") continue
+ if(H.mind.special_role == "Wizard" || H.mind.special_role == "apprentice" || H.mind.special_role == "survivalist") continue
if(prob(survivor_probability) && !(H.mind in ticker.mode.traitors))
ticker.mode.traitors += H.mind
- H.mind.special_role = "traitor"
+ var/datum/objective/summon_guns/guns = new
+ guns.owner = H.mind
+ H.mind.objectives += guns
+ H.mind.special_role = "survivalist"
var/datum/objective/survive/survive = new
survive.owner = H.mind
H.mind.objectives += survive
- H.attack_log += "\[[time_stamp()]\] Was made into a survivor, and trusts no one!"
- H << "You are the survivor! Your own safety matters above all else, trust no one and kill anyone who gets in your way. However, armed as you are, now would be the perfect time to settle that score or grab that pair of yellow gloves you've been eyeing..."
+ H.attack_log += "\[[time_stamp()]\] Was made into a survivalist, and trusts no one!"
+ H << "You are the survivalist! Your own safety matters above all else, and the only way to ensure your safety is to stockpile weapons! Grab as many guns as possible, by any means necessary. Kill anyone who gets in your way."
var/obj_count = 1
for(var/datum/objective/OBJ in H.mind.objectives)
H << "Objective #[obj_count]: [OBJ.explanation_text]"
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index 2c9ea69ef97..0f2b69da0ac 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -327,9 +327,9 @@
/datum/spellbook_entry/summon/guns
name = "Summon Guns"
- category = "Challenges"
+ category = "Rituals"
desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. Just be careful not to stand still too long!"
- cost = 0
+ cost = 1
log_name = "SG"
/datum/spellbook_entry/summon/guns/IsAvailible()
@@ -337,11 +337,9 @@
/datum/spellbook_entry/summon/guns/Buy(var/mob/living/carbon/human/user,var/obj/item/weapon/spellbook/book)
feedback_add_details("wizard_spell_learned",log_name)
- rightandwrong(0, user, 0)
- book.uses += 1
- active = 1
+ rightandwrong(0, user, 25)
playsound(get_turf(user),"sound/magic/CastSummon.ogg",50,1)
- user << "You have cast summon guns and gained an extra charge for your spellbook."
+ user << "You have cast summon guns!"
return 1
/datum/spellbook_entry/summon/magic
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 590837a40fd..12c9fec1d69 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -133,7 +133,7 @@ Detective
H.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/black(H), slot_gloves)
H.equip_to_slot_or_del(new /obj/item/clothing/suit/det_suit(H), slot_wear_suit)
H.equip_to_slot_or_del(new /obj/item/toy/crayon/white(H), slot_l_store)
- H.equip_to_slot_or_del(new /obj/item/weapon/lighter/zippo(H), slot_r_store)
+ H.equip_to_slot_or_del(new /obj/item/weapon/lighter(H), slot_r_store)
var/obj/item/clothing/mask/cigarette/cig = new /obj/item/clothing/mask/cigarette(H)
cig.light("")
diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm
index 66be318890e..16b8d76da62 100644
--- a/code/game/machinery/Freezer.dm
+++ b/code/game/machinery/Freezer.dm
@@ -31,7 +31,7 @@
H += M.rating
for(var/obj/item/weapon/stock_parts/micro_laser/M in component_parts)
T += M.rating
- min_temperature = T0C - (170 + (T*15))
+ min_temperature = max(T0C - (170 + (T*15)), 1)
current_heat_capacity = 1000 * ((H - 1) ** 2)
/obj/machinery/atmospherics/unary/cold_sink/freezer/attackby(obj/item/I, mob/user, params)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index e0156b48bb7..be55c50012c 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -157,16 +157,16 @@
dat += "
")
+
+/datum/html_interface/cards/sendResources(client/client)
+ . = ..() // we need the default resources
+
+ client << browse_rsc('cards.css')
+ client << browse_rsc('cards.png')
\ No newline at end of file
diff --git a/code/modules/html_interface/cards/cards.png b/code/modules/html_interface/cards/cards.png
new file mode 100644
index 00000000000..8001168246d
Binary files /dev/null and b/code/modules/html_interface/cards/cards.png differ
diff --git a/code/modules/html_interface/html_interface.css b/code/modules/html_interface/html_interface.css
new file mode 100644
index 00000000000..85c07f3b857
--- /dev/null
+++ b/code/modules/html_interface/html_interface.css
@@ -0,0 +1,11 @@
+html
+{
+ -ms-overflow-style: scrollbar;
+}
+
+body
+{
+ font-family: Arial;
+ overflow-y: scroll;
+ overflow-x: auto;
+}
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface.dm b/code/modules/html_interface/html_interface.dm
new file mode 100644
index 00000000000..2e3359e80c4
--- /dev/null
+++ b/code/modules/html_interface/html_interface.dm
@@ -0,0 +1,355 @@
+/*
+Author: NullQuery
+Created on: 2014-09-24
+
+ ** CAUTION - A WORD OF WARNING **
+
+If there is no getter or setter available and you aren't extending my code with a sub-type, DO NOT ACCESS VARIABLES DIRECTLY!
+
+Add a getter/setter instead, even if it does nothing but return or set the variable. Thank you for your patience with me. -NQ
+
+ ** Public API **
+
+ var/datum/html_interface/hi = new/datum/html_interface(ref, title, width = 700, height = 480, head = "")
+
+Creates a new HTML interface object with [ref] as the object and [title] as the initial title of the page. [width] and [height] is the initial width and height
+of the window. The text in [head] is added just before the end tag.
+
+ hi.setTitle(title)
+
+Changes the title of the page.
+
+ hi.getTitle()
+
+Returns the current title of the page.
+
+ hi.updateLayout(layout)
+
+Updates the overall layout of the page (the HTML code between the body tags).
+
+This should be used sparingly.
+
+ hi.updateContent(id, content, ignore_cache = FALSE)
+
+Updates a portion of the page, i.e., the DOM element with the appropriate ID. The contents of the element are replaced with the provided HTML.
+
+The content is cached on the server-side to minimize network traffic when the client "should have" the same HTML. The client may not have
+the same HTML if scripts cause the content to change. In this case set the ignore_cache parameter.
+
+ hi.executeJavaScript(jscript, client = null)
+
+Executes Javascript on the browser.
+
+The client is optional and may be a /mob, /client or /html_interface_client object. If not specified the code is executed on all clients.
+
+ hi.show(client)
+
+Shows the HTML interface to the provided client. This will create a window, apply the current layout and contents. It will then wait for events.
+
+ hi.hide(client)
+
+Hides the HTML interface from the provided client. This will close the browser window.
+
+ hi.isUsed()
+
+Returns TRUE if the interface is being used (has an active client) or FALSE if not.
+
+ hi.closeAll()
+
+Closes the interface on all clients.
+
+ ** Additional notes **
+
+When working with byond:// links make sure to reference the HTML interface object and NOT the original object. Topic() will still be called on
+your object, but it will pass through the HTML interface first allowing interception at a higher level.
+
+
+ ** Sample code **
+
+mob/var/datum/html_interface/hi
+
+mob/verb/test()
+ if (!hi) hi = new/datum/html_interface(src, "[src.key]")
+
+ hi.updateLayout("")
+ hi.updateContent("content", "
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
")
+
+ hi.show(src)
+
+*/
+
+/var/list/html_interfaces = new/list()
+
+/datum/html_interface
+ // The atom we should report to.
+ var/atom/ref
+
+ // The current title of the browser window.
+ var/title
+
+ // A list of content elements that have been changed. This is necessary when showing the browser control to new clients.
+ var/list/content_elements = new/list()
+
+ // The HTML layout, typically what's in-between the tag. May be overridden by extensions.
+ var/layout
+
+ // An associative list of clients currently viewing this screen. The key is the /client object, the value is the /datum/html_interface_client object.
+ var/list/clients
+
+ // This goes just before the closing HEAD tag. I haven't exposed any getters/setters for it because it's only being used by extensions.
+ var/head = ""
+
+ // The initial width of the browser control, used when the window is first shown to a client.
+ var/width
+
+ // The initial height of the browser control, used when the window is first shown to a client.
+ var/height
+
+/datum/html_interface/New(atom/ref, title, width = 700, height = 480, head = "")
+ html_interfaces.Add(src)
+
+ . = ..()
+
+ src.ref = ref
+ src.title = title
+ src.width = width
+ src.height = height
+ src.head = head
+
+/datum/html_interface/Destroy()
+ src.closeAll()
+
+ html_interfaces.Remove(src)
+
+ return ..()
+
+/* * Hooks */
+/datum/html_interface/proc/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
+
+/datum/html_interface/proc/sendResources(client/client)
+ client << browse_rsc('jquery.min.js')
+ client << browse_rsc('bootstrap.min.js')
+ client << browse_rsc('bootstrap.min.css')
+ client << browse_rsc('html_interface.css')
+ client << browse_rsc('html_interface.js')
+
+/datum/html_interface/proc/createWindow(datum/html_interface_client/hclient)
+ winclone(hclient.client, "window", "browser_\ref[src]")
+
+ var/list/params = list(
+ "size" = "[width]x[height]",
+ "statusbar" = "false",
+ "on-close" = "byond://?src=\ref[src]&html_interface_action=onclose"
+ )
+
+ if (hclient.client.hi_last_pos) params["pos"] = "[hclient.client.hi_last_pos]"
+
+ winset(hclient.client, "browser_\ref[src]", list2params(params))
+
+ winset(hclient.client, "browser_\ref[src].browser", list2params(list("parent" = "browser_\ref[src]", "type" = "browser", "pos" = "0,0", "size" = "[width]x[height]", "anchor1" = "0,0", "anchor2" = "100,100", "use-title" = "true", "auto-format" = "false")))
+
+/* * Public API */
+/datum/html_interface/proc/getTitle() return src.title
+
+/datum/html_interface/proc/setTitle(title, ignore_cache = FALSE)
+ src.title = title
+
+ var/datum/html_interface_client/hclient
+
+ for (var/client in src.clients)
+ hclient = src._getClient(src.clients[client])
+
+ if (hclient && hclient.active) src._renderTitle(src.clients[client], ignore_cache)
+
+/datum/html_interface/proc/executeJavaScript(jscript, datum/html_interface_client/hclient = null)
+ if (hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ if (hclient.is_loaded) hclient.client << output(list2params(list(jscript)), "browser_\ref[src].browser:eval")
+ else
+ for (var/client in src.clients) if(src.clients[client]) src.executeJavaScript(jscript, src.clients[client])
+
+/datum/html_interface/proc/callJavaScript(func, list/arguments, datum/html_interface_client/hclient = null)
+ if (!arguments) arguments = new/list()
+
+ if (hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ if (hclient.is_loaded)
+ hclient.client << output(list2params(arguments), "browser_\ref[src].browser:[func]")
+ else
+ for (var/client in src.clients) if (src.clients[client]) src.callJavaScript(func, arguments, src.clients[client])
+
+/datum/html_interface/proc/updateLayout(layout)
+ src.layout = layout
+
+ var/datum/html_interface_client/hclient
+
+ for (var/client in src.clients)
+ hclient = src._getClient(src.clients[client])
+
+ if (hclient && hclient.active) src._renderLayout(hclient)
+
+/datum/html_interface/proc/updateContent(id, content, ignore_cache = FALSE)
+ src.content_elements[id] = content
+
+ var/datum/html_interface_client/hclient
+
+ for (var/client in src.clients)
+ hclient = src._getClient(src.clients[client])
+
+ if (hclient && hclient.active)
+ spawn (-1) src._renderContent(id, hclient, ignore_cache)
+
+/datum/html_interface/proc/show(datum/html_interface_client/hclient)
+ hclient = getClient(hclient, TRUE)
+
+ if (istype(hclient))
+ // This needs to be commented out due to BYOND bug http://www.byond.com/forum/?post=1487244
+ // /client/proc/send_resources() executes this per client to avoid the bug, but by using it here files may be deleted just as the HTML is loaded,
+ // causing file not found errors.
+// src.sendResources(hclient.client)
+
+ if (winexists(hclient.client, "browser_\ref[src]"))
+ src._renderTitle(hclient, TRUE)
+ src._renderLayout(hclient)
+ else
+ src.createWindow(hclient)
+ hclient.is_loaded = FALSE
+ hclient.client << output(replacetextEx(replacetextEx(file2text('html_interface.html'), "\[hsrc\]", "\ref[src]"), "", "[head]"), "browser_\ref[src].browser")
+ winshow(hclient.client, "browser_\ref[src]", TRUE)
+
+ while (hclient.client && hclient.active && !hclient.is_loaded) sleep(2)
+
+/datum/html_interface/proc/hide(datum/html_interface_client/hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ if (src.clients)
+ src.clients.Remove(hclient.client)
+
+ if (!src.clients.len) src.clients = null
+
+ hclient.client.hi_last_pos = winget(hclient.client, "browser_\ref[src]" ,"pos")
+
+ winshow(hclient.client, "browser_\ref[src]", FALSE)
+ winset(hclient.client, "browser_\ref[src]", "parent=none")
+
+ if (hascall(src.ref, "hiOnHide")) call(src.ref, "hiOnHide")(hclient)
+
+// Convert a /mob to /client, and /client to /datum/html_interface_client
+/datum/html_interface/proc/getClient(client, create_if_not_exist = FALSE)
+ if (istype(client, /datum/html_interface_client)) return src._getClient(client)
+ else if (ismob(client))
+ var/mob/mob = client
+ client = mob.client
+
+ if (istype(client, /client))
+ if (create_if_not_exist && (!src.clients || !(client in src.clients)))
+ if (!src.clients) src.clients = new/list()
+ if (!(client in src.clients)) src.clients[client] = new/datum/html_interface_client(client)
+
+ if (src.clients && (client in src.clients)) return src._getClient(src.clients[client])
+ else return null
+ else return null
+
+/datum/html_interface/proc/enableFor(datum/html_interface_client/hclient)
+ hclient.active = TRUE
+
+ src.show(hclient)
+
+/datum/html_interface/proc/disableFor(datum/html_interface_client/hclient)
+ hclient.active = FALSE
+
+/datum/html_interface/proc/isUsed()
+ if (src.clients && src.clients.len > 0)
+ var/datum/html_interface_client/hclient
+
+ for (var/key in clients)
+ hclient = _getClient(clients[key])
+
+ if (hclient)
+ if (hclient.active) return TRUE
+ else
+ clients.Remove(key)
+
+ return FALSE
+
+/datum/html_interface/proc/closeAll()
+ if (src.clients)
+ for (var/client in src.clients)
+ src.hide(src.clients[client])
+
+/* * Danger Zone */
+
+/datum/html_interface/proc/_getClient(datum/html_interface_client/hclient)
+ if (hclient)
+ if (hclient.client)
+ // res = if the client has been active in the past 10 minutes and the client is allowed to view the object (context-sensitive).
+ var/res = hclient.client.inactivity <= 6000 && (hascall(src.ref, "hiIsValidClient") ? call(src.ref, "hiIsValidClient")(hclient, src) : TRUE)
+
+ if (res)
+ if (!hclient.active) src.enableFor(hclient)
+ else
+ if (hclient.active) src.disableFor(hclient)
+
+ return hclient
+ else
+ return null
+ else
+ return null
+
+/datum/html_interface/proc/_renderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE, ignore_loaded = FALSE)
+ if (hclient && (ignore_loaded || hclient.is_loaded))
+ // Only render if we have new content.
+
+ if (ignore_cache || src.title != hclient.title)
+ hclient.title = title
+
+ src.specificRenderTitle(hclient)
+
+ hclient.client << output(list2params(list(title)), "browser_\ref[src].browser:setTitle")
+
+/datum/html_interface/proc/_renderLayout(datum/html_interface_client/hclient, ignore_loaded = FALSE)
+ if (hclient && (ignore_loaded || hclient.is_loaded))
+ var/html = src.layout
+
+ // Only render if we have new content.
+ if (html != hclient.layout)
+ hclient.layout = html
+
+ hclient.client << output(list2params(list(html)), "browser_\ref[src].browser:updateLayout")
+
+ for (var/id in src.content_elements) src._renderContent(id, hclient, ignore_loaded = ignore_loaded)
+
+/datum/html_interface/proc/_renderContent(id, datum/html_interface_client/hclient, ignore_cache = FALSE, ignore_loaded = FALSE)
+ if (hclient && (ignore_loaded || hclient.is_loaded))
+ var/html = src.content_elements[id]
+
+ // Only render if we have new content.
+ if (ignore_cache || !(id in hclient.content_elements) || html != hclient.content_elements[id])
+ hclient.content_elements[id] = html
+
+ hclient.client << output(list2params(list(id, html)), "browser_\ref[src].browser:updateContent")
+
+/datum/html_interface/Topic(href, href_list[])
+ var/datum/html_interface_client/hclient = getClient(usr.client)
+
+ if (istype(hclient))
+ if ("html_interface_action" in href_list)
+ switch (href_list["html_interface_action"])
+
+ if ("onload")
+ hclient.layout = null
+ hclient.content_elements.len = 0
+
+ src._renderTitle(hclient, TRUE, TRUE)
+ src._renderLayout(hclient, TRUE)
+
+ hclient.is_loaded = TRUE
+
+ if ("onclose")
+ src.hide(hclient)
+ else if (src.ref && hclient.active) src.ref.Topic(href, href_list, hclient)
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface.html b/code/modules/html_interface/html_interface.html
new file mode 100644
index 00000000000..1231c21df53
--- /dev/null
+++ b/code/modules/html_interface/html_interface.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface.js b/code/modules/html_interface/html_interface.js
new file mode 100644
index 00000000000..83300ee27c4
--- /dev/null
+++ b/code/modules/html_interface/html_interface.js
@@ -0,0 +1,45 @@
+var is_loading = false;
+var load_count = 0;
+
+function onload()
+{
+ if (!is_loading)
+ {
+ var count = ++load_count;
+ is_loading = true;
+ $("body").html("");
+
+ window.location.href = "byond://?src=" + hSrc + "&html_interface_action=onload";
+
+ // The request may fail which would prevent the player from refreshing the screen again. Try to detect this retry.
+ setTimeout(function()
+ {
+ if (count == load_count && is_loading && $("body").html() == "")
+ {
+ is_loading = false;
+ onload();
+ }
+ }, 500);
+ }
+}
+
+$(document).ready(function()
+{
+ $(document).on("keydown", function(e)
+ {
+ if (!e.ctrlKey && e.which == 116)
+ {
+ e.preventDefault();
+
+ onload();
+ }
+ });
+
+ onload();
+});
+
+function fixText(text) { return text.replace(/ÿ/g, ""); }
+
+function setTitle(new_title) { $("title").html(fixText(new_title)); $(window).trigger("onUpdateTitle"); }
+function updateLayout(new_html) { $("body").html(fixText(new_html)); $(window).trigger("onUpdateLayout"); setTimeout(function(){ is_loading = false; }, 200); }
+function updateContent(id, new_html) { $("#" + id).html(fixText(new_html)); $(window).trigger("onUpdateContent"); }
\ No newline at end of file
diff --git a/code/modules/html_interface/html_interface_client.dm b/code/modules/html_interface/html_interface_client.dm
new file mode 100644
index 00000000000..e571a86b3a2
--- /dev/null
+++ b/code/modules/html_interface/html_interface_client.dm
@@ -0,0 +1,43 @@
+/datum/html_interface_client
+ // The /client object represented by this model.
+ var/client/client
+
+ // The layout currently visible to the client.
+ var/layout
+
+ // The content elements (mirrored from /datum/html_interface) currently visible to the client.
+ var/list/content_elements = new/list()
+
+ // The current title for this client
+ var/title
+
+ // TRUE if the browser control has loaded and will accept input, FALSE if not.
+ var/is_loaded = FALSE
+
+ // TRUE if this client should receive updates, FALSE if not.
+ var/active = TRUE
+
+ // A list of extra variables, for use by extensions.
+ var/list/extra_vars
+
+/datum/html_interface_client/New(client/client)
+ . = ..()
+
+ src.client = client
+
+/datum/html_interface_client/proc/putExtraVar(key, value)
+ if (!src.extra_vars) src.extra_vars = new/list()
+ src.extra_vars[key] = value
+
+/datum/html_interface_client/proc/removeExtraVar(key)
+ if (src.extra_vars)
+ . = src.extra_vars[key]
+
+ src.extra_vars.Remove(key)
+
+ if (!src.extra_vars.len) src.extra_vars = null
+
+ return .
+
+/datum/html_interface_client/proc/getExtraVar(key)
+ if (src.extra_vars) return src.extra_vars[key]
\ No newline at end of file
diff --git a/code/modules/html_interface/jquery.min.js b/code/modules/html_interface/jquery.min.js
new file mode 100644
index 00000000000..ab28a24729b
--- /dev/null
+++ b/code/modules/html_interface/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
+if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
")
+
+/datum/html_interface/specificRenderTitle(datum/html_interface_client/hclient, ignore_cache = FALSE)
+ // Update the title in our custom header (in addition to default functionality)
+ winset(hclient.client, "browser_\ref[src].uiTitle", list2params(list("text" = "[src.title]")))
+
+/datum/html_interface/nanotrasen/sendResources(client/client)
+ . = ..() // we need the default resources
+
+ client << browse_rsc('uiBg.png')
+ client << browse_rsc('uiBgcenter.png')
+ client << browse_rsc('nanotrasen.css')
+
+/datum/html_interface/nanotrasen/createWindow(datum/html_interface_client/hclient)
+ . = ..() // we want the default window
+
+ // Remove the titlebar
+ winset(hclient.client, "browser_\ref[src]", list2params(list(
+ "titlebar" = "false"
+ )))
+
+ // Reposition the browser
+ winset(hclient.client, "browser_\ref[src].browser", list2params(list(
+ "pos" = "0,35",
+ "size" = "[width]x[height - 35]"
+ )))
+
+ // Add top background image
+ winset(hclient.client, "browser_\ref[src].topbg", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "pos" = "0,0",
+ "size" = "[width]x35",
+ "anchor1" = "0,0",
+ "anchor2" = "100,0",
+ "image" = "['uiBgtop.png']",
+ "image-mode" = "tile",
+ "is-disabled" = "true"
+ )))
+
+ // Add Nanotrasen logo
+ winset(hclient.client, "browser_\ref[src].uiTitleFluff", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "pos" = "[width - 42 - 4 - 24 - 4 - 24 - 4],5",
+ "size" = "42x24",
+ "anchor1" = "100,0",
+ "anchor2" = "100,0",
+ "image" = "['uiTitleFluff.png']",
+ "image-mode" = "tile",
+ "is-disabled" = "true"
+ )))
+
+ // Add Eye picture
+ winset(hclient.client, "browser_\ref[src].uiTitleEye", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "pos" = "8,5",
+ "size" = "42x24",
+ "anchor1" = "0,0",
+ "anchor2" = "0,0",
+ "image" = "['uiEyeGreen.png']",
+ "image-mode" = "tile",
+ "is-disabled" = "true"
+ )))
+
+ // Add title text
+ winset(hclient.client, "browser_\ref[src].uiTitle", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "label",
+ "is-transparent" = "true",
+ "pos" = "64,0",
+ "size" = "580x35",
+ "anchor1" = "0,0",
+ "anchor2" = "100,0",
+ "is-disabled" = "true",
+ "text" = "[src.title]",
+ "align" = "left",
+ "font-family" = "verdana,Geneva,sans-serif",
+ "font-size" = "12", // ~ 16px
+ "text-color" = "#E9C183"
+ )))
+
+ // Add minimize button
+ // TODO: Style the button (add image)
+ winset(hclient.client, "browser_\ref[src].uiTitleMinimize", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "button",
+ "is-flat" = "true",
+ "background-color"="#383838", // should be unnecessary if image is used
+ "text-color" = "#FFFFFF", // should be unnecessary if image is used
+ "is-transparent" = "true",
+ "pos" = "[width - 24 - 4 - 24 - 4],5",
+ "size" = "24x24",
+ "anchor1" = "100,0",
+ "anchor2" = "100,0",
+ "text" = "-",
+ "font-family" = "verdana,Geneva,sans-serif", // should be unnecessary if image is used
+ "font-size" = "12", // ~ 16px - should be unnecessary if image is used
+
+ // Disable resizing (disables maximizing), minimize window, bind window.on-size to catch 'restore window' button to enable resizing if restored.
+ "command" = ".winset \"browser_\ref[src].can-resize=false;browser_\ref[src].is-minimized=true;browser_\ref[src].on-size=\".swinset \\\"browser_\ref[src].can-resize=true;browser_\ref[src].on-size=\\\"\"\""
+ )))
+
+ // Add close button
+ // TODO: Style the button (add image)
+ winset(hclient.client, "browser_\ref[src].uiTitleClose", list2params(list(
+ "parent" = "browser_\ref[src]",
+ "type" = "button",
+ "is-flat" = "true",
+ "background-color"="#383838", // should be unnecessary if image is used
+ "text-color" = "#FFFFFF", // should be unnecessary if image is used
+ "command" = "byond://?src=\ref[src];html_interface_action=onclose",
+ "is-transparent" = "true",
+ "pos" = "[width - 24 - 4],5",
+ "size" = "24x24",
+ "anchor1" = "100,0",
+ "anchor2" = "100,0",
+ "text" = "X",
+ "font-family" = "verdana,Geneva,sans-serif", // should be unnecessary if image is used
+ "font-size" = "12" // ~ 16px - should be unnecessary if image is used
+ )))
+
+/datum/html_interface/nanotrasen/enableFor(datum/html_interface_client/hclient)
+ . = ..()
+
+ src.setEyeColor("green", hclient)
+
+/datum/html_interface/nanotrasen/disableFor(datum/html_interface_client/hclient)
+ hclient.active = FALSE
+
+ src.setEyeColor("red", hclient)
+
+/datum/html_interface/nanotrasen/proc/setEyeColor(color, datum/html_interface_client/hclient)
+ hclient = getClient(hclient)
+
+ if (istype(hclient))
+ var/resource
+ switch (color)
+ if ("green") resource = 'uiEyeGreen.png'
+ if ("orange") resource = 'uiEyeOrange.png'
+ if ("red") resource = 'uiEyeRed.png'
+ else CRASH("Invalid color: [color]")
+
+ if (hclient.getExtraVar("eye_color") != color)
+ hclient.putExtraVar("eye_color", color)
+
+ winset(hclient.client, "browser_\ref[src].uiTitleEye", list2params(list("image" = "[resource]")))
+ else
+ WARNING("Invalid object passed to /datum/html_interface/nanotrasen/proc/setEyeColor")
\ No newline at end of file
diff --git a/code/modules/html_interface/nanotrasen/uiBg.png b/code/modules/html_interface/nanotrasen/uiBg.png
new file mode 100644
index 00000000000..bba99d3106a
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiBg.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiBgcenter.png b/code/modules/html_interface/nanotrasen/uiBgcenter.png
new file mode 100644
index 00000000000..b258f180192
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiBgcenter.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiBgtop.png b/code/modules/html_interface/nanotrasen/uiBgtop.png
new file mode 100644
index 00000000000..a3579d6df94
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiBgtop.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiEyeGreen.png b/code/modules/html_interface/nanotrasen/uiEyeGreen.png
new file mode 100644
index 00000000000..0205f4ae00c
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiEyeGreen.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiEyeOrange.png b/code/modules/html_interface/nanotrasen/uiEyeOrange.png
new file mode 100644
index 00000000000..cce6cfe5374
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiEyeOrange.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiEyeRed.png b/code/modules/html_interface/nanotrasen/uiEyeRed.png
new file mode 100644
index 00000000000..662f0d522fa
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiEyeRed.png differ
diff --git a/code/modules/html_interface/nanotrasen/uiTitleFluff.png b/code/modules/html_interface/nanotrasen/uiTitleFluff.png
new file mode 100644
index 00000000000..5d499f7afad
Binary files /dev/null and b/code/modules/html_interface/nanotrasen/uiTitleFluff.png differ
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index ba32bb2c6ff..bec34b1c197 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -169,6 +169,7 @@
dat += "Shoulder holster: Make ([400/efficiency]) "
dat += "Leather Satchel: Make ([400/efficiency]) "
dat += "Leather Jacket: Make ([500/efficiency]) "
+ dat += "Leather Overcoat: Make ([1000/efficiency]) "
dat += "
"
else
dat += "
No container inside, please insert container.
"
@@ -301,6 +302,9 @@
if("jacket")
if (check_cost(500/efficiency)) return 0
else new/obj/item/clothing/suit/jacket/leather(src.loc)
+ if("overcoat")
+ if (check_cost(1000/efficiency)) return 0
+ else new/obj/item/clothing/suit/jacket/leather/overcoat(src.loc)
//if("monkey")
// if (check_cost(500)) return 0
// else new/mob/living/carbon/monkey(src.loc)
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 38c9be4e471..8fe33dc7e58 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -20,6 +20,7 @@
icon = 'icons/obj/hydroponics/harvest.dmi'
potency = -1
dried_type = -1 //bit different. saves us from having to define each stupid grown's dried_type as itself. If you don't want a plant to be driable (watermelons) set this to null in the time definition.
+ burn_state = 0 //Burnable
/obj/item/weapon/reagent_containers/food/snacks/grown/New(newloc, new_potency = 50)
..()
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 07ee7c17a2e..f0ca0943691 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -5,6 +5,7 @@
/obj/item/weapon/grown // Grown weapons
name = "grown_weapon"
icon = 'icons/obj/hydroponics/harvest.dmi'
+ burn_state = 0 //Burnable
var/seed = null
var/plantname = ""
var/product //a type path
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 3b3b9ab28d2..bb6cf6c74af 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -730,7 +730,7 @@
user.visible_message("[user] begins to wrench [src] into place.", \
"You begin to wrench [src] in place...")
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
- if (do_after(user, 20))
+ if (do_after(user, 20, target = src))
if(anchored)
return
anchored = 1
@@ -740,7 +740,7 @@
user.visible_message("[user] begins to unwrench [src].", \
"You begin to unwrench [src]...")
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
- if (do_after(user, 20))
+ if (do_after(user, 20, target = src))
if(!anchored)
return
anchored = 0
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 0e491e575bf..662f76cb686 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -7,6 +7,7 @@
icon = 'icons/obj/hydroponics/seeds.dmi'
icon_state = "seed" //Unknown plant seed - these shouldn't exist in-game.
w_class = 1 //Pocketable.
+ burn_state = 0 //Burnable
var/plantname = "Plants" //Name of plant when planted.
var/product //A type path. The thing that is created when the plant is harvested.
var/species = "" //Used to update icons. Should match the name in the sprites.
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index 298ebdcf61c..96dc3f1b9a1 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -17,6 +17,8 @@
anchored = 0
density = 1
opacity = 0
+ burn_state = 0 //Burnable
+ burntime = 30
var/state = 0
var/list/allowed_books = list(/obj/item/weapon/book, /obj/item/weapon/spellbook, /obj/item/weapon/storage/book) //Things allowed in the bookcase
@@ -36,13 +38,13 @@
if(0)
if(istype(I, /obj/item/weapon/wrench))
playsound(loc, 'sound/items/Ratchet.ogg', 100, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
user << "You wrench the frame into place."
anchored = 1
state = 1
if(istype(I, /obj/item/weapon/crowbar))
playsound(loc, 'sound/items/Crowbar.ogg', 100, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
user << "You pry the frame apart."
new /obj/item/stack/sheet/mineral/wood(loc, 4)
qdel(src)
@@ -165,6 +167,7 @@
throw_range = 5
w_class = 3 //upped to three because books are, y'know, pretty big. (and you could hide them inside eachother recursively forever)
attack_verb = list("bashed", "whacked", "educated")
+ burn_state = 0 //Burnable
var/dat //Actual page content
var/due_date = 0 //Game time in 1/10th seconds
var/author //Who wrote the thing, can be changed by pen or PC. It is not automatically assigned
@@ -253,7 +256,7 @@
else if(istype(I, /obj/item/weapon/kitchen/knife) || istype(I, /obj/item/weapon/wirecutters))
user << "You begin to carve out [title]..."
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
user << "You carve out the pages from [title]! You didn't want to read it anyway."
var/obj/item/weapon/storage/book/B = new
B.name = src.name
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
new file mode 100644
index 00000000000..1e38491439f
--- /dev/null
+++ b/code/modules/mining/abandoned_crates.dm
@@ -0,0 +1,212 @@
+//Originally coded by ISaidNo, later modified by Kelenius. Ported from Baystation12.
+
+/obj/structure/closet/crate/secure/loot
+ name = "abandoned crate"
+ desc = "What could be inside?"
+ icon_crate = "securecrate"
+ icon_state = "securecrate"
+ var/code = null
+ var/lastattempt = null
+ var/attempts = 10
+ var/codelen = 4
+ locked = 1
+
+/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) //100 different crates with varying chances of spawning
+ switch(loot)
+ if(1 to 5) //5% chance
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/rum(src)
+ new /obj/item/weapon/reagent_containers/food/snacks/grown/ambrosia(src)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/whiskey(src)
+ new /obj/item/weapon/lighter(src)
+ if(6 to 10)
+ new /obj/item/weapon/bedsheet(src)
+ new /obj/item/weapon/kitchen/knife(src)
+ new /obj/item/weapon/wirecutters(src)
+ new /obj/item/weapon/screwdriver(src)
+ new /obj/item/weapon/weldingtool(src)
+ new /obj/item/weapon/hatchet(src)
+ new /obj/item/weapon/crowbar(src)
+ if(11 to 15)
+ new /obj/item/weapon/reagent_containers/glass/beaker/bluespace(src)
+ if(16 to 20)
+ for(var/i = 0, i < 10, i++)
+ new /obj/item/weapon/ore/diamond(src)
+ if(21 to 25)
+ for(var/i = 0, i < 5, i++)
+ new /obj/item/weapon/contraband/poster(src)
+ if(26 to 30)
+ for(var/i = 0, i < 3, i++)
+ new /obj/item/weapon/reagent_containers/glass/beaker/noreact(src)
+ if(31 to 35)
+ new /obj/item/seeds/cashseed(src)
+ if(36 to 40)
+ new /obj/item/weapon/melee/baton(src)
+ if(41 to 45)
+ new /obj/item/clothing/under/shorts/red(src)
+ new /obj/item/clothing/under/shorts/blue(src)
+ 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)
+ if(51 to 52) // 2% chance
+ new /obj/item/weapon/melee/classic_baton(src)
+ if(53 to 54)
+ new /obj/item/toy/balloon(src)
+ if(55 to 56)
+ var/newitem = pick(typesof(/obj/item/toy/prize) - /obj/item/toy/prize)
+ new newitem(src)
+ if(57 to 58)
+ new /obj/item/toy/syndicateballoon(src)
+ if(59 to 60)
+ new /obj/item/weapon/pickaxe/drill(src)
+ new /obj/item/device/taperecorder(src)
+ new /obj/item/clothing/suit/space(src)
+ new /obj/item/clothing/head/helmet/space(src)
+ if(61 to 62)
+ for(var/i = 0, i < 12, ++i)
+ new /obj/item/clothing/head/kitty(src)
+ if(63 to 64)
+ var/t = rand(4,7)
+ for(var/i = 0, i < t, ++i)
+ var/newcoin = pick(/obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/silver, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/iron, /obj/item/weapon/coin/gold, /obj/item/weapon/coin/diamond, /obj/item/weapon/coin/plasma, /obj/item/weapon/coin/uranium)
+ new newcoin(src)
+ if(65 to 66)
+ new /obj/item/clothing/suit/ianshirt(src)
+ if(67 to 68)
+ var/t = rand(4,7)
+ for(var/i = 0, i < t, ++i)
+ var /newitem = pick(typesof(/obj/item/weapon/stock_parts) - /obj/item/weapon/stock_parts - /obj/item/weapon/stock_parts/subspace)
+ new newitem(src)
+ if(69 to 70)
+ for(var/i = 0, i < 5, ++i)
+ new /obj/item/bluespace_crystal(src)
+ if(71 to 72)
+ new /obj/item/weapon/pickaxe/drill(src)
+ if(73 to 74)
+ new /obj/item/weapon/pickaxe/drill/jackhammer(src)
+ if(75 to 76)
+ new /obj/item/weapon/pickaxe/diamond(src)
+ if(77 to 78)
+ new /obj/item/weapon/pickaxe/drill/diamonddrill(src)
+ if(79 to 80)
+ new /obj/item/weapon/cane(src)
+ new /obj/item/clothing/head/collectable/tophat(src)
+ if(81 to 82)
+ new /obj/item/weapon/gun/energy/plasmacutter(src)
+ if(83 to 84)
+ new /obj/item/toy/katana(src)
+ if(85 to 86)
+ new /obj/item/weapon/defibrillator/compact(src)
+ if(87) //1% chance
+ new /obj/item/weed_extract(src)
+ if(88)
+ new /obj/item/organ/brain(src)
+ if(89)
+ new /obj/item/organ/brain/alien(src)
+ if(90)
+ new /obj/item/organ/heart(src)
+ if(91)
+ new /obj/item/device/soulstone/anybody(src)
+ if(92)
+ new /obj/item/weapon/katana(src)
+ if(93)
+ new /obj/item/weapon/dnainjector/xraymut(src)
+ if(94)
+ new /obj/item/weapon/storage/backpack/clown(src)
+ new /obj/item/clothing/under/rank/clown(src)
+ new /obj/item/clothing/shoes/clown_shoes(src)
+ new /obj/item/device/pda/clown(src)
+ new /obj/item/clothing/mask/gas/clown_hat(src)
+ new /obj/item/weapon/bikehorn(src)
+ new /obj/item/toy/crayon/rainbow(src)
+ new /obj/item/weapon/reagent_containers/spray/waterflower(src)
+ if(95)
+ new /obj/item/clothing/under/rank/mime(src)
+ new /obj/item/clothing/shoes/sneakers/black(src)
+ new /obj/item/device/pda/mime(src)
+ new /obj/item/clothing/gloves/color/white(src)
+ new /obj/item/clothing/mask/gas/mime(src)
+ new /obj/item/clothing/head/beret(src)
+ new /obj/item/clothing/suit/suspenders(src)
+ new /obj/item/toy/crayon/mime(src)
+ new /obj/item/weapon/reagent_containers/food/drinks/bottle/bottleofnothing(src)
+ if(96)
+ new /obj/item/weapon/hand_tele(src)
+ if(97)
+ new /obj/item/clothing/mask/balaclava
+ new /obj/item/weapon/gun/projectile/automatic/pistol(src)
+ new /obj/item/ammo_box/magazine/m10mm(src)
+ if(98)
+ new /obj/item/weapon/katana/cursed(src)
+ if(99)
+ new /obj/item/weapon/storage/belt/champion(src)
+ new /obj/item/clothing/mask/luchador(src)
+ if(100)
+ new /obj/item/clothing/head/bearpelt(src)
+
+/obj/structure/closet/crate/secure/loot/attack_hand(mob/user as mob)
+ if(locked)
+ user << "The crate is locked with a Deca-code lock."
+ var/input = input(usr, "Enter [codelen] digits.", "Deca-Code Lock", "") as text
+ if(user.canUseTopic(src, 1))
+ if (input == code)
+ user << "The crate unlocks!"
+ locked = 0
+ overlays.Cut()
+ overlays += greenlight
+ else if (input == null || length(input) != codelen)
+ user << "You leave the crate alone."
+ else
+ user << "A red light flashes."
+ lastattempt = input
+ attempts--
+ if (attempts == 0)
+ user << "The crate's anti-tamper system activates!"
+ var/turf/T = get_turf(src.loc)
+ explosion(T, -1, -1, 1, 1)
+ qdel(src)
+ return
+ else
+ return ..()
+
+/obj/structure/closet/crate/secure/loot/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(locked)
+ if (istype(W, /obj/item/weapon/card/emag))
+ user << "The crate's anti-tamper system activates!"
+ var/turf/T = get_turf(src.loc)
+ explosion(T, -1, -1, 1, 1)
+ qdel(src)
+ return
+ if (istype(W, /obj/item/device/multitool))
+ user << "DECA-CODE LOCK REPORT:"
+ if (attempts == 1)
+ user << "* Anti-Tamper Bomb will activate on next failed access attempt."
+ else
+ user << "* Anti-Tamper Bomb will activate after [src.attempts] failed access attempts."
+ if (lastattempt != null)
+ var/list/guess = list()
+ var/bulls = 0
+ var/cows = 0
+ for(var/i = 1, i < codelen + 1, i++)
+ var/a = copytext(lastattempt, i, i+1) //Stuff the code into the list
+ guess += a
+ guess[a] = i
+ for(var/i in guess) //Go through list and count matches
+ var/a = findtext(code, i)
+ if(a == guess[i])
+ ++bulls
+ else if(a)
+ ++cows
+ user << "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions."
+ else ..()
+ else ..()
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index 3ba4b0cdea6..80fb5aa07b9 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -9,6 +9,26 @@
/**********************Miner Lockers**************************/
+/obj/structure/closet/wardrobe/miner
+ name = "mining wardrobe"
+ icon_door = "mixed"
+
+/obj/structure/closet/wardrobe/miner/New()
+ ..()
+ contents = list()
+ new /obj/item/weapon/storage/backpack/dufflebag/engineering(src)
+ new /obj/item/weapon/storage/backpack/industrial(src)
+ new /obj/item/weapon/storage/backpack/satchel_eng(src)
+ new /obj/item/clothing/under/rank/miner(src)
+ new /obj/item/clothing/under/rank/miner(src)
+ new /obj/item/clothing/under/rank/miner(src)
+ new /obj/item/clothing/shoes/sneakers/black(src)
+ new /obj/item/clothing/shoes/sneakers/black(src)
+ new /obj/item/clothing/shoes/sneakers/black(src)
+ new /obj/item/clothing/gloves/fingerless(src)
+ new /obj/item/clothing/gloves/fingerless(src)
+ new /obj/item/clothing/gloves/fingerless(src)
+
/obj/structure/closet/secure_closet/miner
name = "miner's equipment"
icon_state = "mining"
@@ -16,14 +36,7 @@
/obj/structure/closet/secure_closet/miner/New()
..()
- if(prob(50))
- new /obj/item/weapon/storage/backpack/industrial(src)
- else
- new /obj/item/weapon/storage/backpack/satchel_eng(src)
new /obj/item/device/radio/headset/headset_cargo(src)
- new /obj/item/clothing/under/rank/miner(src)
- new /obj/item/clothing/gloves/fingerless(src)
- new /obj/item/clothing/shoes/sneakers/black(src)
new /obj/item/device/mining_scanner(src)
new /obj/item/weapon/storage/bag/ore(src)
new /obj/item/weapon/shovel(src)
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 00bed34c8fd..2f3218f4e27 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -431,7 +431,7 @@ var/global/list/rockTurfEdgeCache
user << "You start picking..."
P.playDigSound()
- if(do_after(user,P.digspeed))
+ if(do_after(user,P.digspeed, target = src))
if(istype(src, /turf/simulated/mineral)) //sanity check against turf being deleted during digspeed delay
user << "You finish cutting into the rock."
P.update_icon()
diff --git a/code/modules/mining/money_bag.dm b/code/modules/mining/money_bag.dm
index e9befa30d43..a8eefeb5bfc 100644
--- a/code/modules/mining/money_bag.dm
+++ b/code/modules/mining/money_bag.dm
@@ -8,6 +8,8 @@
force = 10.0
throwforce = 0
w_class = 4.0
+ burn_state = 0 //Burnable
+ burntime = 20
/obj/item/weapon/moneybag/attack_hand(user as mob)
var/amt_gold = 0
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index baddbc27a53..52e97f3a423 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -326,7 +326,7 @@
flick("coin_[cmineral]_flip", src)
icon_state = "coin_[cmineral]_[coinflip]"
playsound(user.loc, 'sound/items/coinflip.ogg', 50, 1)
- if(do_after(user, 15))
+ if(do_after(user, 15, target = src))
user.visible_message("[user] has flipped [src]. It lands on [coinflip].", \
"You flip [src]. It lands on [coinflip].", \
"You hear the clattering of loose change.")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 02b856d2356..558604dad94 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -146,3 +146,6 @@
/mob/living/carbon/alien/humanoid/check_ear_prot()
return 1
+
+/mob/living/carbon/alien/carbon/alien/humanoid/get_permeability_protection()
+ return 0.8
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
index 9670240e4aa..1b58d61fb27 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
@@ -84,7 +84,9 @@
overlays.Cut()
if(stat == DEAD)
icon_state = "queen_dead"
- else if(stat == UNCONSCIOUS || lying || resting)
+ else if((stat == UNCONSCIOUS && !sleeping) || weakened)
+ icon_state = "queen_l"
+ else if(sleeping || lying || resting)
icon_state = "queen_sleep"
else
icon_state = "queen_s"
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 39b9a267f9e..f081e566f3a 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -64,4 +64,5 @@
return 1
/mob/living/carbon/alien/CheckStamina()
+ setStaminaLoss(max((staminaloss - 2), 0))
return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 7ff98ab7531..c053d20c090 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -15,9 +15,10 @@ var/const/MAX_ACTIVE_TIME = 400
icon_state = "facehugger"
item_state = "facehugger"
w_class = 1 //note: can be picked up by aliens unlike most other items of w_class below 4
- flags = MASKCOVERSMOUTH | MASKCOVERSEYES | MASKINTERNALS
+ flags = MASKINTERNALS
throw_range = 5
tint = 3
+ flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index 753d2bd2d6c..4bca8132157 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -14,6 +14,7 @@
//Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
var/locked = 0
+ var/syndiemmi = 0 //Whether or not this is a Syndicate MMI
var/mob/living/carbon/brain/brainmob = null //The current occupant.
var/mob/living/silicon/robot = null //Appears unused.
var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm.
@@ -182,3 +183,8 @@
else
user << "The MMI indicates the brain is active."
+
+/obj/item/device/mmi/syndie
+ name = "Syndicate Man-Machine Interface"
+ desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores."
+ syndiemmi = 1
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm
index ed151132066..7a233cea9c2 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/carbon/brain/brain_item.dm
@@ -51,7 +51,7 @@
return ..()
var/mob/living/carbon/human/H = M
- if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES)))
+ if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES)))
user << "You're going to need to remove their head cover first!"
return
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 73f8aedc7bc..937d13e4ec4 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -38,9 +38,10 @@
/mob/living/carbon/relaymove(var/mob/user, direction)
if(user in src.stomach_contents)
if(prob(40))
- audible_message("You hear something rumbling inside [src]'s stomach...", \
- "You hear something rumbling.", 4,\
- "Something is rumbling inside your stomach!")
+ if(prob(25))
+ audible_message("You hear something rumbling inside [src]'s stomach...", \
+ "You hear something rumbling.", 4,\
+ "Something is rumbling inside your stomach!")
var/obj/item/I = user.get_active_hand()
if(I && I.force)
var/d = rand(round(I.force / 4), I.force)
@@ -407,7 +408,7 @@ var/const/GALOSHES_DONT_HELP = 8
last_special = world.time + CLICK_CD_BREAKOUT
visible_message("[src] attempts to unbuckle themself!", \
"You attempt to unbuckle yourself... (This will take around one minute and you need to stay still.)")
- if(do_after(src, 600, needhand = 0))
+ if(do_after(src, 600, needhand = 0, target = src))
if(!buckled)
return
buckled.user_unbuckle_mob(src,src)
@@ -450,7 +451,7 @@ var/const/GALOSHES_DONT_HELP = 8
if(!cuff_break)
visible_message("[src] attempts to remove [I]!")
src << "You attempt to remove [I]... (This will take around [displaytime] minutes and you need to stand still.)"
- if(do_after(src, breakouttime, 10, 0))
+ if(do_after(src, breakouttime, 10, 0, target = src))
if(I.loc != src || buckled)
return
visible_message("[src] manages to remove [I]!")
@@ -476,7 +477,7 @@ var/const/GALOSHES_DONT_HELP = 8
breakouttime = 50
visible_message("[src] is trying to break [I]!")
src << "You attempt to break [I]... (This will take around 5 seconds and you need to stand still.)"
- if(do_after(src, breakouttime, needhand = 0))
+ if(do_after(src, breakouttime, needhand = 0, target = src))
if(!I.loc || buckled)
return
visible_message("[src] manages to break [I]!")
@@ -494,7 +495,7 @@ var/const/GALOSHES_DONT_HELP = 8
src << "You fail to break [I]!"
/mob/living/carbon/proc/is_mouth_covered(head_only = 0, mask_only = 0)
- if( (!mask_only && head && (head.flags & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags & MASKCOVERSMOUTH)) )
+ if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
return 1
/mob/living/carbon/get_standard_pixel_y_offset(lying = 0)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 16be6a0f49e..b8024eed08d 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -116,11 +116,9 @@
gib()
return
else
+ shred_clothing(1,150)
var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
throw_at(target, 200, 4)
- //return
-// var/atom/target = get_edge_target_turf(user, get_dir(src, get_step_away(user, src)))
- //user.throw_at(target, 200, 4)
if (2.0)
b_loss += 60
@@ -130,6 +128,9 @@
if (prob(getarmor(null, "bomb")))
b_loss = b_loss/1.5
f_loss = f_loss/1.5
+ shred_clothing(1,25)
+ else
+ shred_clothing(1,50)
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
adjustEarDamage(30, 120)
@@ -140,6 +141,8 @@
b_loss += 30
if (prob(getarmor(null, "bomb")))
b_loss = b_loss/2
+ else
+ shred_clothing(1,10)
if (!istype(ears, /obj/item/clothing/ears/earmuffs))
adjustEarDamage(15,60)
if (prob(50))
@@ -284,7 +287,7 @@
return
var/time_taken = I.embedded_unsafe_removal_time*I.w_class
usr.visible_message("[usr] attempts to remove [I] from their [L.getDisplayName()].","You attempt to remove [I] from your [L.getDisplayName()]... (It will take [time_taken/10] seconds.)")
- if(do_after(usr, time_taken, needhand = 1))
+ if(do_after(usr, time_taken, needhand = 1, target = src))
L.embedded_objects -= I
L.take_damage(I.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus.
I.loc = get_turf(src)
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
index 7c0773877c1..48250417654 100644
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ b/code/modules/mob/living/carbon/human/human_damage.dm
@@ -10,9 +10,10 @@
total_brute += O.brute_dam
total_burn += O.burn_dam
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
- //TODO: fix husking
if( ((maxHealth - total_burn) < config.health_threshold_dead) && stat == DEAD )
ChangeToHusk()
+ if(on_fire)
+ shred_clothing()
med_hud_set_health()
med_hud_set_status()
return
@@ -50,7 +51,7 @@
var/loose = 40
if(stat || (status_flags & FAKEDEATH))
multiplier = 2
- if(H.flags & (HEADCOVERSEYES | HEADCOVERSMOUTH) || H.flags_inv & (HIDEEYES | HIDEFACE))
+ if(H.flags_cover & (HEADCOVERSEYES | HEADCOVERSMOUTH) || H.flags_inv & (HIDEEYES | HIDEFACE))
loose = 0
return loose * multiplier
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 523c683b61e..b231ef67bec 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -108,7 +108,6 @@ emp_act
"The reactive teleport system flings [src] clear of [attack_text]!")
var/list/turfs = new/list()
for(var/turf/T in orange(6, src))
- if(istype(T,/turf/space)) continue
if(T.density) continue
if(T.x>world.maxx-6 || T.x<6) continue
if(T.y>world.maxy-6 || T.y<6) continue
@@ -118,7 +117,7 @@ emp_act
if(!isturf(picked)) return
if(buckled)
buckled.unbuckle_mob()
- src.loc = picked
+ forceMove(picked)
return 1
return 0
@@ -189,7 +188,7 @@ emp_act
visible_message("[src] has been knocked unconscious!", \
"[src] has been knocked unconscious!")
apply_effect(20, PARALYZE, armor)
- if(prob(I.force + ((100 - src.health)/2)) && src != user && I.damtype == BRUTE)
+ if(prob(I.force + min(100,100 - src.health)) && src != user && I.damtype == BRUTE)
ticker.mode.remove_revolutionary(mind)
ticker.mode.remove_gangster(mind, exclude_bosses=1)
if(bloody) //Apply blood
@@ -239,6 +238,9 @@ emp_act
/mob/living/carbon/human/acid_act(var/acidpwr, var/toxpwr, var/acid_volume)
var/list/damaged = list()
var/list/inventory_items_to_kill = list()
+ var/acidity = min(acidpwr*acid_volume/200, toxpwr)
+ var/acid_volume_left = acid_volume
+ var/acid_decay = 100/acidpwr // how much volume we lose per item we try to melt. 5 for fluoro, 10 for sulphuric
//HEAD//
var/obj/item/clothing/head_clothes = null
@@ -250,7 +252,8 @@ emp_act
head_clothes = head
if(head_clothes)
if(!head_clothes.unacidable)
- head_clothes.acid_act(acidpwr)
+ head_clothes.acid_act(acidpwr, acid_volume_left)
+ acid_volume_left = max(acid_volume_left - acid_decay, 0) //We remove some of the acid volume.
update_inv_glasses()
update_inv_wear_mask()
update_inv_head()
@@ -271,7 +274,8 @@ emp_act
chest_clothes = wear_suit
if(chest_clothes)
if(!chest_clothes.unacidable)
- chest_clothes.acid_act(acidpwr)
+ chest_clothes.acid_act(acidpwr, acid_volume_left)
+ acid_volume_left = max(acid_volume_left - acid_decay, 0)
update_inv_w_uniform()
update_inv_wear_suit()
else
@@ -300,7 +304,8 @@ emp_act
arm_clothes = wear_suit
if(arm_clothes)
if(!arm_clothes.unacidable)
- arm_clothes.acid_act(acidpwr)
+ arm_clothes.acid_act(acidpwr, acid_volume_left)
+ acid_volume_left = max(acid_volume_left - acid_decay, 0)
update_inv_gloves()
update_inv_w_uniform()
update_inv_wear_suit()
@@ -325,7 +330,8 @@ emp_act
leg_clothes = wear_suit
if(leg_clothes)
if(!leg_clothes.unacidable)
- leg_clothes.acid_act(acidpwr)
+ leg_clothes.acid_act(acidpwr, acid_volume_left)
+ acid_volume_left = max(acid_volume_left - acid_decay, 0)
update_inv_shoes()
update_inv_w_uniform()
update_inv_wear_suit()
@@ -342,11 +348,11 @@ emp_act
//DAMAGE//
for(var/obj/item/organ/limb/affecting in damaged)
- affecting.take_damage(2*toxpwr, toxpwr)
+ affecting.take_damage(acidity, 2*acidity)
if(affecting.name == "head")
- affecting.take_damage(2*toxpwr, toxpwr)
- if(prob(2*acidpwr)) //Applies disfigurement
+ if(prob(min(acidpwr*acid_volume/10, 90))) //Applies disfigurement
+ affecting.take_damage(acidity, 2*acidity)
emote("scream")
facial_hair_style = "Shaved"
hair_style = "Bald"
@@ -367,7 +373,8 @@ emp_act
inventory_items_to_kill += l_hand
for(var/obj/item/I in inventory_items_to_kill)
- I.acid_act(acidpwr)
+ I.acid_act(acidpwr, acid_volume_left)
+ acid_volume_left = max(acid_volume_left - acid_decay, 0)
/mob/living/carbon/human/grabbedby(mob/living/user)
if(w_uniform)
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 8d08b29ecb2..e163fb158e0 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -139,10 +139,30 @@
/mob/living/carbon/human/can_track(mob/living/user)
if(wear_id && istype(wear_id.GetID(), /obj/item/weapon/card/id/syndicate))
- return 0
+ return 0
if(istype(head, /obj/item/clothing/head))
var/obj/item/clothing/head/hat = head
if(hat.blockTracking)
return 0
-
+
return ..()
+
+/mob/living/carbon/human/get_permeability_protection()
+ var/list/prot = list("hands"=0, "chest"=0, "groin"=0, "legs"=0, "feet"=0, "arms"=0, "head"=0)
+ for(var/obj/item/I in get_equipped_items())
+ if(I.body_parts_covered & HANDS)
+ prot["hands"] = max(1 - I.permeability_coefficient, prot["hands"])
+ if(I.body_parts_covered & CHEST)
+ prot["chest"] = max(1 - I.permeability_coefficient, prot["chest"])
+ if(I.body_parts_covered & GROIN)
+ prot["groin"] = max(1 - I.permeability_coefficient, prot["groin"])
+ if(I.body_parts_covered & LEGS)
+ prot["legs"] = max(1 - I.permeability_coefficient, prot["legs"])
+ if(I.body_parts_covered & FEET)
+ prot["feet"] = max(1 - I.permeability_coefficient, prot["feet"])
+ if(I.body_parts_covered & ARMS)
+ prot["arms"] = max(1 - I.permeability_coefficient, prot["arms"])
+ if(I.body_parts_covered & HEAD)
+ prot["head"] = max(1 - I.permeability_coefficient, prot["head"])
+ var/protection = (prot["head"] + prot["arms"] + prot["feet"] + prot["legs"] + prot["groin"] + prot["chest"] + prot["hands"])/7
+ return protection
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 1a4cd41351c..4bd3d94f560 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -390,3 +390,85 @@
src << "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!"
return
+//Cycles through all clothing slots and tests them for destruction
+/mob/living/carbon/human/proc/shred_clothing(var/bomb,var/shock)
+ var/covered_parts //The body parts that are protected by exterior clothing/armor
+ var/head_absorbed = 0 //How much of the shock the headgear absorbs when it is shredded. -1=it survives
+ var/suit_absorbed = 0 //How much of the shock the exosuit absorbs when it is shredded. -1=it survives
+
+ //Backpacks can never be protected but are annoying as fuck to lose, so they get a lower chance to be shredded
+ if(back)
+ back.shred(bomb,shock-30,src)
+
+ if(head)
+ covered_parts |= head.flags_inv
+ head_absorbed = head.shred(bomb,shock,src)
+ if(wear_mask)
+ var/absorbed = ((covered_parts & HIDEMASK) ? head_absorbed : 0) //Check if clothing covering this part absorbed any of the shock
+ if(!(absorbed < 0))
+ //Masks can be used to shield other parts, but are simplified to simply add their absorbsion to the head armor if it covers the face
+ var/mask_absorbed = wear_mask.shred(bomb,shock-absorbed,src)
+ if(wear_mask.flags_inv & HIDEFACE)
+ covered_parts |= wear_mask.flags_inv
+ if(mask_absorbed < 0) //If the mask didn't get shredded, everything else on the head is protected
+ head_absorbed = -1
+ else
+ head_absorbed += mask_absorbed
+ if(ears)
+ var/absorbed = ((covered_parts & HIDEEARS) ? head_absorbed : 0)
+ if(!(absorbed < 0))
+ ears.shred(bomb,shock-absorbed,src)
+ if(glasses)
+ var/absorbed = ((covered_parts & HIDEEYES) ? head_absorbed : 0)
+ if(!(absorbed < 0))
+ glasses.shred(bomb,shock-absorbed,src)
+
+ if(wear_suit)
+ covered_parts |= wear_suit.flags_inv
+ suit_absorbed = wear_suit.shred(bomb,shock,src)
+ if(gloves)
+ var/absorbed = ((covered_parts & HIDEGLOVES) ? suit_absorbed : 0)
+ if(!(absorbed < 0))
+ gloves.shred(bomb,shock-absorbed,src)
+ if(shoes)
+ var/absorbed = ((covered_parts & HIDESHOES) ? suit_absorbed : 0)
+ if(!(absorbed < 0))
+ shoes.shred(bomb,shock-absorbed,src)
+ if(w_uniform)
+ var/absorbed = ((covered_parts & HIDEJUMPSUIT) ? suit_absorbed : 0)
+ if(!(absorbed < 0))
+ w_uniform.shred(bomb,shock-absorbed,src)
+
+/obj/item/proc/shred(var/bomb,var/shock,var/mob/living/carbon/human/Human)
+ if(flags & ABSTRACT)
+ return -1
+
+ var/shredded
+
+ if(!bomb)
+ if(burn_state != -1)
+ shredded = 1 //No heat protection, it burns
+ else
+ shredded = -1 //Heat protection = Fireproof
+
+ else if(shock > 0)
+ if(prob(min(90,max(0,shock))))
+ shredded = armor["bomb"] + 10 //It gets shredded, but it also absorbs the shock the clothes underneath would recieve by this amount
+ else
+ shredded = -1 //It survives explosion
+
+ if(shredded > 0)
+ if(Human) //Unequip if equipped
+ Human.unEquip(src)
+
+ if(bomb)
+ for(var/obj/item/Item in contents) //Empty out the contents
+ Item.loc = src.loc
+ spawn(1) //so the shreds aren't instantly deleted by the explosion
+ var/obj/effect/decal/cleanable/shreds/Shreds = new(loc)
+ Shreds.desc = "The sad remains of what used to be [src.name]."
+ qdel(src)
+ else
+ burn()
+
+ return shredded
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 34a081d802a..df7579f5190 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -738,7 +738,7 @@
if(P.allow_thrust(0.01, H))
hasjetpack = 1
- mspeed = 1 - hasjetpack
+ mspeed = -1 - hasjetpack
if(grav || !hasjetpack)
var/health_deficiency = (100 - H.health + H.staminaloss)
@@ -763,11 +763,12 @@
mspeed += speedmod
- if(H.status_flags & GOTTAGOFAST)
- mspeed -= 1
+ if(grav)
+ if(H.status_flags & GOTTAGOFAST)
+ mspeed -= 1
- if(H.status_flags & GOTTAGOREALLYFAST)
- mspeed -= 2
+ if(H.status_flags & GOTTAGOREALLYFAST)
+ mspeed -= 2
return mspeed
@@ -924,7 +925,7 @@
return 0
var/armor = H.run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened a hit to your [hit_area].",I.armour_penetration)
- armor = max(90,armor) //cap damage reduction at 90%
+ armor = min(90,armor) //cap damage reduction at 90%
var/Iforce = I.force //to avoid runtimes on the forcesay checks at the bottom. Some items might delete themselves if you drop them. (stunning yourself, ninja swords)
apply_damage(I.force, I.damtype, affecting, armor, H)
@@ -1101,13 +1102,13 @@
// Handle chem smoke effect -- Doohl
if(!H.has_smoke_protection())
- for(var/obj/effect/effect/chem_smoke/smoke in view(1, H))
- if(smoke.reagents.total_volume)
- smoke.reagents.reaction(H, INGEST)
- spawn(5)
- if(smoke)
- smoke.reagents.copy_to(H, 10) // I dunno, maybe the reagents enter the blood stream through the lungs?
- break // If they breathe in the nasty stuff once, no need to continue checking
+ for(var/obj/effect/effect/smoke/chem/S in range(1, H))
+ if(S.reagents.total_volume && S.lifetime)
+ var/fraction = 1/S.max_lifetime
+ S.reagents.reaction(H,INGEST, fraction)
+ var/amount = round(S.reagents.total_volume*fraction,0.1)
+ S.reagents.copy_to(H, amount)
+ S.lifetime--
else //Still give containing object the chance to interact
if(istype(H.loc, /obj/))
diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm
index fd4573900c7..f42c367d4bb 100644
--- a/code/modules/mob/living/carbon/human/whisper.dm
+++ b/code/modules/mob/living/carbon/human/whisper.dm
@@ -1,6 +1,8 @@
/mob/living/carbon/human/whisper(message as text)
if(!IsVocal())
return
+ if(!message)
+ return
if(say_disabled) //This is here to try to identify lag problems
usr << "Speech is currently admin-disabled."
@@ -9,18 +11,18 @@
if(stat == DEAD)
return
-
+
message = trim(html_encode(message))
if(!can_speak(message))
return
-
- message = "[message]"
+
+ message = "[message]"
log_whisper("[src.name]/[src.key] : [message]")
if (src.client)
if (src.client.prefs.muted & MUTE_IC)
src << "You cannot whisper (muted)."
- return
+ return
log_whisper("[src.name]/[src.key] : [message]")
@@ -66,13 +68,17 @@
var/spans = list(SPAN_ITALICS)
rendered = "[GetVoice()][alt_name] [whispers], \"[attach_spans(message, spans)]\""
- for(var/mob/M in listening)
- M.Hear(rendered, src, languages, message, , spans)
+ for(var/atom/movable/AM in listening)
+ if(istype(AM,/obj/item/device/radio))
+ continue
+ AM.Hear(rendered, src, languages, message, , spans)
message = stars(message)
rendered = "[GetVoice()][alt_name] [whispers], \"[attach_spans(message, spans)]\""
- for(var/mob/M in eavesdropping)
- M.Hear(rendered, src, languages, message, , spans)
+ for(var/atom/movable/AM in eavesdropping)
+ if(istype(AM,/obj/item/device/radio))
+ continue
+ AM.Hear(rendered, src, languages, message, , spans)
if(critical) //Dying words.
succumb(1)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 9ac7837148a..b019a52ab44 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -71,13 +71,13 @@
//Harmful gasses
if(!has_smoke_protection())
- for(var/obj/effect/effect/chem_smoke/smoke in view(1,src))
- if(smoke.reagents.total_volume)
- smoke.reagents.reaction(src,INGEST)
- spawn(5)
- if(smoke)
- smoke.reagents.copy_to(src, 10)
- break
+ for(var/obj/effect/effect/smoke/chem/S in range(1, src))
+ if(S.reagents.total_volume && S.lifetime)
+ var/fraction = 1/S.max_lifetime
+ S.reagents.reaction(src,INGEST, fraction)
+ var/amount = round(S.reagents.total_volume*fraction,0.1)
+ S.reagents.copy_to(src, amount)
+ S.lifetime--
else //Breathe from loc as obj again
if(istype(loc, /obj/))
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index a7c821c9493..394a92d9437 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -255,7 +255,7 @@
src << "Your mask protects you from the acid."
return
- take_organ_damage(min(6*toxpwr, acid_volume * toxpwr))
+ take_organ_damage(min(6*toxpwr, acid_volume * acidpwr/10))
/mob/living/carbon/monkey/help_shake_act(mob/living/carbon/M)
if(health < 0 && ishuman(M))
@@ -263,3 +263,12 @@
H.do_cpr(src)
else
..()
+
+/mob/living/carbon/monkey/get_permeability_protection()
+ var/protection = 0
+ if(head)
+ protection = 1 - head.permeability_coefficient
+ if(wear_mask)
+ protection = max(1 - wear_mask.permeability_coefficient, protection)
+ protection = protection/7 //the rest of the body isn't covered.
+ return protection
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm
index 9f218605c01..0d8a39ee9ef 100644
--- a/code/modules/mob/living/carbon/say.dm
+++ b/code/modules/mob/living/carbon/say.dm
@@ -5,7 +5,7 @@
return message
-/mob/living/carbon/can_speak_basic(message)
+/mob/living/carbon/can_speak_vocal(message)
if(silent)
return 0
return ..()
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index d79896f82dd..08ffb07c7d9 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -3,6 +3,9 @@
//Intended to be called by a higher up emote proc if the requested emote isn't in the custom emotes.
/mob/living/emote(var/act, var/m_type=1, var/message = null)
+ if(stat)
+ return
+
var/param = null
if (findtext(act, "-", 1, null))
@@ -150,8 +153,6 @@
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
- if (stat)
- return
if(!(message))
return
else
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 5beeeb3a847..151b8978dc8 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -62,6 +62,7 @@
return
/mob/living/proc/handle_mutations_and_radiation()
+ radiation = 0 //so radiation don't accumulate in simple animals
return
/mob/living/proc/handle_chemicals_in_body()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index bc689b62098..000893f5165 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -849,7 +849,7 @@ Sorry Giacom. Please don't be mad :(
return 0
if(T.z >= ZLEVEL_SPACEMAX)
return 0
- if(src == user)
+ if(user != null && src == user)
return 0
if(invisibility || alpha == 0)//cloaked
return 0
@@ -861,3 +861,7 @@ Sorry Giacom. Please don't be mad :(
return 0
return 1
+
+//used in datum/reagents/reaction() proc
+/mob/living/proc/get_permeability_protection()
+ return 0
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 35d2a433f96..af8b231f78a 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -228,7 +228,7 @@
return 0
if (M.a_intent == "harm")
- if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags & MASKCOVERSMOUTH))
+ if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
M << "You can't bite with your mouth covered!"
return 0
M.do_attack_animation(src)
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 6509db4ac67..b48f2f21e14 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -43,4 +43,6 @@
var/list/datum/action/actions = list()
var/list/pipes_shown = list()
- var/last_played_vent
\ No newline at end of file
+ var/last_played_vent
+
+ var/smoke_delay = 0 //used to prevent spam with smoke reagent reaction on mob.
\ No newline at end of file
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index def924f9943..a0df06a9088 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -56,6 +56,8 @@ var/list/department_radio_keys = list(
":ï" = "changeling", "#ï" = "changeling", ".ï" = "changeling"
)
+var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
+
/mob/living/say(message, bubble_type,)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
@@ -63,18 +65,17 @@ var/list/department_radio_keys = list(
say_dead(message)
return
- if(stat)
- return
-
if(check_emote(message))
return
if(!can_speak_basic(message)) //Stat is seperate so I can handle whispers properly.
- src << "You find yourself unable to speak!"
return
var/message_mode = get_message_mode(message)
+ if(stat && !(message_mode in crit_allowed_modes))
+ return
+
if(message_mode == MODE_HEADSET || message_mode == MODE_ROBOT)
message = copytext(message, 2)
else if(message_mode)
@@ -86,14 +87,14 @@ var/list/department_radio_keys = list(
return
if(!can_speak_vocal(message))
- src << "You find yourself unable to speak!" //repetition intended
+ src << "You find yourself unable to speak!"
return
message = treat_message(message)
var/spans = list()
spans += get_spans()
- if(!message || message == "")
+ if(!message)
return
var/message_range = 7
@@ -163,9 +164,6 @@ var/list/department_radio_keys = list(
return 1
/mob/living/proc/can_speak_basic(message) //Check BEFORE handling of xeno and ling channels
- if(!message || message == "")
- return 0
-
if(client)
if(client.prefs.muted & MUTE_IC)
src << "You cannot speak in IC (muted)."
@@ -176,9 +174,6 @@ var/list/department_radio_keys = list(
return 1
/mob/living/proc/can_speak_vocal(message) //Check AFTER handling of xeno and ling channels
- if(!message)
- return 0
-
if(disabilities & MUTE)
return 0
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index e37ac76c526..c1030d43b39 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -483,7 +483,7 @@
else
playsound(src, 'sound/items/Ratchet.ogg', 50, 1)
user << "You start to unfasten [src]'s securing bolts..."
- if(do_after(user, 50) && !cell)
+ if(do_after(user, 50, target = src) && !cell)
user.visible_message("[user] deconstructs [src]!", "You unfasten the securing bolts, and [src] falls to pieces!")
deconstruct()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index e9bd8434232..59e6475286e 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -101,8 +101,6 @@
emag.reagents.add_reagent("facid", 250)
emag.name = "Fluacid spray"
- var/obj/item/weapon/reagent_containers/spray/S = emag
- S.banned_reagents = list()
var/datum/robot_energy_storage/gauze/gauzestore = new /datum/robot_energy_storage/gauze(src)
@@ -221,7 +219,7 @@
modules += new /obj/item/weapon/reagent_containers/dropper(src)
- var/obj/item/weapon/lighter/zippo/L = new /obj/item/weapon/lighter/zippo(src)
+ var/obj/item/weapon/lighter/L = new /obj/item/weapon/lighter(src)
L.lit = 1
modules += L
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index c73a3443b09..1462e2b52ed 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -81,7 +81,7 @@
user << "You can't shave this corgi, it's already been shaved!"
return
user.visible_message("[user] starts to shave [src] using \the [O].", "You start to shave [src] using \the [O]...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
user.visible_message("[user] shaves [src]'s hair using \the [O].")
playsound(loc, 'sound/items/Welder2.ogg', 20, 1)
shaved = 1
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index 930dff33f2e..d4b664f4536 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -42,7 +42,7 @@
if(istype(loc, /mob/living))
var/mob/living/L = loc
L.show_message("[drone] is trying to escape!")
- if(!do_after(L, 50) || loc != L)
+ if(!do_after(L, 50, target = L) || loc != L)
return
L.unEquip(src)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index 61ffbe0eecf..98253d6b5d5 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -33,7 +33,7 @@
D << "You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]."
return
D.visible_message("[D] begins to reactivate [src].", "You begin to reactivate [src]...")
- if(do_after(user,30,needhand = 1))
+ if(do_after(user,30,needhand = 1, target = src))
health = health_repair_max
stat = CONSCIOUS
icon_state = icon_living
@@ -49,7 +49,7 @@
if("Cannibalize")
if(D.health < D.maxHealth)
D.visible_message("[D] begins to cannibalize parts from [src].", "You begin to cannibalize parts from [src]...")
- if(do_after(D, 60,5,0))
+ if(do_after(D, 60,5,0, target = src))
D.visible_message("[D] repairs itself using [src]'s remains!", "You repair yourself using [src]'s remains.")
D.adjustBruteLoss(-src.maxHealth)
new /obj/effect/decal/cleanable/oil/streak(get_turf(src))
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
index b4616ae9fb7..850f307f63b 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -264,7 +264,7 @@
/obj/item/asteroid/hivelord_core
name = "hivelord remains"
- desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating."
+ desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly."
icon = 'icons/obj/food/food.dmi'
icon_state = "boiledrorocore"
var/inert = 0
@@ -285,10 +285,9 @@
user << "[src] are useless on the dead."
return
if(H != user)
- H.visible_message("[user] forces [H] to eat [src]... they quickly regenerate all injuries!")
+ H.visible_message("[user] forces [H] to apply [src]... they quickly regenerate all injuries!")
else
- user << "You chomp into [src], barely managing to hold it down, but feel amazingly refreshed in mere moments."
- playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
+ user << "You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments."
H.revive()
qdel(src)
..()
diff --git a/code/modules/mob/living/simple_animal/revenant/revenant.dm b/code/modules/mob/living/simple_animal/revenant/revenant.dm
index c81bb72ee31..dc1137e62d5 100644
--- a/code/modules/mob/living/simple_animal/revenant/revenant.dm
+++ b/code/modules/mob/living/simple_animal/revenant/revenant.dm
@@ -18,6 +18,7 @@
response_help = "passes through"
response_disarm = "swings at"
response_harm = "punches"
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
maxbodytemp = INFINITY
harm_intent_damage = 5
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index f7f81ef7c41..7b9348d0108 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -201,6 +201,10 @@
if(!atmos_suitable)
adjustBruteLoss(unsuitable_atmos_damage)
+ else
+ if(atmos_requirements["min_oxy"] || atmos_requirements["min_tox"] || atmos_requirements["min_n2"] || atmos_requirements["min_co2"])
+ adjustBruteLoss(unsuitable_atmos_damage)
+
handle_temperature_damage()
/mob/living/simple_animal/proc/handle_temperature_damage()
@@ -274,7 +278,7 @@
visible_message("[M] [response_harm] [src]!")
playsound(loc, "punch", 25, 1, -1)
attack_threshold_check(harm_intent_damage)
- add_logs(M, src, "attacked", admin=0)
+ add_logs(M, src, "attacked", admin=1)
updatehealth()
return 1
@@ -297,13 +301,13 @@
playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
visible_message("[M] [response_disarm] [name]!", \
"[M] [response_disarm] [name]!")
- add_logs(M, src, "disarmed", admin=0)
+ add_logs(M, src, "disarmed", admin=1)
else
var/damage = rand(15, 30)
visible_message("[M] has slashed at [src]!", \
"[M] has slashed at [src]!")
playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- add_logs(M, src, "attacked", admin=0)
+ add_logs(M, src, "attacked", admin=1)
attack_threshold_check(damage)
return 1
diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
index 267af8c2dd7..61f19d51552 100644
--- a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
+++ b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
@@ -145,6 +145,7 @@
var/canmove = 1
density = 0
anchored = 1
+ invisibility = 60
obj/effect/dummy/slaughter/relaymove(var/mob/user, direction)
if (!src.canmove || !direction) return
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index e2b541d9c53..a2da3fb63d6 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -182,7 +182,9 @@
var/new_powerlevel = round(powerlevel / 4)
for(var/i=1,i<=4,i++)
var/mob/living/simple_animal/slime/M = new /mob/living/simple_animal/slime/(loc)
- if(prob(mutation_chance))
+ if(mutation_chance >= 100)
+ M.colour = "rainbow"
+ else if(prob(mutation_chance))
M.colour = slime_mutation[rand(1,4)]
else
M.colour = colour
diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm
index 9165e233d1b..5df785e016c 100644
--- a/code/modules/mob/living/ventcrawling.dm
+++ b/code/modules/mob/living/ventcrawling.dm
@@ -37,7 +37,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
if(vent_found.parent && (vent_found.parent.members.len || vent_found.parent.other_atmosmch))
visible_message("[src] begins climbing into the ventilation system..." ,"You begin climbing into the ventilation system...")
- if(!do_after(src, 25))
+ if(!do_after(src, 25, target = vent_found))
return
if(!client)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 416fe4d1170..1ff60cfeffb 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -159,8 +159,8 @@ var/next_mob_id = 0
var/range = 7
if(hearing_distance)
range = hearing_distance
- var/msg = message
for(var/mob/M in get_hearers_in_view(range, src))
+ var/msg = message
if(self_message && M==src)
msg = self_message
M.show_message( msg, 2, deaf_message, 1)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index c9883f02afe..265a428ba71 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -100,8 +100,6 @@
var/in_throw_mode = 0
- var/coughedtime = null
-
var/music_lastplayed = "null"
var/job = null//Living
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
index 45f84087221..fa3a9bb4bbc 100644
--- a/code/modules/mob/mob_grab.dm
+++ b/code/modules/mob/mob_grab.dm
@@ -158,7 +158,7 @@
assailant.visible_message("[assailant] starts to tighten \his grip on [affecting]'s neck!")
hud.icon_state = "disarm/kill1"
state = GRAB_UPGRADING
- if(do_after(assailant, UPGRADE_KILL_TIMER))
+ if(do_after(assailant, UPGRADE_KILL_TIMER, target = affecting))
if(state == GRAB_KILL)
return
if(!affecting)
@@ -207,9 +207,9 @@
var/mob/living/carbon/attacker = user
user.visible_message("[user] is attempting to devour [affecting]!")
if(istype(user, /mob/living/carbon/alien/humanoid/hunter))
- if(!do_mob(user, affecting)||!do_after(user, 30)) return
+ if(!do_mob(user, affecting)||!do_after(user, 30, target = affecting)) return
else
- if(!do_mob(user, affecting)||!do_after(user, 100)) return
+ if(!do_mob(user, affecting)||!do_after(user, 100, target = affecting)) return
user.visible_message("[user] devours [affecting]!")
affecting.loc = user
attacker.stomach_contents.Add(affecting)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index a0106cfcc02..f80afc9d4f8 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -389,4 +389,4 @@
return
/mob/proc/update_gravity()
- return
+ return
\ No newline at end of file
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
index d6dc568105f..94740bd0e1e 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
@@ -18,7 +18,7 @@
spawn(30)//Slight delay so the enemy does not immedietly know the ability was used. Due to lag, this often came before waking up.
H.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"))
spawn(70)
- reagents.reaction(H, 2)
+ reagents.reaction(H, INGEST)
reagents.trans_id_to(H, "radium", a_transfer)
H << "You are beginning to feel the after-effect of the injection."
a_boost--
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm
index aef3d012dd8..c89a3b11f92 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_smoke.dm
@@ -9,7 +9,7 @@
if(!ninjacost(0,N_SMOKE_BOMB))
var/mob/living/carbon/human/H = affecting
- var/datum/effect/effect/system/bad_smoke_spread/smoke = new /datum/effect/effect/system/bad_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/bad/smoke = new
smoke.set_up(10, 0, H.loc)
smoke.start()
playsound(H.loc, 'sound/effects/bamf.ogg', 50, 2)
diff --git a/code/modules/ninja/suit/ninjaDrainAct.dm b/code/modules/ninja/suit/ninjaDrainAct.dm
index 71f729da249..bea7284744c 100644
--- a/code/modules/ninja/suit/ninjaDrainAct.dm
+++ b/code/modules/ninja/suit/ninjaDrainAct.dm
@@ -41,7 +41,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
drain = S.cell.maxcharge - S.cell.charge
maxcapacity = 1//Reached maximum battery capacity.
- if (do_after(H,10))
+ if (do_after(H,10, target = src))
spark_system.start()
playsound(loc, "sparks", 50, 1)
cell.charge -= drain
@@ -84,7 +84,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
drain = S.cell.maxcharge - S.cell.charge
maxcapacity = 1
- if (do_after(H,10))
+ if (do_after(H,10, target = src))
spark_system.start()
playsound(loc, "sparks", 50, 1)
charge -= drain
@@ -103,7 +103,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
. = 0
if(charge)
- if(G.candrain && do_after(H,30))
+ if(G.candrain && do_after(H,30, target = src))
. = charge
if(S.cell.charge + charge > S.cell.maxcharge)
S.cell.charge = S.cell.maxcharge
@@ -130,7 +130,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
if(files && files.known_tech.len)
for(var/datum/tech/current_data in S.stored_research)
H << "Checking \the [current_data.name] database."
- if(do_after(H, S.s_delay) && G.candrain && src)
+ if(do_after(H, S.s_delay, target = src) && G.candrain && src)
for(var/datum/tech/analyzing_data in files.known_tech)
if(current_data.id == analyzing_data.id)
if(analyzing_data.level > current_data.level)
@@ -161,7 +161,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
if(files && files.known_tech.len)
for(var/datum/tech/current_data in S.stored_research)
H << "Checking \the [current_data.name] database."
- if(do_after(H, S.s_delay) && G.candrain && src)
+ if(do_after(H, S.s_delay, target = src) && G.candrain && src)
for(var/datum/tech/analyzing_data in files.known_tech)
if(current_data.id == analyzing_data.id)
if(analyzing_data.level > current_data.level)
@@ -189,7 +189,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
while(G.candrain && !maxcapacity && src)
drain = (round((rand(G.mindrain, G.maxdrain))/2))
var/drained = 0
- if(PN && do_after(H,10))
+ if(PN && do_after(H,10, target = src))
drained = min(drain, PN.avail)
PN.load += drained
if(drained < drain)//if no power on net, drain apcs
@@ -229,7 +229,7 @@ They *could* go in their appropriate files, but this is supposed to be modular
if(S.cell.charge + drain > S.cell.maxcharge)
drain = S.cell.maxcharge - S.cell.charge
maxcapacity = 1
- if (do_after(H,10))
+ if (do_after(H,10, target = src))
spark_system.start()
playsound(loc, "sparks", 50, 1)
cell.use(drain)
diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm
index a2683d39d8c..775143b8feb 100644
--- a/code/modules/ninja/suit/suit_attackby.dm
+++ b/code/modules/ninja/suit/suit_attackby.dm
@@ -23,7 +23,7 @@
var/obj/item/weapon/stock_parts/cell/CELL = I
if(CELL.maxcharge > cell.maxcharge && n_gloves && n_gloves.candrain)
U << "Higher maximum capacity detected.\nUpgrading..."
- if (n_gloves && n_gloves.candrain && do_after(U,s_delay))
+ if (n_gloves && n_gloves.candrain && do_after(U,s_delay, target = src))
U.drop_item()
CELL.loc = src
CELL.charge = min(CELL.charge+cell.charge, CELL.maxcharge)
@@ -43,7 +43,7 @@
var/obj/item/weapon/disk/tech_disk/TD = I
if(TD.stored)//If it has something on it.
U << "Research information detected, processing..."
- if(do_after(U,s_delay))
+ if(do_after(U,s_delay, target = src))
for(var/datum/tech/current_data in stored_research)
if(current_data.id==TD.stored.id)
if(current_data.levelPicking up a burning paper seems awfully stupid."
- return //Doesn't make any sense to pick up a burning paper
- else //Probably isn't necessary but it's safer
- ..()
-
-
/obj/item/weapon/paper/attack_ai(mob/living/silicon/ai/user)
var/dist
if(istype(user) && user.current) //is AI
@@ -278,7 +273,7 @@
/obj/item/weapon/paper/attackby(obj/item/weapon/P, mob/living/carbon/human/user, params)
..()
- if(burning)
+ if(burn_state == 1)
return
if(is_blind(user))
@@ -325,27 +320,21 @@
user.unEquip(src)
user.visible_message("[user] lights [src] ablaze with [P]!", "You light [src] on fire!")
- burn(0, 100)
+ fire_act()
add_fingerprint(user)
/obj/item/weapon/paper/fire_act()
- burn(1, 50)
-
-/obj/item/weapon/paper/proc/burn(var/showmsg, var/burntime)
- if (burning)
- return
- if(showmsg)
- src.visible_message("[src] catches on fire.")
- burning = 1
+ ..(0)
icon_state = "paper_onfire"
info = "[stars(info)]"
- spawn(burntime) //7 seconds
- src.visible_message("[src] burns away, leaving behind a pile of ashes.")
- new /obj/effect/decal/cleanable/ash(src.loc)
- qdel(src)
+
+
+/obj/item/weapon/paper/extinguish()
+ ..()
+ update_icon()
/*
* Premade paper
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index dd672a6d11c..568680b5d45 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -8,9 +8,20 @@
throw_speed = 3
throw_range = 7
pressure_resistance = 8
+ burn_state = 0 //Burnable
var/amount = 30 //How much paper is in the bin.
var/list/papers = new/list() //List of papers put in the bin for reference.
+/obj/item/weapon/paper_bin/fire_act()
+ if(!amount)
+ return
+ ..()
+
+/obj/item/weapon/paper_bin/burn()
+ amount = 0
+ extinguish()
+ update_icon()
+ return
/obj/item/weapon/paper_bin/MouseDrop(atom/over_object)
var/mob/M = usr
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index d5efcbe8dd4..5ec959df34f 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -44,13 +44,14 @@
colour = "white"
-/obj/item/weapon/pen/attack(mob/living/M, mob/user)
+/obj/item/weapon/pen/attack(mob/living/M, mob/user,var/stealth)
if(!istype(M))
return
if(M.can_inject(user, 1))
user << "You stab [M] with the pen."
- M << "You feel a tiny prick!"
+ if(!stealth)
+ M << "You feel a tiny prick!"
. = 1
add_logs(user, M, "stabbed", object="[name]")
@@ -68,59 +69,12 @@
if(..())
if(reagents.total_volume)
if(M.reagents)
- reagents.trans_to(M, 55)
+ reagents.trans_to(M, reagents.total_volume)
/obj/item/weapon/pen/sleepy/New()
- create_reagents(55)
- reagents.add_reagent("morphine", 30)
+ create_reagents(45)
+ reagents.add_reagent("morphine", 20)
reagents.add_reagent("mutetoxin", 15)
reagents.add_reagent("tirizene", 10)
..()
-
-/*
- * Gang Boss Pens
- */
-/obj/item/weapon/pen/gang
- origin_tech = "materials=2;syndicate=5"
- var/cooldown
-
-/obj/item/weapon/pen/gang/attack(mob/living/M, mob/user)
- if(!istype(M)) return
- if(..())
- if(ishuman(M) && ishuman(user) && M.stat != DEAD)
- if(user.mind && ((user.mind in ticker.mode.A_bosses) || (user.mind in ticker.mode.B_bosses)))
- if(cooldown)
- user << "[src] needs more time to recharge before it can be used."
- return
- if(M.client)
- M.mind_initialize() //give them a mind datum if they don't have one.
- if(user.mind in ticker.mode.A_bosses)
- var/recruitable = ticker.mode.add_gangster(M.mind,"A")
- switch(recruitable)
- if(2)
- M.Paralyse(5)
- cooldown(max(0,ticker.mode.B_gang.len - ticker.mode.A_gang.len))
- if(1)
- user << "This mind has already been recruited by another gang!"
- else
- user << "This mind is resistant to recruitment!"
- else if(user.mind in ticker.mode.B_bosses)
- var/recruitable = ticker.mode.add_gangster(M.mind,"B")
- switch(recruitable)
- if(2)
- M.Paralyse(5)
- cooldown(max(0,ticker.mode.A_gang.len - ticker.mode.B_gang.len))
- if(1)
- user << "This mind has already been recruited by another gang!"
- else
- user << "This mind is resistant to recruitment!"
-
-/obj/item/weapon/pen/gang/proc/cooldown(modifier)
- cooldown = 1
- icon_state = "pen_blink"
- spawn(max(50,1200-(modifier*100)))
- cooldown = 0
- icon_state = "pen"
- var/mob/M = get(src, /mob)
- M << "\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly."
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 35e87edada7..ee16c94ee28 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -262,7 +262,7 @@
return
playsound(loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "You start [anchored ? "unwrenching" : "wrenching"] [src]..."
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if(gc_destroyed)
return
user << "You [anchored ? "unwrench" : "wrench"] [src]."
@@ -309,7 +309,7 @@
else
user.visible_message("[user] starts putting [target] onto the photocopier!", "You start putting [target] onto the photocopier...")
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if(!target || target.gc_destroyed || gc_destroyed || !Adjacent(target)) //check if the photocopier/target still exists.
return
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 0832ab226f3..d8312036260 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -17,7 +17,7 @@
icon_state = "film"
item_state = "electropack"
w_class = 1.0
-
+ burn_state = 0 //Burnable
/*
* Photo
@@ -28,6 +28,8 @@
icon_state = "photo"
item_state = "paper"
w_class = 1.0
+ burn_state = 0 //Burnable
+ burntime = 5
var/icon/img //Big photo image
var/scribble //Scribble on the back.
var/blueprints = 0 //Does it include the blueprints?
@@ -92,7 +94,7 @@
icon_state = "album"
item_state = "briefcase"
can_hold = list(/obj/item/weapon/photo)
-
+ burn_state = 0 //Burnable
/*
* Camera
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 4f9dbe520be..329346fa41b 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -112,6 +112,8 @@
/obj/machinery/power/apc/New(turf/loc, var/ndir, var/building=0)
..()
+ apcs_list += src
+
wires = new(src)
// offset 24 pixels in direction of dir
// this allows the APC to be embedded in a wall, yet still inside an area
@@ -138,6 +140,8 @@
src.update()
/obj/machinery/power/apc/Destroy()
+ apcs_list -= src
+
if(malfai && operating)
if (ticker.mode.config_tag == "malfunction")
if (src.z == ZLEVEL_STATION) //if (is_type_in_list(get_area(src), the_station_areas))
@@ -381,7 +385,7 @@
return
playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
user << "You are trying to remove the power control board..." //lpeters - fixed grammar issues
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
if (has_electronics==1)
has_electronics = 0
if ((stat & BROKEN) || malfhack)
@@ -476,7 +480,7 @@
user.visible_message("[user.name] adds cables to the APC frame.", \
"You start adding cables to the APC frame...")
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if (C.amount >= 10 && !terminal && opened && has_electronics != 2)
var/turf/T = get_turf(src)
var/obj/structure/cable/N = T.get_cable_node()
@@ -496,7 +500,7 @@
user.visible_message("[user.name] inserts the power control board into [src].", \
"You start to insert the power control board into the frame...")
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 10))
+ if(do_after(user, 10, target = src))
if(has_electronics==0)
has_electronics = 1
user << "You place the power control board inside the frame."
@@ -513,7 +517,7 @@
"You start welding the APC frame...", \
"You hear welding.")
playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
if(!src || !WT.remove_fuel(3, user)) return
if (emagged || malfhack || (stat & BROKEN) || opened==2)
new /obj/item/stack/sheet/metal(loc)
@@ -542,7 +546,7 @@
return
user.visible_message("[user.name] replaces the damaged APC frame with a new one.",\
"You begin to replace the damaged APC frame...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
user << "You replace the damaged APC frame with a new one."
qdel(W)
stat &= ~BROKEN
@@ -937,11 +941,11 @@
cell.corrupt()
src.malfhack = 1
update_icon()
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/smoke = new
smoke.set_up(3, 0, src.loc)
smoke.attach(src)
smoke.start()
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ var/datum/effect/effect/system/spark_spread/s = new
s.set_up(3, 1, src)
s.start()
visible_message("The [src.name] suddenly lets out a blast of smoke and some sparks!", \
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 3608dde2b80..c9784c27f94 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -42,7 +42,7 @@
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
var/constrdir = usr.dir
var/constrloc = usr.loc
- if (!do_after(usr, 30))
+ if (!do_after(usr, 30, target = src))
return
switch(fixture_type)
if("bulb")
@@ -100,7 +100,7 @@
if (src.stage == 1)
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
usr << "You begin deconstructing [src]..."
- if (!do_after(usr, 30))
+ if (!do_after(usr, 30, target = src))
return
new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
user.visible_message("[user.name] deconstructs [src].", \
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index 6468170f288..d6f19601413 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -356,7 +356,6 @@
return null
/area/proc/get_apc()
- for(var/area/RA in src.related)
- var/obj/machinery/power/apc/FINDME = locate() in RA
- if (FINDME)
- return FINDME
+ for(var/obj/machinery/power/apc/APC in apcs_list)
+ if(APC.area == src)
+ return APC
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 1ab4c078d11..cfffc52cdd7 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -213,7 +213,7 @@
user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \
"You start to weld \the [src] to the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 2
user << "You weld \the [src] to the floor."
@@ -224,7 +224,7 @@
user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \
"You start to cut \the [src] free from the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 1
user << "You cut \the [src] free from the floor."
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 8cb5c1c626f..07943676729 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -129,7 +129,7 @@ field_generator power level display
user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \
"You start to weld \the [src] to the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 2
user << "You weld the field generator to the floor."
@@ -141,7 +141,7 @@ field_generator power level display
user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \
"You start to cut \the [src] free from the floor...", \
"You hear welding.")
- if (do_after(user,20))
+ if (do_after(user,20, target = src))
if(!src || !WT.isOn()) return
state = 1
user << "You cut \the [src] free from the floor."
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 96a08d99e4d..607be1ba324 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -42,7 +42,7 @@
user << "Your soul is too far away."
return
makeNewConstruct(/mob/living/simple_animal/construct/harvester, user, null, 1)
- PoolOrNew(/obj/effect/effect/sleep_smoke, user.loc)
+ PoolOrNew(/obj/effect/effect/smoke/sleeping, user.loc)
/obj/singularity/narsie/process()
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 9a30df83891..90c60fc5769 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -358,18 +358,13 @@
/obj/singularity/proc/toxmob()
var/toxrange = 10
- var/toxdamage = 4
var/radiation = 15
var/radiationmin = 3
- if (src.energy>200)
- toxdamage = round(((src.energy-150)/50)*4,1)
- radiation = round(((src.energy-150)/50)*5,1)
- radiationmin = round((radiation/5),1)//
+ if (energy>200)
+ radiation += round((energy-150)/10,1)
+ radiationmin = round((radiation/5),1)
for(var/mob/living/M in view(toxrange, src.loc))
M.irradiate(rand(radiationmin,radiation))
- toxdamage = (toxdamage - (toxdamage*M.getarmor(null, "rad")))
- M.apply_effect(toxdamage, TOX)
- return
/obj/singularity/proc/combust_mobs()
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index f5c64014ddf..04f15cbdfec 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -135,7 +135,7 @@
user << "You start building the power terminal..."
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 20) && C.amount >= 10)
+ if(do_after(user, 20, target = src) && C.amount >= 10)
var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one
if (prob(50) && electrocute_mob(usr, N, N)) //animate the electrocution if uncautious and unlucky
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 16a5f58588e..f85d5dcc655 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -60,7 +60,7 @@
if(istype(W, /obj/item/weapon/crowbar))
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
user.visible_message("[user] begins to take the glass off the solar panel.", "You begin to take the glass off the solar panel...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
var/obj/item/solar_assembly/S = locate() in src
if(S)
S.loc = src.loc
@@ -391,7 +391,7 @@
/obj/machinery/power/solar_control/attackby(I as obj, user as mob, params)
if(istype(I, /obj/item/weapon/screwdriver))
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if (src.stat & BROKEN)
user << "The broken glass falls out."
var/obj/structure/computerframe/A = new /obj/structure/computerframe( src.loc )
diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm
index 724de7a1b41..ded1f663392 100644
--- a/code/modules/power/terminal.dm
+++ b/code/modules/power/terminal.dm
@@ -60,7 +60,7 @@
"You begin to cut the cables...")
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
if(master && master.can_terminal_dismantle())
if(prob(50) && electrocute_mob(user, powernet, src))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
diff --git a/code/modules/power/tracker.dm b/code/modules/power/tracker.dm
index 2ce74ae88dd..d39921f2699 100644
--- a/code/modules/power/tracker.dm
+++ b/code/modules/power/tracker.dm
@@ -63,7 +63,7 @@
if(istype(W, /obj/item/weapon/crowbar))
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
user.visible_message("[user] begins to take the glass off the solar tracker.", "You begin to take the glass off the solar tracker...")
- if(do_after(user, 50))
+ if(do_after(user, 50, target = src))
var/obj/item/solar_assembly/S = locate() in src
if(S)
S.loc = src.loc
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index 461af979728..55f9ff2849f 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -123,7 +123,7 @@
/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob)
do_teleport(user, user, 10)
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/smoke = new
smoke.set_up(10, 0, user.loc)
smoke.start()
charges--
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 9e1dc22e592..c31eedd7b5d 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -93,7 +93,7 @@
afterattack(user, user) //you know the drill
user.visible_message("[src] goes off!", "[src] goes off in your face!")
return
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
if(magazine.ammo_count())
user << "You can't modify it!"
return
@@ -106,7 +106,7 @@
afterattack(user, user) //and again
user.visible_message("[src] goes off!", "[src] goes off in your face!")
return
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
if(magazine.ammo_count())
user << "You can't modify it!"
return
diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm
index 56a312e9c19..56fb14a3dd1 100644
--- a/code/modules/projectiles/guns/projectile/shotgun.dm
+++ b/code/modules/projectiles/guns/projectile/shotgun.dm
@@ -229,7 +229,7 @@
sawn_state = SAWN_SAWING
- if(do_after(user, 30))
+ if(do_after(user, 30, target = src))
user.visible_message("[user] shortens \the [src]!", "You shorten \the [src].")
name = "sawn-off [src.name]"
desc = sawn_desc
@@ -296,4 +296,4 @@
icon_state = "cshotgun"
origin_tech = "combat=5;materials=2"
mag_type = /obj/item/ammo_box/magazine/internal/shotcom
- w_class = 5
\ No newline at end of file
+ w_class = 5
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index efc20cedfd7..ec2bbcdae6c 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -83,7 +83,7 @@
if(!stuff.anchored && stuff.loc)
teleammount++
do_teleport(stuff, stuff, 10)
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new /datum/effect/effect/system/harmless_smoke_spread()
+ var/datum/effect/effect/system/smoke_spread/smoke = new
smoke.set_up(max(round(10 - teleammount),1), 0, stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity
smoke.start()
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index 94e40614ab8..0978a34f58f 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -124,7 +124,7 @@ var/const/INGEST = 2
var/current_reagent_transfer = current_reagent.volume * part
if(preserve_data)
trans_data = copy_data(current_reagent)
- R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, src.chem_temp)
+ R.add_reagent(current_reagent.id, (current_reagent_transfer * multiplier), trans_data, src.chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered.
src.remove_reagent(current_reagent.id, current_reagent_transfer)
src.update_total()
@@ -426,17 +426,21 @@ var/const/INGEST = 2
return 0
/datum/reagents/proc/reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=1,var/show_message=1)
- for(var/datum/reagent/R in reagent_list)
- if(ismob(A))
- R.reaction_mob(A, method, R.volume*volume_modifier, show_message)
- if(isturf(A))
+ if(isliving(A))
+ var/mob/living/L = A
+ var/touch_protection = 0
+ if(method == TOUCH)
+ touch_protection = L.get_permeability_protection()
+ for(var/datum/reagent/R in reagent_list)
+ R.reaction_mob(L, method, R.volume*volume_modifier, show_message, touch_protection)
+ else if(isturf(A))
+ for(var/datum/reagent/R in reagent_list)
R.reaction_turf(A, R.volume*volume_modifier, show_message)
- if(isobj(A))
+ else if(isobj(A))
+ for(var/datum/reagent/R in reagent_list)
R.reaction_obj(A, R.volume*volume_modifier, show_message)
- return
-
-/datum/reagents/proc/add_reagent(var/reagent, var/amount, var/list/data=null, var/reagtemp = 300)
+/datum/reagents/proc/add_reagent(var/reagent, var/amount, var/list/data=null, var/reagtemp = 300, var/no_react = 0)
if(!isnum(amount) || !amount)
return 1
update_total()
@@ -451,7 +455,8 @@ var/const/INGEST = 2
update_total()
my_atom.on_reagent_change()
R.on_merge(data)
- handle_reactions()
+ if(!no_react)
+ handle_reactions()
return 0
var/datum/reagent/D = chemical_reagents_list[reagent]
@@ -465,19 +470,16 @@ var/const/INGEST = 2
R.data = data
R.on_new(data)
- //debug
- //world << "Adding data"
- //for(var/D in R.data)
- // world << "Container data: [D] = [R.data[D]]"
- //debug
update_total()
my_atom.on_reagent_change()
- handle_reactions()
+ if(!no_react)
+ handle_reactions()
return 0
else
WARNING("[my_atom] attempted to add a reagent called ' [reagent] ' which doesn't exist. ([usr])")
- handle_reactions()
+ if(!no_react)
+ handle_reactions()
return 1
diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm
index 2934c57a3c0..5fe6dc7e8fa 100644
--- a/code/modules/reagents/Chemistry-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents.dm
@@ -34,43 +34,22 @@
..()
holder = null
-/datum/reagent/proc/reaction_mob(var/mob/M, var/method=TOUCH, var/volume, var/show_message = 1) //By default we have a chance to transfer some
- if(!istype(M, /mob/living))
+/datum/reagent/proc/reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume, var/show_message = 1, var/touch_protection = 0)
+ if(!istype(M))
return 0
var/datum/reagent/self = src
- src = null //of the reagent to the mob on TOUCHING it.
+ src = null
- if(!istype(self.holder.my_atom, /obj/effect/effect/chem_smoke))
- // If the chemicals are in a smoke cloud, do not try to let the chemicals "penetrate" into the mob's system (balance station 13) -- Doohl
-
- if(method == TOUCH)
-
- var/chance = 1
- var/block = 0
-
- for(var/obj/item/clothing/C in M.get_equipped_items())
- if(C.permeability_coefficient < chance) chance = C.permeability_coefficient
- if(istype(C, /obj/item/clothing/suit/bio_suit))
- // bio suits are just about completely fool-proof - Doohl
- // kind of a hacky way of making bio suits more resistant to chemicals but w/e
- if(prob(75))
- block = 1
-
- if(istype(C, /obj/item/clothing/head/bio_hood))
- if(prob(75))
- block = 1
-
- chance = chance * 100
-
- if(prob(chance) && !block)
- if(M.reagents)
- M.reagents.add_reagent(self.id,self.volume/2)
+ if(method == TOUCH)
+ if(M.reagents)
+ var/modifier = Clamp((1 - touch_protection) + rand(-5,5)/100, 0, 1)
+ var/amount = round(volume*modifier, 0.1)
+ if(amount >= 1)
+ M.reagents.add_reagent(self.id, amount)
return 1
-/datum/reagent/proc/reaction_obj(var/obj/O, var/volume) //By default we transfer a small part of the reagent to the object
- src = null //if it can hold reagents. nope!
- //if(O.reagents)
- // O.reagents.add_reagent(id,volume/3)
+/datum/reagent/proc/reaction_obj(var/obj/O, var/volume)
+ src = null
return
/datum/reagent/proc/reaction_turf(var/turf/T, var/volume)
diff --git a/code/modules/reagents/Chemistry-Reagents/Blob-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Blob-Reagents.dm
index f3706a7e76b..19826ce0d21 100644
--- a/code/modules/reagents/Chemistry-Reagents/Blob-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Blob-Reagents.dm
@@ -11,13 +11,12 @@
color = "#B68D00"
message = "The blob splashes you with burning oil"
-/datum/reagent/blob/boiling_oil/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/boiling_oil/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(15, BURN)
- M.adjust_fire_stacks(2)
+ var/ratio = volume/25
+ M.apply_damage(15*ratio, BURN)
+ M.adjust_fire_stacks(2*ratio)
M.IgniteMob()
- if(show_message)
- send_message(M)
if(isliving(M))
M.emote("scream")
@@ -28,11 +27,10 @@
color = "#008000"
message_living = ", and you feel sick and nauseated"
-/datum/reagent/blob/toxic_goop/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/toxic_goop/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(20, TOX)
- if(show_message)
- send_message(M)
+ var/ratio = volume/25
+ M.apply_damage(20*ratio, TOX)
/datum/reagent/blob/skin_ripper
name = "Skin Ripper"
@@ -41,12 +39,11 @@
color = "#FF4C4C"
message_living = ", and you feel your skin ripping and tearing off"
-/datum/reagent/blob/skin_ripper/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/skin_ripper/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(20, BRUTE)
- if(show_message)
- send_message(M)
- if(isliving(M))
+ var/ratio = volume/25
+ M.apply_damage(20*ratio, BRUTE)
+ if(iscarbon(M))
M.emote("scream")
// Combo Reagents
@@ -58,15 +55,14 @@
color = "#7F0000"
message_living = ", and you feel your skin char and melt"
-/datum/reagent/blob/skin_melter/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/skin_melter/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(10, BRUTE)
- M.apply_damage(10, BURN)
- M.adjust_fire_stacks(2)
+ var/ratio = volume/25
+ M.apply_damage(10*ratio, BRUTE)
+ M.apply_damage(10*ratio, BURN)
+ M.adjust_fire_stacks(2*ratio)
M.IgniteMob()
- if(show_message)
- send_message(M)
- if(isliving(M))
+ if(iscarbon(M))
M.emote("scream")
/datum/reagent/blob/lung_destroying_toxin
@@ -76,13 +72,13 @@
color = "#00FFC5"
message_living = ", and your lungs feel heavy and weak"
-/datum/reagent/blob/lung_destroying_toxin/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume,var/show_message = 1)
+/datum/reagent/blob/lung_destroying_toxin/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(20, OXY)
- M.losebreath += 15
- M.apply_damage(20, TOX)
- if(show_message)
- send_message(M)
+ var/ratio = volume/25
+ M.apply_damage(20* ratio, OXY)
+ M.losebreath += 15*ratio
+ M.apply_damage(20*ratio, TOX)
+
// Special Reagents
/datum/reagent/blob/radioactive_liquid
@@ -92,19 +88,18 @@
color = "#00EE00"
message_living = ", and your skin feels papery and everything hurts"
-/datum/reagent/blob/radioactive_liquid/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume,var/show_message = 1)
+/datum/reagent/blob/radioactive_liquid/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
+ var/ratio = volume/25
+ M.apply_damage(10*ratio, BRUTE)
if(istype(M, /mob/living/carbon/human))
- M.apply_damage(10, BRUTE)
- M.irradiate(40)
- if(prob(33))
+ M.irradiate(40*ratio)
+ if(prob(33*ratio))
randmuti(M)
if(prob(98))
randmutb(M)
domutcheck(M, null)
updateappearance(M)
- if(show_message)
- send_message(M)
/datum/reagent/blob/dark_matter
name = "Dark Matter"
@@ -113,12 +108,12 @@
color = "#61407E"
message = "You feel a thrum as the blob strikes you, and everything flies at you"
-/datum/reagent/blob/dark_matter/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/dark_matter/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(15, BRUTE)
+ var/ratio = volume/25
+ M.apply_damage(15*ratio, BRUTE)
reagent_vortex(M, 0)
- if(show_message)
- send_message(M)
+
/datum/reagent/blob/b_sorium
name = "Sorium"
@@ -127,11 +122,10 @@
color = "#808000"
message = "The blob slams into you, and sends you flying"
-/datum/reagent/blob/b_sorium/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/b_sorium/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- M.apply_damage(15, BRUTE)
- if(show_message)
- send_message(M)
+ var/ratio = volume/25
+ M.apply_damage(15*ratio, BRUTE)
reagent_vortex(M, 1)
@@ -142,11 +136,10 @@
color = "#FFA500"
message = "The blob strikes you, and its tendrils explode"
-/datum/reagent/blob/explosive/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/explosive/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- if(prob(75))
- if(show_message)
- send_message(M)
+ var/ratio = volume/25
+ if(prob(75*ratio))
explosion(M.loc, 0, 0, 1, 0, 0)
/datum/reagent/blob/omnizine
@@ -157,11 +150,10 @@
message = "The blob squirts something at you"
message_living = ", and you feel great"
-/datum/reagent/blob/omnizine/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/omnizine/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- if(show_message)
- send_message(M)
- M.reagents.add_reagent("omnizine", 11)
+ var/ratio = volume/25
+ M.reagents.add_reagent("omnizine", 11*ratio)
/datum/reagent/blob/spacedrugs
name = "Space drugs"
@@ -171,12 +163,12 @@
message = "The blob squirts something at you"
message_living = ", and you feel funny"
-/datum/reagent/blob/spacedrugs/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume, var/show_message = 1)
+/datum/reagent/blob/spacedrugs/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume)
if(method == TOUCH)
- if(show_message)
- send_message(M)
- M.reagents.add_reagent("space_drugs", 15)
- M.apply_damage(10, TOX)
+ var/ratio = volume/25
+ M.hallucination += 20*ratio
+ M.reagents.add_reagent("space_drugs", 15*ratio)
+ M.apply_damage(10*ratio, TOX)
/datum/reagent/blob/proc/reagent_vortex(var/mob/living/M as mob, var/setting_type)
@@ -197,4 +189,4 @@
if(message_living && !issilicon(M))
totalmessage += message_living
totalmessage += "!"
- M << "[totalmessage]"
+ M << "[totalmessage]"
\ No newline at end of file
diff --git a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm
index 7fd49928443..64ac0c3278b 100644
--- a/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Consumable-Reagents/Food-Reagents.dm
@@ -176,10 +176,10 @@
//monkeys and humans can have masks
if( victim.wear_mask )
- if ( victim.wear_mask.flags & MASKCOVERSEYES )
+ if ( victim.wear_mask.flags_cover & MASKCOVERSEYES )
eyes_covered = 1
safe_thing = victim.wear_mask
- if ( victim.wear_mask.flags & MASKCOVERSMOUTH )
+ if ( victim.wear_mask.flags_cover & MASKCOVERSMOUTH )
mouth_covered = 1
safe_thing = victim.wear_mask
@@ -187,10 +187,10 @@
if(istype(victim, /mob/living/carbon/human))
var/mob/living/carbon/human/H = victim
if( H.head )
- if ( H.head.flags & MASKCOVERSEYES )
+ if ( H.head.flags_cover & MASKCOVERSEYES )
eyes_covered = 1
safe_thing = H.head
- if ( H.head.flags & MASKCOVERSMOUTH )
+ if ( H.head.flags_cover & MASKCOVERSMOUTH )
mouth_covered = 1
safe_thing = H.head
if(H.glasses)
diff --git a/code/modules/reagents/Chemistry-Reagents/Drug-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Drug-Reagents.dm
index 579caddc98a..c21cdf68b33 100644
--- a/code/modules/reagents/Chemistry-Reagents/Drug-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Drug-Reagents.dm
@@ -10,7 +10,7 @@
id = "space_drugs"
description = "An illegal chemical compound used as drug."
color = "#60A584" // rgb: 96, 165, 132
- overdose_threshold = 25
+ overdose_threshold = 30
/datum/reagent/drug/space_drugs/on_mob_life(var/mob/living/M as mob)
M.druggy = max(M.druggy, 15)
@@ -22,11 +22,13 @@
..()
return
+/datum/reagent/drug/space_drugs/overdose_start(var/mob/living/M as mob)
+ M << "You start tripping hard!"
+
+
/datum/reagent/drug/space_drugs/overdose_process(var/mob/living/M as mob)
- if(prob(20))
- M.hallucination = max(M.hallucination, 5)
- M.adjustBrainLoss(0.25*REM)
- M.adjustToxLoss(0.25*REM)
+ if(M.hallucination < volume && prob(20))
+ M.hallucination += 5
..()
return
@@ -39,8 +41,8 @@
addiction_threshold = 30
/datum/reagent/drug/nicotine/on_mob_life(var/mob/living/M as mob)
- var/smoke_message = pick("You can just feel your lungs dying!", "You feel relaxed.", "You feel calmed.", "You feel the lung cancer forming.", "You feel the money you wasted.", "You feel like a space cowboy.", "You feel rugged.")
- if(prob(5))
+ if(prob(1))
+ var/smoke_message = pick("You feel relaxed.", "You feel calmed.","You feel alert.","You feel rugged.")
M << "[smoke_message]"
M.AdjustStunned(-1)
M.adjustStaminaLoss(-0.5*REM)
diff --git a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
index d53b85db81d..0637664da4d 100644
--- a/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Medicine-Reagents.dm
@@ -704,10 +704,10 @@
M.adjustToxLoss(-1*REM)
M.adjustBruteLoss(-1*REM)
M.adjustFireLoss(-1*REM)
- M.AdjustParalysis(-1)
- M.AdjustStunned(-1)
- M.AdjustWeakened(-1)
- M.adjustStaminaLoss(-1.5*REM)
+ M.AdjustParalysis(-3)
+ M.AdjustStunned(-3)
+ M.AdjustWeakened(-3)
+ M.adjustStaminaLoss(-5*REM)
..()
/datum/reagent/medicine/stimulants/overdose_process(var/mob/living/M as mob)
diff --git a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
index 270ddfdabb6..0db45f86c9e 100644
--- a/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Other-Reagents.dm
@@ -144,6 +144,11 @@
/datum/reagent/water/reaction_obj(var/obj/O, var/volume)
src = null
+
+ if(istype(O,/obj/item))
+ var/obj/item/Item = O
+ Item.extinguish()
+
// Monkey cube
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/monkeycube))
var/obj/item/weapon/reagent_containers/food/snacks/monkeycube/cube = O
@@ -151,7 +156,7 @@
cube.Expand()
// Dehydrated carp
- if(istype(O,/obj/item/toy/carpplushie/dehy_carp))
+ else if(istype(O,/obj/item/toy/carpplushie/dehy_carp))
var/obj/item/toy/carpplushie/dehy_carp/dehy = O
dehy.Swell() // Makes a carp
@@ -628,7 +633,7 @@
/datum/reagent/nanites/reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
src = null
- if( (prob(10) && method==TOUCH) || method==INGEST)
+ if( (prob(min(10, volume)) && method==TOUCH) || method==INGEST)
M.ForceContractDisease(new /datum/disease/transformation/robot(0))
/datum/reagent/xenomicrobes
@@ -639,7 +644,7 @@
/datum/reagent/xenomicrobes/reaction_mob(var/mob/M, var/method=TOUCH, var/volume)
src = null
- if( (prob(10) && method==TOUCH) || method==INGEST)
+ if( (prob(min(10, volume)) && method==TOUCH) || method==INGEST)
M.ContractDisease(new /datum/disease/transformation/xeno(0))
/datum/reagent/fluorosurfactant//foam precursor
diff --git a/code/modules/reagents/Chemistry-Reagents/Pyrotechnic-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Pyrotechnic-Reagents.dm
index 67c110b34bd..e8d4ebf6909 100644
--- a/code/modules/reagents/Chemistry-Reagents/Pyrotechnic-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Pyrotechnic-Reagents.dm
@@ -67,7 +67,7 @@
/datum/reagent/clf3/reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)
if(method == TOUCH && isliving(M))
- M.adjust_fire_stacks(5)
+ M.adjust_fire_stacks(min(volume/5, 10))
M.IgniteMob()
PoolOrNew(/obj/effect/hotspot, M.loc)
@@ -148,7 +148,7 @@
/datum/reagent/napalm/reaction_mob(var/mob/living/M, var/method=TOUCH, var/volume)
if(method == TOUCH && isliving(M))
- M.adjust_fire_stacks(7)
+ M.adjust_fire_stacks(min(volume/4, 20))
/datum/reagent/cryostylane
name = "Cryostylane"
diff --git a/code/modules/reagents/Chemistry-Reagents/Toxin-Reagents.dm b/code/modules/reagents/Chemistry-Reagents/Toxin-Reagents.dm
index bbb31522bbb..212414de446 100644
--- a/code/modules/reagents/Chemistry-Reagents/Toxin-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Toxin-Reagents.dm
@@ -34,7 +34,7 @@
if(!istype(M) || !M.dna)
return //No robots, AIs, aliens, Ians or other mobs should be affected by this.
src = null
- if((method==TOUCH && prob(33)) || method==INGEST)
+ if((method==TOUCH && prob(min(33, volume))) || method==INGEST)
randmuti(M)
if(prob(98))
randmutb(M)
@@ -194,8 +194,8 @@
if(iscarbon(M))
var/mob/living/carbon/C = M
if(!C.wear_mask) // If not wearing a mask
- C.adjustToxLoss(2) // 4 toxic damage per application, doubled for some reason
-
+ var/damage = min(round(0.4*volume, 0.1),10)
+ C.adjustToxLoss(damage)
/datum/reagent/toxin/plantbgone/weedkiller
name = "Weed Killer"
id = "weedkiller"
@@ -215,7 +215,8 @@
if(iscarbon(M))
var/mob/living/carbon/C = M
if(!C.wear_mask) // If not wearing a mask
- C.adjustToxLoss(2) // 4 toxic damage per application, doubled for some reason
+ var/damage = min(round(0.4*volume, 0.1),10)
+ C.adjustToxLoss(damage)
/datum/reagent/toxin/spore
name = "Spore Toxin"
@@ -362,9 +363,9 @@
..()
/datum/reagent/toxin/histamine/overdose_process(var/mob/living/M as mob)
- M.adjustOxyLoss(1*REM)
- M.adjustBruteLoss(1*REM)
- M.adjustToxLoss(1*REM)
+ M.adjustOxyLoss(2*REM)
+ M.adjustBruteLoss(2*REM)
+ M.adjustToxLoss(2*REM)
..()
/datum/reagent/toxin/formaldehyde
@@ -374,7 +375,7 @@
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
- toxpwr = 0.5
+ toxpwr = 1
/datum/reagent/toxin/formaldehyde/on_mob_life(var/mob/living/M as mob)
if(prob(5))
@@ -392,8 +393,8 @@
toxpwr = 0
/datum/reagent/toxin/venom/on_mob_life(var/mob/living/M as mob)
- toxpwr = 0.05*volume
- M.adjustBruteLoss((0.1*volume)*REM)
+ toxpwr = 0.2*volume
+ M.adjustBruteLoss((0.3*volume)*REM)
if(prob(15))
M.reagents.add_reagent("histamine",pick(5,10))
M.reagents.remove_reagent("venom",1)
@@ -423,12 +424,12 @@
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.125 * REAGENTS_METABOLISM
- toxpwr = 0.75
+ toxpwr = 1.25
/datum/reagent/toxin/cyanide/on_mob_life(var/mob/living/M as mob)
if(prob(5))
M.losebreath += 1
- if(prob(4))
+ if(prob(8))
M << "You feel horrendously weak!"
M.Stun(2)
M.adjustToxLoss(2*REM)
@@ -482,7 +483,7 @@
toxpwr = 2.5
/datum/reagent/toxin/initropidril/on_mob_life(var/mob/living/M as mob)
- if(prob(5))
+ if(prob(25))
var/picked_option = rand(1,3)
switch(picked_option)
if(1)
@@ -504,7 +505,7 @@
/datum/reagent/toxin/pancuronium
name = "Pancuronium"
id = "pancuronium"
- description = "Knocks you out after 10 seconds, 7% chance to cause some oxygen loss."
+ description = "Knocks you out after 10 seconds, 20% chance to cause some oxygen loss."
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
@@ -513,14 +514,14 @@
/datum/reagent/toxin/pancuronium/on_mob_life(var/mob/living/M as mob)
if(current_cycle >= 10)
M.SetParalysis(1)
- if(prob(7))
+ if(prob(20))
M.losebreath += 4
..()
/datum/reagent/toxin/sodium_thiopental
name = "Sodium Thiopental"
id = "sodium_thiopental"
- description = "Puts you to sleep after 30 seconds, along with some major stamina loss."
+ description = "Puts you to sleep after 10 seconds, along with some major stamina loss."
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.75 * REAGENTS_METABOLISM
@@ -529,13 +530,13 @@
/datum/reagent/toxin/sodium_thiopental/on_mob_life(var/mob/living/M as mob)
if(current_cycle >= 10)
M.sleeping += 1
- M.adjustStaminaLoss(5*REM)
+ M.adjustStaminaLoss(10*REM)
..()
/datum/reagent/toxin/sulfonal
name = "Sulfonal"
id = "sulfonal"
- description = "Deals some toxin damage, and puts you to sleep after 66 seconds."
+ description = "Deals some toxin damage, and puts you to sleep after 22 seconds."
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.125 * REAGENTS_METABOLISM
@@ -584,10 +585,10 @@
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.06 * REAGENTS_METABOLISM
- toxpwr = 1
+ toxpwr = 1.75
/datum/reagent/toxin/coniine/on_mob_life(var/mob/living/M as mob)
- M.losebreath += 3
+ M.losebreath += 5
..()
/datum/reagent/toxin/curare
@@ -597,12 +598,12 @@
reagent_state = LIQUID
color = "#CF3600"
metabolization_rate = 0.125 * REAGENTS_METABOLISM
- toxpwr = 0.5
+ toxpwr = 1
/datum/reagent/toxin/curare/on_mob_life(var/mob/living/M as mob)
if(current_cycle >= 11)
M.Weaken(1)
- M.adjustOxyLoss(0.5*REM)
+ M.adjustOxyLoss(1*REM)
..()
@@ -620,6 +621,7 @@
/datum/reagent/toxin/acid/reaction_mob(var/mob/living/carbon/C, var/method=TOUCH, var/volume)
if(!istype(C))
return
+ volume = round(volume,0.1)
if(method != TOUCH)
C.take_organ_damage(min(6*toxpwr, volume * toxpwr))
return
@@ -629,6 +631,7 @@
/datum/reagent/toxin/acid/reaction_obj(var/obj/O, var/volume)
if(istype(O.loc, /mob)) //handled in human acid_act()
return
+ volume = round(volume,0.1)
O.acid_act(acidpwr, toxpwr, volume)
/datum/reagent/toxin/acid/fluacid
diff --git a/code/modules/reagents/Chemistry-Recipes/Others.dm b/code/modules/reagents/Chemistry-Recipes/Others.dm
index 99866fd47eb..f03bec05038 100644
--- a/code/modules/reagents/Chemistry-Recipes/Others.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Others.dm
@@ -143,10 +143,8 @@
/datum/chemical_reaction/foam/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
-
for(var/mob/M in viewers(5, location))
M << "The solution spews out foam!"
-
var/datum/effect/effect/system/foam_spread/s = new()
s.set_up(created_volume, location, holder)
s.start()
diff --git a/code/modules/reagents/Chemistry-Recipes/Pyrotechnics.dm b/code/modules/reagents/Chemistry-Recipes/Pyrotechnics.dm
index 4b265fae1b9..ba20b7c7817 100644
--- a/code/modules/reagents/Chemistry-Recipes/Pyrotechnics.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Pyrotechnics.dm
@@ -216,19 +216,16 @@
if(holder.has_reagent("stabilizing_agent"))
return
holder.remove_reagent("smoke_powder", created_volume)
+ var/smoke_amount = round(Clamp(created_volume/5, 1, 20),1)
var/location = get_turf(holder.my_atom)
- var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread
+ var/datum/effect/effect/system/smoke_spread/chem/S = new
S.attach(location)
playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
- spawn(0)
- if(S)
- S.set_up(holder, 10, 0, location)
- S.start()
- sleep(10)
- S.start()
- if(holder && holder.my_atom)
- holder.clear_reagents()
- return
+ if(S)
+ S.set_up(holder, smoke_amount, 0, location)
+ S.start()
+ if(holder && holder.my_atom)
+ holder.clear_reagents()
/datum/chemical_reaction/smoke_powder_smoke
name = "smoke_powder_smoke"
@@ -242,18 +239,16 @@
/datum/chemical_reaction/smoke_powder_smoke/on_reaction(var/datum/reagents/holder, var/created_volume)
var/location = get_turf(holder.my_atom)
- var/datum/effect/effect/system/chem_smoke_spread/S = new /datum/effect/effect/system/chem_smoke_spread
+ var/smoke_amount = round(Clamp(created_volume/5, 1, 20),1)
+ var/datum/effect/effect/system/smoke_spread/chem/S = new
S.attach(location)
playsound(location, 'sound/effects/smoke.ogg', 50, 1, -3)
- spawn(0)
- if(S)
- S.set_up(holder, 10, 0, location)
- S.start()
- sleep(10)
- S.start()
- if(holder && holder.my_atom)
- holder.clear_reagents()
- return
+ if(S)
+ S.set_up(holder, smoke_amount, 0, location)
+ S.start()
+ if(holder && holder.my_atom)
+ holder.clear_reagents()
+
/datum/chemical_reaction/sonic_powder
@@ -318,6 +313,7 @@
var/turf/simulated/T = get_turf(holder.my_atom)
if(istype(T))
T.atmos_spawn_air(SPAWN_HEAT | SPAWN_TOXINS, created_volume)
+ holder.clear_reagents()
return
diff --git a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
index 996604a0822..98f34ef9f73 100644
--- a/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
+++ b/code/modules/reagents/Chemistry-Recipes/Slime_extracts.dm
@@ -11,10 +11,9 @@
/datum/chemical_reaction/slimespawn/on_reaction(var/datum/reagents/holder)
feedback_add_details("slime_cores_used","[replacetext(name," ","_")]")
- for(var/mob/O in viewers(get_turf(holder.my_atom), null))
- O.show_message(text("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!"), 1)
var/mob/living/simple_animal/slime/S = new /mob/living/simple_animal/slime
S.loc = get_turf(holder.my_atom)
+ S.visible_message("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!")
/datum/chemical_reaction/slimeinaprov
name = "Slime epinephrine"
@@ -618,3 +617,20 @@
var/obj/P = new chosen
if(P)
P.loc = get_turf(holder.my_atom)
+
+//Rainbow :o)
+/datum/chemical_reaction/slimeRNG
+ name = "Random Core"
+ id = "slimerng"
+ result = null
+ required_reagents = list("plasma" = 1)
+ result_amount = 1
+ required_other = 1
+ required_container = /obj/item/slime_extract/rainbow
+
+/datum/chemical_reaction/slimeRNG/on_reaction(var/datum/reagents/holder)
+ feedback_add_details("slime_cores_used","[replacetext(name," ","_")]")
+ var/mob/living/simple_animal/slime/S = new /mob/living/simple_animal/slime
+ S.colour = pick("grey","orange", "metal", "blue", "purple", "dark purple", "dark blue", "green", "silver", "yellow", "gold", "yellow", "red", "silver", "pink", "cerulean", "sepia", "bluespace", "pyrite", "light pink", "oil", "adamantine", "black")
+ S.loc = get_turf(holder.my_atom)
+ S.visible_message("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!")
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index a938b092061..c3108ddeb0c 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -7,7 +7,6 @@
var/amount_per_transfer_from_this = 5
var/possible_transfer_amounts = list(5,10,15,25,30)
var/volume = 30
- var/list/banned_reagents = list() //List of reagent IDs we reject.
var/list/list_reagents = null
var/spawned_disease = null
var/disease_amount = 20
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index d3c923f6e2c..eed51ff2a81 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -92,7 +92,8 @@ Borg Hypospray
if (R.total_volume && M.can_inject(user, 1))
M << "You feel a tiny prick!"
user << "You inject [M] with the injector."
- R.reaction(M, INGEST)
+ var/fraction = min(amount_per_transfer_from_this/R.total_volume, 1)
+ R.reaction(M, INGEST, fraction)
if(M.reagents)
var/trans = R.trans_to(M, amount_per_transfer_from_this)
user << "[trans] unit\s injected. [R.total_volume] unit\s remaining."
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 8a8f5f1728b..7e5a3d234fd 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -21,6 +21,7 @@
return
var/trans = 0
+ var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
if(ismob(target))
if(istype(target , /mob/living/carbon/human))
@@ -28,10 +29,10 @@
var/obj/item/safe_thing = null
if(victim.wear_mask)
- if(victim.wear_mask.flags & MASKCOVERSEYES)
+ if(victim.wear_mask.flags_cover & MASKCOVERSEYES)
safe_thing = victim.wear_mask
if(victim.head)
- if(victim.head.flags & MASKCOVERSEYES)
+ if(victim.head.flags_cover & MASKCOVERSEYES)
safe_thing = victim.head
if(victim.glasses)
if(!safe_thing)
@@ -40,12 +41,12 @@
if(safe_thing)
if(!safe_thing.reagents)
safe_thing.create_reagents(100)
+
+ reagents.reaction(safe_thing, TOUCH, fraction)
trans = reagents.trans_to(safe_thing, amount_per_transfer_from_this)
target.visible_message("[user] tries to squirt something into [target]'s eyes, but fails!", \
"[user] tries to squirt something into [target]'s eyes, but fails!")
- spawn(5)
- reagents.reaction(safe_thing, TOUCH)
user << "You transfer [trans] unit\s of the solution."
update_icon()
@@ -53,7 +54,8 @@
target.visible_message("[user] squirts something into [target]'s eyes!", \
"[user] squirts something into [target]'s eyes!")
- reagents.reaction(target, TOUCH)
+
+ reagents.reaction(target, TOUCH, fraction)
var/mob/M = target
var/R
if(reagents)
@@ -83,7 +85,8 @@
update_icon()
/obj/item/weapon/reagent_containers/dropper/update_icon()
- if(reagents.total_volume<=0)
- icon_state = "dropper0"
- else
- icon_state = "dropper1"
\ No newline at end of file
+ overlays.Cut()
+ if(reagents.total_volume)
+ var/image/filling = image('icons/obj/reagentfillings.dmi', src, "dropper")
+ filling.color = mix_color_from_reagents(reagents.reagent_list)
+ overlays += filling
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 2a21fe917d8..b8f188c3ba5 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -72,12 +72,6 @@
user << "[target] is full."
return
- if(istype(target, /obj/item/weapon/reagent_containers))
- var/obj/item/weapon/reagent_containers/RC = target
- for(var/bad_reg in RC.banned_reagents)
- if(reagents.has_reagent(bad_reg, 1)) //Message is a bit "Game-y" but I can't think up a better one.
- user << "A chemical in [src] is far too dangerous to transfer to [RC]!"
- return
var/trans = reagents.trans_to(target, amount_per_transfer_from_this)
user << "You transfer [trans] unit\s of the solution to [target]."
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index 708b8659a7a..1a86c6f9ed7 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -25,7 +25,8 @@
M << "You feel a tiny prick!"
user << "You inject [M] with [src]."
- reagents.reaction(M, INGEST)
+ var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
+ reagents.reaction(M, INGEST, fraction)
if(M.reagents)
var/list/injected = list()
for(var/datum/reagent/R in reagents.reagent_list)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 4520bb48afb..b675f86913b 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -45,10 +45,9 @@
if(reagents.total_volume)
reagents.reaction(M, apply_type)
- spawn(5)
- reagents.trans_to(M, reagents.total_volume)
- qdel(src)
- return 1
+ reagents.trans_to(M, reagents.total_volume)
+ qdel(src)
+ return 1
else
qdel(src)
return 1
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index edfce7a4595..054b8113f2f 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -15,7 +15,6 @@
amount_per_transfer_from_this = 5
volume = 250
possible_transfer_amounts = null
- banned_reagents = list("facid","sacid")
/obj/item/weapon/reagent_containers/spray/afterattack(atom/A as mob|obj, mob/user as mob)
@@ -159,7 +158,6 @@
amount_per_transfer_from_this = 10
volume = 600
origin_tech = "combat=3;materials=3;engineering=3"
- banned_reagents = list()//the safeties are off, spray and pay!
/obj/item/weapon/reagent_containers/spray/chemsprayer/spray(var/atom/A)
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 9d7988c289e..e41a0a2639c 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -151,7 +151,8 @@
var/contained = english_list(rinject)
var/mob/M = target
add_logs(user, M, "injected", object="[src.name]", addition="which had [contained]")
- reagents.reaction(target, INGEST)
+ var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
+ reagents.reaction(target, INGEST, fraction)
if(ismob(target) && target == user)
//Attack log entries are produced here due to failure to produce elsewhere. Remove them here if you have doubles from normal syringes.
var/list/rinject = list()
@@ -161,8 +162,8 @@
var/mob/M = target
log_attack("[user.name] ([user.ckey]) injected [M.name] ([M.ckey]) with [src.name], which had [contained] (INTENT: [uppertext(user.a_intent)])")
M.attack_log += text("\[[time_stamp()]\] Injected themselves ([contained]) with [src.name].")
-
- reagents.reaction(target, INGEST)
+ var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
+ reagents.reaction(target, INGEST, fraction)
spawn(5)
var/datum/reagent/blood/B
for(var/datum/reagent/blood/d in src.reagents.reagent_list)
@@ -180,7 +181,7 @@
/obj/item/weapon/reagent_containers/syringe/update_icon()
- var/rounded_vol = round(reagents.total_volume,5)
+ var/rounded_vol = min(max(round(reagents.total_volume,5),5),15)
overlays.Cut()
if(ismob(loc))
var/injoverlay
@@ -195,12 +196,7 @@
if(reagents.total_volume)
var/image/filling = image('icons/obj/reagentfillings.dmi', src, "syringe10")
-
- switch(rounded_vol)
- if(5) filling.icon_state = "syringe5"
- if(10) filling.icon_state = "syringe10"
- if(15) filling.icon_state = "syringe15"
-
+ filling.icon_state = "syringe[rounded_vol]"
filling.color = mix_color_from_reagents(reagents.reagent_list)
overlays += filling
diff --git a/code/modules/recycling/disposal-construction.dm b/code/modules/recycling/disposal-construction.dm
index bf75185292d..2576dcfc98c 100644
--- a/code/modules/recycling/disposal-construction.dm
+++ b/code/modules/recycling/disposal-construction.dm
@@ -223,7 +223,7 @@
if(W.remove_fuel(0,user))
playsound(loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start welding the [nicetype] in place..."
- if(do_after(user, 20))
+ if(do_after(user, 20, target = src))
if(!loc || !W.isOn())
return
user << "The [nicetype] has been welded in place."
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index f1afbfe34ee..80035f45a33 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -100,7 +100,7 @@
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the floorweld off \the [src]..."
- if(do_after(user,20))
+ if(do_after(user,20, target = src))
if(!src || !W.isOn()) return
user << "You slice the floorweld off \the [src]."
Deconstruct()
@@ -847,7 +847,7 @@
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the disposal pipe..."
// check if anything changed over 2 seconds
- if(do_after(user,30))
+ if(do_after(user,30, target = src))
if(!src || !W.isOn()) return
Deconstruct()
user << "You slice the disposal pipe."
@@ -1151,7 +1151,7 @@
if(W.remove_fuel(0,user))
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the disposal pipe..."
- if(do_after(user,30))
+ if(do_after(user,30, target = src))
if(!src || !W.isOn()) return
Deconstruct()
user << "You slice the disposal pipe."
@@ -1285,7 +1285,7 @@
if(W.remove_fuel(0,user))
playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the floorweld off \the [src]..."
- if(do_after(user,20))
+ if(do_after(user,20, target = src))
if(!src || !W.isOn()) return
user << "You slice the floorweld off \the [src]."
stored.loc = loc
@@ -1330,4 +1330,4 @@
else
dirs = alldirs.Copy()
- src.streak(dirs)
\ No newline at end of file
+ src.streak(dirs)
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index f4495358aed..5225e5a4d48 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -117,6 +117,7 @@
flags = NOBLUDGEON
amount = 25
max_amount = 25
+ burn_state = 0 //burnable
/obj/item/stack/packageWrap/afterattack(var/obj/target as obj, mob/user as mob, proximity)
@@ -312,7 +313,7 @@
if(W.remove_fuel(0,user))
playsound(loc, 'sound/items/Welder2.ogg', 100, 1)
user << "You start slicing the floorweld off the delivery chute..."
- if(do_after(user,20))
+ if(do_after(user,20, target = src))
if(!src || !W.isOn()) return
Deconstruct()
user << "You slice the floorweld off the delivery chute."
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 1eeb4731c18..86e8b96252d 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -231,7 +231,7 @@
loaded_item = null
/obj/machinery/r_n_d/experimentor/proc/throwSmoke(var/turf/where)
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new
+ var/datum/effect/effect/system/smoke_spread/smoke = new
smoke.set_up(1,0, where, 0)
smoke.start()
@@ -323,7 +323,7 @@
R.my_atom = src
R.add_reagent(chosenchem , 50)
investigate_log("Experimentor has released [chosenchem] smoke.", "experimentor")
- var/datum/effect/effect/system/chem_smoke_spread/smoke = new
+ var/datum/effect/effect/system/smoke_spread/chem/smoke = new
smoke.set_up(R, 1, 0, src, 0, silent = 1)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
@@ -335,7 +335,7 @@
var/datum/reagents/R = new/datum/reagents(50)
R.my_atom = src
R.add_reagent(chosenchem , 50)
- var/datum/effect/effect/system/chem_smoke_spread/smoke = new
+ var/datum/effect/effect/system/smoke_spread/chem/smoke = new
smoke.set_up(R, 1, 0, src, 0, silent = 1)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
@@ -422,7 +422,7 @@
R.my_atom = src
R.add_reagent("frostoil" , 50)
investigate_log("Experimentor has released frostoil gas.", "experimentor")
- var/datum/effect/effect/system/chem_smoke_spread/smoke = new
+ var/datum/effect/effect/system/smoke_spread/chem/smoke = new
smoke.set_up(R, 1, 0, src, 0, silent = 1)
playsound(src.loc, 'sound/effects/smoke.ogg', 50, 1, -3)
smoke.start()
@@ -444,7 +444,7 @@
ejectItem(TRUE)
if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] malfunctions, releasing a flurry of chilly air as [exp_on] pops out!")
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new
+ var/datum/effect/effect/system/smoke_spread/smoke = new
smoke.set_up(1,0, src.loc, 0)
smoke.start()
ejectItem()
@@ -652,7 +652,7 @@
//////////////// RELIC PROCS /////////////////////////////
/obj/item/weapon/relic/proc/throwSmoke(var/turf/where)
- var/datum/effect/effect/system/harmless_smoke_spread/smoke = new
+ var/datum/effect/effect/system/smoke_spread/smoke = new
smoke.set_up(1,0, where, 0)
smoke.start()
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index 4f67a8aa16d..4ee8ea23b77 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -42,6 +42,16 @@
pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/PSHOOM.ogg'
alt_sound = 'sound/items/PSHOOM_2.ogg'
+/obj/item/weapon/storage/part_replacer/bluespace/content_can_dump(atom/dest_object, mob/user)
+ if(Adjacent(user))
+ if(get_dist(user, dest_object) < 8)
+ if(dest_object.storage_contents_dump_act(src, user))
+ play_rped_sound()
+ user.Beam(dest_object,icon_state="rped_upgrade",icon='icons/effects/effects.dmi',time=5)
+ return 1
+ user << "The [src.name] buzzes."
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
+ return 0
/obj/item/weapon/storage/part_replacer/proc/play_rped_sound()
//Plays the sound for RPED exhanging or installing parts.
diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm
index 62aac98be5e..75ae34bc050 100644
--- a/code/modules/scripting/Implementations/Telecomms.dm
+++ b/code/modules/scripting/Implementations/Telecomms.dm
@@ -308,7 +308,7 @@ var/const/SIGNAL_COOLDOWN = 20 // 2 seconds
ERROR("[src] has no radio.")
return
- if((!message || message == "") && message != 0)
+ if((!message) && message != 0)
message = "*beep*"
if(!source)
source = "[html_encode(uppertext(S.id))]"
diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm
index 662a4304d3e..4982c6bcc64 100644
--- a/code/modules/surgery/helpers.dm
+++ b/code/modules/surgery/helpers.dm
@@ -80,13 +80,13 @@
for(var/obj/item/clothing/I in list(C.back, C.wear_mask, C.head))
covered_locations |= I.body_parts_covered
face_covered |= I.flags_inv
- eyesmouth_covered |= I.flags
+ eyesmouth_covered |= I.flags_cover
if(ishuman(C))
var/mob/living/carbon/human/H = C
for(var/obj/item/I in list(H.wear_suit, H.w_uniform, H.shoes, H.belt, H.gloves, H.glasses, H.ears))
covered_locations |= I.body_parts_covered
face_covered |= I.flags_inv
- eyesmouth_covered |= I.flags
+ eyesmouth_covered |= I.flags_cover
switch(location)
if("head")
diff --git a/code/modules/surgery/organs/cybernetic_implants.dm b/code/modules/surgery/organs/cybernetic_implants.dm
index a54491e6f41..7230c1d0572 100644
--- a/code/modules/surgery/organs/cybernetic_implants.dm
+++ b/code/modules/surgery/organs/cybernetic_implants.dm
@@ -318,6 +318,7 @@
origin_tech = "materials=6;programming=3;biotech=6;syndicate=4"
var/revive_cost = 0
var/reviving = 0
+ var/cooldown = 0
/obj/item/cybernetic_implant/chest/reviver/function()
SSobj.processing |= src
@@ -333,22 +334,22 @@
spawn(30)
if(prob(90) && owner.getOxyLoss())
owner.adjustOxyLoss(-3)
- revive_cost += 0.1
+ revive_cost += 5
if(prob(75) && owner.getBruteLoss())
owner.adjustBruteLoss(-1)
- revive_cost += 0.5
+ revive_cost += 20
if(prob(75) && owner.getFireLoss())
owner.adjustFireLoss(-1)
- revive_cost += 0.5
+ revive_cost += 20
if(prob(40) && owner.getToxLoss())
owner.adjustToxLoss(-1)
- revive_cost++
+ revive_cost += 50
else
- revive_cost = (revive_cost * 100) + world.time
+ cooldown = revive_cost + world.time
reviving = 0
return
- if(revive_cost > world.time)
+ if(cooldown > world.time)
return
if(owner.stat != UNCONSCIOUS)
return
@@ -360,7 +361,11 @@
reviving = 1
/obj/item/cybernetic_implant/chest/reviver/emp_act(severity)
- revive_cost = world.time + 200
+ if(reviving)
+ revive_cost += 200
+ else
+ cooldown += 200
+
if(prob(50 / severity))
owner.heart_attack = 1
spawn(600 / severity)
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index 2c7f7ddbec4..e630e7da48e 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -43,7 +43,7 @@
Handle_Multi_Loc(user, target)
preop(user, target, target_zone, tool)
- if(do_after(user, time))
+ if(do_after(user, time, target = target))
var/advance = 0
var/prob_chance = 100
diff --git a/code/modules/telesci/telesci_computer.dm b/code/modules/telesci/telesci_computer.dm
index 0450b8109c1..3e0a44925ea 100644
--- a/code/modules/telesci/telesci_computer.dm
+++ b/code/modules/telesci/telesci_computer.dm
@@ -1,7 +1,8 @@
/obj/machinery/computer/telescience
name = "\improper Telepad Control Console"
desc = "Used to teleport objects to and from the telescience telepad."
- icon_state = "teleport"
+ icon_screen = "teleport"
+ icon_keyboard = "teleport_key"
circuit = /obj/item/weapon/circuitboard/telesci_console
var/sending = 1
var/obj/machinery/telepad/telepad = null
diff --git a/config/admins.txt b/config/admins.txt
index 8a308e187ce..a029f2639e4 100644
--- a/config/admins.txt
+++ b/config/admins.txt
@@ -7,7 +7,8 @@
# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn #
# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. #
###############################################################################################
-MrStonedOne = Host
+Optimumtact = Host
+MrStonedOne = Game Master
microscopics = Game Master
Gun Hog = Game Master
KorPhaeron = Game Master
@@ -84,4 +85,4 @@ vekter = Game Master
Ahammer18 = Game Master
ACCount12 = Game Master
fayrik = Game Master
-shadowlight213 = Game Master
\ No newline at end of file
+shadowlight213 = Game Master
diff --git a/config/config.txt b/config/config.txt
index cdfd19f9f34..f7ec7eda026 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -190,4 +190,7 @@ NOTIFY_NEW_PLAYER_AGE 0
#PANIC_BUNKER
## Uncomment to have the changelog file automatically open when a user connects and hasn't seen the latest changelog
-#AGGRESSIVE_CHANGELOG
\ No newline at end of file
+#AGGRESSIVE_CHANGELOG
+
+## Uncomment to have the game log runtimes to the log folder. (Note: this disables normal output in dd/ds, so it should be left off for testing.
+#LOG_RUNTIMES
\ No newline at end of file
diff --git a/config/tips.txt b/config/tips.txt
index 04ea4ab50d0..ca03cc723d6 100644
--- a/config/tips.txt
+++ b/config/tips.txt
@@ -12,7 +12,7 @@ You can drag the icon of an equipped headset or PDA onto your screen to interact
The mime's invisible wall will block electrodes and other projectiles, but beams pass straight through it like windows.
The Library system is much more robust than most people think! Mess around with it, see if you can log who takes out the books for radio-reading.
Use a pair of handcuffs on a pair of orange shoes (standard prisoner issue) to chain them together.
-Revolutionaries brainwashed by Rev leaders can have their opinions swayed back to Nanotrasen loyalty by enough heavy objects to the head.
+Revolutionaries and gangsters can have their opinions swayed back to Nanotrasen loyalty by enough heavy objects to the head.
Husked corpses that have been drained of their genomes by a changeling also lack blood in their veins, unlike burned or space frozen corpses.
The stethoscope's utility extends beyond lung and heart check-ups. They can also be used to crack certain safes.
Chloral Hydrate can be counteracted by having coffee in your system!
@@ -43,6 +43,7 @@ Blobs are extremely powerful and are impossible to defeat alone. Communicate wit
You can fight blob pieces diagonally, as they can only expand onto adjacent tiles in cardinal directions.
Security huds and secglass huds can tell you if someone is implanted with a loyalty implant. Use this to your advantage in a revolution.
Loyalty implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
+Loyalty implants can only prevent someone from being turned into a gangster: unlike revolutionaries, it will not de-gang them if they have already been recruited.
Don't neglect upgrading your machines with the machine parts produced by research! These can seriously improve the efficiency of your equipment.
Cyborgs are impervious to fires and temperature, and can walk in a blazing inferno without worry. Don't shy away from setting the whole station on fire as a malfunctioning or rogue AI!
The heads of staff, especially the Head of Security and the Captain, are usually extremely difficult to kill. If one of them is your target as a traitor, plan carefully.
@@ -88,3 +89,4 @@ In the job selection menu, from the lobby, you can use right click on the "Low/M
If you stay out of camera range for 10 seconds, the AI's track on you will break.
You can shoot cameras with bullets to disable them remotely.
Disabling a camera with wirecutters will not cause a camera alarm, but bludgeoning it will.
+Gangs derive their power from their presence. Cleaning up gang tags is the best way to prevent them from growing out of control.
diff --git a/html/changelog.html b/html/changelog.html
index baceb83765d..94f1837dbaa 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,6 +55,178 @@
-->
+
01 July 2015
+
NullQuery updated:
+
+
The crew monitoring computer, AI crew monitoring popup and the handheld crew monitor now update automatically.
+
Crew monitoring: The health information has been turned into a health indicator. It goes from green to red. Hovering over the icon shows detailed information (if available).
+
Crew monitoring: The location coordinates have been hidden. You can see them by hovering over the 'Location' column.
+
Crew monitoring: A minimap has been added so you can easily see where people are.
+
Crew monitoring: Players who are not in range of a camera are not shown on the minimap.
+
Crew monitoring: AI players can quickly move to other locations or track players by clicking the minimap or items in the table.
+
Crew monitoring: For AI players, health information always shows a white indicator instead of green-to-red. This is a deliberate limitation to prevent the AI from becoming too omnipresent.
+
+
phil235 updated:
+
+
Space drug overdose no longer cause brute/brain damage but you hallucinate more. Space Drug Blob now makes you hallucinate even if you don't overdose on its space drug.
+
+
+
29 June 2015
+
Ikarrus updated:
+
+
Clothing has been separated out of equipment lockers into wardrobes to reduce clutter.
+
+
Incoming5643 updated:
+
+
The secrets of the rainbow slimes have finally been revealed. To attain this rare blob you must breed a slime with a 100% mutation chance!
+
Rainbow slime cores will generate a randomly colored slime when injected with plasma. It's a good plan B if the slimes aren't cooperating in terms of colors. You can get any color slime this way, pray to the RNG!
+
+
Xhuis updated:
+
+
The Sleeping Carp clan has made its presence known on Space Station 13. Some gangs will name themselves after this group and practice martial arts rather than using traditional gang weaponry. These shadowboxers are not to be taken lightly.
+
+
oranges updated:
+
+
Thanks to a breakthrough in directed vector thrusting, all nanotrasen brand jetpacks have been greatly improved in speed and handling
+
+
+
28 June 2015
+
Ikarrus updated:
+
+
Gang Lieutenants can buy gang tools now, but at a higher cost than the original boss
+
Gang leaders can register additional gangtools to themselves for use as spares.
+
Number of maximum lieutenants lowered to 2
+
Pistol cost increased to 25 influence
+
Uzi cost increased to 50 influence
+
Uzi Ammo decreased to 20 influence
+
Overcoats added to items the biogenerator can produce.
+
Micro and Macro bomb implants are now restricted to the Nuclear game mode.
+
+
phil235 updated:
+
+
Smoke (and foam) no longer distribute more reagents than they have. The amount of clouds in a smoke now depends on the amount of smoke created. Acid no longer melts items on a mob at low volume, and the chances to melt them increases with the amount applied on the mob. Sprays can now contain acid again.
+
+
+
27 June 2015
+
Ikarrus updated:
+
+
Some objects can be burned now.
+
Bombs will shred your clothes, with respect to their layering and armor values. Exterior clothing will shield clothing underneath. Storage items will drop their contents when bombed this way.
+
+
Laharl Montogmmery updated:
+
+
Storage Content Transfer : Bluespace Boogaloo! You can now transfer the content of the BoH/BRPED into tiles/bins/bags out of your reach. Range is 7 tiles.
+
+
MrStonedOne updated:
+
+
Admins will now receive a notification when one of them starts to reply to an adminhelp to cut down on multiple responses to adminhelps and let admins know when an adminhelp isn't getting replied to.
+
The keyword finder in admin helps (adds a (?) link next to player names in the text of adminhelps) has been added for all player to admin pms, as well as admin say.
+
+
NullQuery updated:
+
+
Introduces html_interface, a module to streamline the management of browser windows.
+
Adds playing cards that utilize a new HTML window management system.
+
+
Vekter updated:
+
+
Added a new military jacket to the Autodrobe and ClothesMate.
+
+
+
26 June 2015
+
Ikarrus updated:
+
+
Added a couple of new gang tag resprites by Joan.
+
+
Kor updated:
+
+
Summon Guns has returned to its former glory. The spell will once again create antagonists, now with the objective to steal as many guns as possible.
+
Summon Guns once again costs a spell point, rather than granting one.
+
+
phil235 updated:
+
+
Buffs traitor stimpack (and adrenalin implant) to be more efficient against stuns/knockdowns.
+
+
pudl updated:
+
+
You can now play games of mastermind to unlock abandoned crates found throughout space.
+
+
+
25 June 2015
+
Iamgoofball updated:
+
+
Changes up how Explosive Implants work.
+
They have become Microbomb Implants. They cost 1 TC each. Each implant you inject increases the size of the explosion. You gib on usage, regardless of explosion size.
+
A Macrobomb implant was added for 20 TC. It is the equivalent of injecting 20 microbombs.
+
Nuke Ops start with microbomb implants again.
+
+
+
24 June 2015
+
Ikarrus updated:
+
+
Request Console message sent to major departments will now be broadcasted on that department's radio.
+
Request Consoles can be used to quicly declare a security, medical, or engineering emergency.
+
+
+
23 June 2015
+
Fayrik updated:
+
+
NanoUI is now Telekenesis aware, but due to other constraints, NanoUI interfaces are read only at a distance.
+
Refactored all NanoUI interfaces to use a more universal proc.
+
Adjusted the refresh time of the NanoUI SubSystem. All interfaces will update less, but register mouse clicks faster.
+
Removed automatic updates on atmospheric pumps, canisters and tanks, making them respond to button clicks much faster.
+
Atmos alarm reset buttons work now. Probably.
+
+
Iamgoofball updated:
+
+
Adds a progress bar when performing actions.
+
+
Ikarrus updated:
+
+
New gang names with tags created by Joan
+
C4 explosive can be purchased by gangs for 10 influence.
+
Recruitment pen cost increased to 50.
+
Lieutenants recieve one free recruitment pen.
+
Recruitment pens are now stealthy and no longer give a tiny prick message.
+
Increased chance of deconversion with head trauma
+
Recalling the shuttle now takes about a minute to work, during which you won't be able to use your gangtool.
+
Pinpointers no longer point at dominators. Instead, dominators will beep while active.
+
Added puffer jackets and vests.
+
Increased gang outfit armor. It is moderately resistant to bullets now.
+
Removed bulletproof vests from gangtool menu.
+
+
Jordie0608 updated:
+
+
Admins can now flag ckeys to be alerted when they connect to the server.
+
+
MrStonedOne updated:
+
+
Admins can now reject poor adminhelps. This will tell the player how to construct a useful adminhelp and give them back their adminhelp verb
+
+
RemieRichards updated:
+
+
Cumulative armour damage resistance is now capped at 90%, you will now always take at bare minimum, 10% of the incoming damage.
+
Added a system for Armour Penetration to items, it works by temporarily (It does NOT damage the armour or anything) reducing the armour values by the AP value during the attack instance.
+
The formula for AP is Armour-ArmourPenetration = AdjustedArmour and AdjustedArmour is used for all the remaining calculations instead of Armour (Eg: 80 Melee - 15 AP = 65 Melee).
+
The Ninja's Energy Katana has 15 AP, Xenomorphs have an inbuilt AP of 10.
+
You can now unwrench pipes who's internal pressures are greater than that of their environment...
+
However it will throw you away from the pipe at extreme speed! (You are warned beforehand if the pipe will do this, allowing you to cancel)
+
+
Vekter updated:
+
+
Finally fixed immovable rods! They will now properly bisect the station (and crit anyone unlucky enough to be in their path).
+
Increased Meteor activity detected in the vicinity of the station. Be advised that many storms may be more violent than they once were.
+
Gravitational anomalies will now throw items at mobs in their vicinity. Take care while scanning them.
+
Flux anomalies explode much more violently now. Get there and destroy them, or risk losing half a department.
+
+
xxalpha updated:
+
+
Added a new Reviver implant: now it revives you from unconsciousness rather than death.
+
Added cybernetic implants and a cybernetic implants bundle to the Nuke Ops uplink.
+
Fixed Nutriment pump implant printing.
+
Health Analyzers now have the ability to detect cybernetic implants.
+
X-Ray implants are now much harder to unlock.
+
+
22 June 2015
Iamgoofball updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index 0a91a248be7..33cba4c2a67 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -2890,3 +2890,174 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
- bugfix: Revenants can no longer use abilities from inside walls.
- rscdel: Directly lethal abilities have been removed from revenants. In addition,
they can no longer harvest unconscious people, only the dead.
+2015-06-23:
+ Fayrik:
+ - rscadd: NanoUI is now Telekenesis aware, but due to other constraints, NanoUI
+ interfaces are read only at a distance.
+ - tweak: Refactored all NanoUI interfaces to use a more universal proc.
+ - tweak: Adjusted the refresh time of the NanoUI SubSystem. All interfaces will
+ update less, but register mouse clicks faster.
+ - bugfix: Removed automatic updates on atmospheric pumps, canisters and tanks, making
+ them respond to button clicks much faster.
+ - bugfix: Atmos alarm reset buttons work now. Probably.
+ Iamgoofball:
+ - rscadd: Adds a progress bar when performing actions.
+ Ikarrus:
+ - rscadd: New gang names with tags created by Joan
+ - rscadd: C4 explosive can be purchased by gangs for 10 influence.
+ - tweak: Recruitment pen cost increased to 50.
+ - rscadd: Lieutenants recieve one free recruitment pen.
+ - tweak: Recruitment pens are now stealthy and no longer give a tiny prick message.
+ - tweak: Increased chance of deconversion with head trauma
+ - tweak: Recalling the shuttle now takes about a minute to work, during which you
+ won't be able to use your gangtool.
+ - rscadd: Pinpointers no longer point at dominators. Instead, dominators will beep
+ while active.
+ - rscadd: Added puffer jackets and vests.
+ - tweak: Increased gang outfit armor. It is moderately resistant to bullets now.
+ - rscdel: Removed bulletproof vests from gangtool menu.
+ Jordie0608:
+ - rscadd: Admins can now flag ckeys to be alerted when they connect to the server.
+ MrStonedOne:
+ - rscadd: Admins can now reject poor adminhelps. This will tell the player how to
+ construct a useful adminhelp and give them back their adminhelp verb
+ RemieRichards:
+ - tweak: Cumulative armour damage resistance is now capped at 90%, you will now
+ always take at bare minimum, 10% of the incoming damage.
+ - rscadd: Added a system for Armour Penetration to items, it works by temporarily
+ (It does NOT damage the armour or anything) reducing the armour values by the
+ AP value during the attack instance.
+ - rscadd: 'The formula for AP is Armour-ArmourPenetration = AdjustedArmour and AdjustedArmour
+ is used for all the remaining calculations instead of Armour (Eg: 80 Melee -
+ 15 AP = 65 Melee).'
+ - rscadd: The Ninja's Energy Katana has 15 AP, Xenomorphs have an inbuilt AP of
+ 10.
+ - tweak: You can now unwrench pipes who's internal pressures are greater than that
+ of their environment...
+ - rscadd: However it will throw you away from the pipe at extreme speed! (You are
+ warned beforehand if the pipe will do this, allowing you to cancel)
+ Vekter:
+ - bugfix: Finally fixed immovable rods! They will now properly bisect the station
+ (and crit anyone unlucky enough to be in their path).
+ - tweak: Increased Meteor activity detected in the vicinity of the station. Be advised
+ that many storms may be more violent than they once were.
+ - rscadd: Gravitational anomalies will now throw items at mobs in their vicinity.
+ Take care while scanning them.
+ - rscadd: Flux anomalies explode much more violently now. Get there and destroy
+ them, or risk losing half a department.
+ xxalpha:
+ - rscadd: 'Added a new Reviver implant: now it revives you from unconsciousness
+ rather than death.'
+ - rscadd: Added cybernetic implants and a cybernetic implants bundle to the Nuke
+ Ops uplink.
+ - bugfix: Fixed Nutriment pump implant printing.
+ - tweak: Health Analyzers now have the ability to detect cybernetic implants.
+ - tweak: X-Ray implants are now much harder to unlock.
+2015-06-24:
+ Ikarrus:
+ - rscadd: Request Console message sent to major departments will now be broadcasted
+ on that department's radio.
+ - rscadd: Request Consoles can be used to quicly declare a security, medical, or
+ engineering emergency.
+2015-06-25:
+ Iamgoofball:
+ - rscadd: Changes up how Explosive Implants work.
+ - rscadd: They have become Microbomb Implants. They cost 1 TC each. Each implant
+ you inject increases the size of the explosion. You gib on usage, regardless
+ of explosion size.
+ - rscadd: A Macrobomb implant was added for 20 TC. It is the equivalent of injecting
+ 20 microbombs.
+ - rscadd: Nuke Ops start with microbomb implants again.
+2015-06-26:
+ Ikarrus:
+ - imageadd: Added a couple of new gang tag resprites by Joan.
+ Kor:
+ - tweak: Summon Guns has returned to its former glory. The spell will once again
+ create antagonists, now with the objective to steal as many guns as possible.
+ - tweak: Summon Guns once again costs a spell point, rather than granting one.
+ phil235:
+ - tweak: Buffs traitor stimpack (and adrenalin implant) to be more efficient against
+ stuns/knockdowns.
+ pudl:
+ - rscadd: You can now play games of mastermind to unlock abandoned crates found
+ throughout space.
+2015-06-27:
+ Ikarrus:
+ - rscadd: Some objects can be burned now.
+ - rscadd: Bombs will shred your clothes, with respect to their layering and armor
+ values. Exterior clothing will shield clothing underneath. Storage items will
+ drop their contents when bombed this way.
+ Laharl Montogmmery:
+ - rscadd: 'Storage Content Transfer : Bluespace Boogaloo! You can now transfer the
+ content of the BoH/BRPED into tiles/bins/bags out of your reach. Range is 7
+ tiles.'
+ MrStonedOne:
+ - tweak: Admins will now receive a notification when one of them starts to reply
+ to an adminhelp to cut down on multiple responses to adminhelps and let admins
+ know when an adminhelp isn't getting replied to.
+ - rscadd: The keyword finder in admin helps (adds a (?) link next to player names
+ in the text of adminhelps) has been added for all player to admin pms, as well
+ as admin say.
+ NullQuery:
+ - wip: Introduces html_interface, a module to streamline the management of browser
+ windows.
+ - rscadd: Adds playing cards that utilize a new HTML window management system.
+ Vekter:
+ - rscadd: Added a new military jacket to the Autodrobe and ClothesMate.
+2015-06-28:
+ Ikarrus:
+ - rscadd: Gang Lieutenants can buy gang tools now, but at a higher cost than the
+ original boss
+ - rscadd: Gang leaders can register additional gangtools to themselves for use as
+ spares.
+ - tweak: Number of maximum lieutenants lowered to 2
+ - tweak: Pistol cost increased to 25 influence
+ - tweak: Uzi cost increased to 50 influence
+ - tweak: Uzi Ammo decreased to 20 influence
+ - rscadd: Overcoats added to items the biogenerator can produce.
+ - rscdel: Micro and Macro bomb implants are now restricted to the Nuclear game mode.
+ phil235:
+ - tweak: Smoke (and foam) no longer distribute more reagents than they have. The
+ amount of clouds in a smoke now depends on the amount of smoke created. Acid
+ no longer melts items on a mob at low volume, and the chances to melt them increases
+ with the amount applied on the mob. Sprays can now contain acid again.
+2015-06-29:
+ Ikarrus:
+ - rscadd: Clothing has been separated out of equipment lockers into wardrobes to
+ reduce clutter.
+ Incoming5643:
+ - rscadd: The secrets of the rainbow slimes have finally been revealed. To attain
+ this rare blob you must breed a slime with a 100% mutation chance!
+ - rscadd: Rainbow slime cores will generate a randomly colored slime when injected
+ with plasma. It's a good plan B if the slimes aren't cooperating in terms of
+ colors. You can get any color slime this way, pray to the RNG!
+ Xhuis:
+ - rscadd: The Sleeping Carp clan has made its presence known on Space Station 13.
+ Some gangs will name themselves after this group and practice martial arts rather
+ than using traditional gang weaponry. These shadowboxers are not to be taken
+ lightly.
+ oranges:
+ - tweak: Thanks to a breakthrough in directed vector thrusting, all nanotrasen brand
+ jetpacks have been greatly improved in speed and handling
+2015-07-01:
+ NullQuery:
+ - tweak: The crew monitoring computer, AI crew monitoring popup and the handheld
+ crew monitor now update automatically.
+ - tweak: 'Crew monitoring: The health information has been turned into a health
+ indicator. It goes from green to red. Hovering over the icon shows detailed
+ information (if available).'
+ - tweak: 'Crew monitoring: The location coordinates have been hidden. You can see
+ them by hovering over the ''Location'' column.'
+ - rscadd: 'Crew monitoring: A minimap has been added so you can easily see where
+ people are.'
+ - tweak: 'Crew monitoring: Players who are not in range of a camera are not shown
+ on the minimap.'
+ - tweak: 'Crew monitoring: AI players can quickly move to other locations or track
+ players by clicking the minimap or items in the table.'
+ - tweak: 'Crew monitoring: For AI players, health information always shows a white
+ indicator instead of green-to-red. This is a deliberate limitation to prevent
+ the AI from becoming too omnipresent.'
+ phil235:
+ - tweak: Space drug overdose no longer cause brute/brain damage but you hallucinate
+ more. Space Drug Blob now makes you hallucinate even if you don't overdose on
+ its space drug.
diff --git a/html/changelogs/Fayrik-TheNanoingFixes.yml b/html/changelogs/Fayrik-TheNanoingFixes.yml
deleted file mode 100644
index ee0cc06c287..00000000000
--- a/html/changelogs/Fayrik-TheNanoingFixes.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-author: Fayrik
-
-delete-after: True
-
-changes:
-- rscadd: "NanoUI is now Telekenesis aware, but due to other constraints, NanoUI interfaces are read only at a distance."
-- tweak: "Refactored all NanoUI interfaces to use a more universal proc."
-- tweak: "Adjusted the refresh time of the NanoUI SubSystem. All interfaces will update less, but register mouse clicks faster."
-- bugfix: "Removed automatic updates on atmospheric pumps, canisters and tanks, making them respond to button clicks much faster."
-- bugfix: "Atmos alarm reset buttons work now. Probably."
\ No newline at end of file
diff --git a/html/changelogs/RemieRichards-ArmourPenetration.yml b/html/changelogs/RemieRichards-ArmourPenetration.yml
deleted file mode 100644
index 7bbac062acf..00000000000
--- a/html/changelogs/RemieRichards-ArmourPenetration.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-author: RemieRichards
-
-delete-after: True
-
-changes:
- - tweak: "Cumulative armour damage resistance is now capped at 90%, you will now always take at bare minimum, 10% of the incoming damage."
- - rscadd: "Added a system for Armour Penetration to items, it works by temporarily (It does NOT damage the armour or anything) reducing the armour values by the AP value during the attack instance."
- - rscadd: "The formula for AP is Armour-ArmourPenetration = AdjustedArmour and AdjustedArmour is used for all the remaining calculations instead of Armour (Eg: 80 Melee - 15 AP = 65 Melee)."
- - rscadd: "The Ninja's Energy Katana has 15 AP, Xenomorphs have an inbuilt AP of 10."
\ No newline at end of file
diff --git a/html/changelogs/RemieRichards-PipePressureLethality.yml b/html/changelogs/RemieRichards-PipePressureLethality.yml
deleted file mode 100644
index 43ba4edfbd0..00000000000
--- a/html/changelogs/RemieRichards-PipePressureLethality.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-author: RemieRichards
-
-delete-after: True
-
-changes:
- - tweak: "You can now unwrench pipes who's internal pressures are greater than that of their environment..."
- - rscadd: "However it will throw you away from the pipe at extreme speed! (You are warned beforehand if the pipe will do this, allowing you to cancel)"
diff --git a/html/changelogs/jordie watchlist.yml b/html/changelogs/jordie watchlist.yml
deleted file mode 100644
index 34c7c4ede6a..00000000000
--- a/html/changelogs/jordie watchlist.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: Jordie0608
-
-delete-after: True
-
-changes:
- - rscadd: "Admins can now flag ckeys to be alerted when they connect to the server."
\ No newline at end of file
diff --git a/html/changelogs/vekter - 10092.yml b/html/changelogs/vekter - 10092.yml
deleted file mode 100644
index 2f6be0d85f2..00000000000
--- a/html/changelogs/vekter - 10092.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-author: Vekter
-
-delete-after: True
-
-changes:
- - bugfix: "Finally fixed immovable rods! They will now properly bisect the station (and crit anyone unlucky enough to be in their path)."
- - tweak: "Increased Meteor activity detected in the vicinity of the station. Be advised that many storms may be more violent than they once were."
- - rscadd: "Gravitational anomalies will now throw items at mobs in their vicinity. Take care while scanning them."
- - rscadd: "Flux anomalies explode much more violently now. Get there and destroy them, or risk losing half a department."
diff --git a/html/changelogs/xxalpha-fixfixfix.yml b/html/changelogs/xxalpha-fixfixfix.yml
deleted file mode 100644
index 8d94cfb1e84..00000000000
--- a/html/changelogs/xxalpha-fixfixfix.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-author: xxalpha
-
-delete-after: True
-
-changes:
- - rscadd: "Added a new Reviver implant: now it revives you from unconsciousness rather than death."
- - rscadd: "Added cybernetic implants and a cybernetic implants bundle to the Nuke Ops uplink."
- - bugfix: "Fixed Nutriment pump implant printing."
- - tweak: "Health Analyzers now have the ability to detect cybernetic implants."
- - tweak: "X-Ray implants are now much harder to unlock."
\ No newline at end of file
diff --git a/html/changelogs/xxalpha-niggastolemynuke.yml b/html/changelogs/xxalpha-niggastolemynuke.yml
new file mode 100644
index 00000000000..c16be2567cd
--- /dev/null
+++ b/html/changelogs/xxalpha-niggastolemynuke.yml
@@ -0,0 +1,6 @@
+author: xxalpha
+
+delete-after: True
+
+changes:
+ - rscadd: "Added a new traitor objective: steal the station's self-destruct nuke plutonium core."
\ No newline at end of file
diff --git a/html/mapbase1024.png b/html/mapbase1024.png
new file mode 100644
index 00000000000..a927a71b6e7
Binary files /dev/null and b/html/mapbase1024.png differ
diff --git a/icons/effects/crayondecal.dmi b/icons/effects/crayondecal.dmi
index 5525d3b1cbf..a7c84b45ba7 100644
Binary files a/icons/effects/crayondecal.dmi and b/icons/effects/crayondecal.dmi differ
diff --git a/icons/effects/doafter_icon.dmi b/icons/effects/doafter_icon.dmi
new file mode 100644
index 00000000000..0add263e976
Binary files /dev/null and b/icons/effects/doafter_icon.dmi differ
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 62170e230e6..5102b40d59e 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index a8e2032719a..a536f9f7919 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 6db0ab5709a..79dba919f26 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 83986fd1ae8..d0e6e69563b 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 3bbd054bce7..f4536caa9a3 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 3b14ad7d0cb..fded89b9805 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index 42e1b95b2c0..e44ddedfcd4 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi
index 8a22d33423e..517f220f2ba 100644
Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 647f1384e17..324c7d695b8 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/dropper.dmi b/icons/obj/dropper.dmi
deleted file mode 100644
index 40fa42fafd3..00000000000
Binary files a/icons/obj/dropper.dmi and /dev/null differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 787f929e923..194a21eecb6 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/machines/bignuke.dmi b/icons/obj/machines/bignuke.dmi
index 04b319c4748..336d5d8d390 100644
Binary files a/icons/obj/machines/bignuke.dmi and b/icons/obj/machines/bignuke.dmi differ
diff --git a/icons/obj/machines/nuke.dmi b/icons/obj/machines/nuke.dmi
new file mode 100644
index 00000000000..f0a5210d588
Binary files /dev/null and b/icons/obj/machines/nuke.dmi differ
diff --git a/icons/obj/nuke_tools.dmi b/icons/obj/nuke_tools.dmi
new file mode 100644
index 00000000000..4b604712a71
Binary files /dev/null and b/icons/obj/nuke_tools.dmi differ
diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi
index 594e646fa2d..52aea26c0cb 100644
Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ
diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi
index 52fefa673d1..d9be4abbce7 100644
Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index bd9e5cc7e60..47a2d13262c 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi
index 3624a9b4bff..c2f7bfcc202 100644
Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ
diff --git a/interface/interface.dm b/interface/interface.dm
index ffaeadc5776..a24e86cd3aa 100644
--- a/interface/interface.dm
+++ b/interface/interface.dm
@@ -171,4 +171,11 @@ Any-Mode: (hotkey doesn't need to be on)
"}
src << hotkey_mode
- src << other
\ No newline at end of file
+ src << other
+
+// Needed to circumvent a bug where .winset does not work when used on the window.on-size event in skins.
+// Used by /datum/html_interface/nanotrasen (code/modules/html_interface/nanotrasen/nanotrasen.dm)
+/client/verb/_swinset(var/x as text)
+ set name = ".swinset"
+ set hidden = 1
+ winset(src, null, x)
diff --git a/tgstation.dme b/tgstation.dme
index 98922e497d9..9bf9082b7a1 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -136,11 +136,13 @@
#include "code\controllers\subsystem\npcpool.dm"
#include "code\controllers\subsystem\objects.dm"
#include "code\controllers\subsystem\pai.dm"
+#include "code\controllers\subsystem\procqueue.dm"
#include "code\controllers\subsystem\radio.dm"
#include "code\controllers\subsystem\server_maintenance.dm"
#include "code\controllers\subsystem\shuttles.dm"
#include "code\controllers\subsystem\sun.dm"
#include "code\controllers\subsystem\ticker.dm"
+#include "code\controllers\subsystem\timer.dm"
#include "code\controllers\subsystem\voting.dm"
#include "code\controllers\subsystem\shuttles\emergency.dm"
#include "code\controllers\subsystem\shuttles\supply.dm"
@@ -154,6 +156,7 @@
#include "code\datums\hud.dm"
#include "code\datums\martial.dm"
#include "code\datums\mind.dm"
+#include "code\datums\mineral_container.dm"
#include "code\datums\modules.dm"
#include "code\datums\mutations.dm"
#include "code\datums\recipe.dm"
@@ -328,6 +331,7 @@
#include "code\game\gamemodes\extended\extended.dm"
#include "code\game\gamemodes\gang\dominator.dm"
#include "code\game\gamemodes\gang\gang.dm"
+#include "code\game\gamemodes\gang\gang_pen.dm"
#include "code\game\gamemodes\gang\recaller.dm"
#include "code\game\gamemodes\malfunction\Malf_Modules.dm"
#include "code\game\gamemodes\malfunction\malfunction.dm"
@@ -565,6 +569,7 @@
#include "code\game\objects\items\documents.dm"
#include "code\game\objects\items\holotape.dm"
#include "code\game\objects\items\latexballoon.dm"
+#include "code\game\objects\items\nuke_tools.dm"
#include "code\game\objects\items\shooting_range.dm"
#include "code\game\objects\items\toys.dm"
#include "code\game\objects\items\trash.dm"
@@ -1025,8 +1030,13 @@
#include "code\modules\food&drinks\recipes\tablecraft\recipes_sandwich.dm"
#include "code\modules\food&drinks\recipes\tablecraft\recipes_soup.dm"
#include "code\modules\food&drinks\recipes\tablecraft\recipes_spaghetti.dm"
+#include "code\modules\games\cards.dm"
#include "code\modules\holiday\easter.dm"
#include "code\modules\holiday\holidays.dm"
+#include "code\modules\html_interface\html_interface.dm"
+#include "code\modules\html_interface\html_interface_client.dm"
+#include "code\modules\html_interface\cards\cards.dm"
+#include "code\modules\html_interface\nanotrasen\nanotrasen.dm"
#include "code\modules\hydroponics\biogenerator.dm"
#include "code\modules\hydroponics\grown.dm"
#include "code\modules\hydroponics\growninedible.dm"
@@ -1038,6 +1048,7 @@
#include "code\modules\library\lib_machines.dm"
#include "code\modules\library\lib_readme.dm"
#include "code\modules\lighting\lighting_system.dm"
+#include "code\modules\mining\abandoned_crates.dm"
#include "code\modules\mining\equipment_locker.dm"
#include "code\modules\mining\machine_input_output_plates.dm"
#include "code\modules\mining\machine_processing.dm"
diff --git a/tools/mapmerge/MapPatcher.jar b/tools/mapmerge/MapMerge.jar
similarity index 72%
rename from tools/mapmerge/MapPatcher.jar
rename to tools/mapmerge/MapMerge.jar
index 5cbaad488c1..aa4a779ca5d 100644
Binary files a/tools/mapmerge/MapPatcher.jar and b/tools/mapmerge/MapMerge.jar differ
diff --git a/tools/mapmerge/prepare_map.bat b/tools/mapmerge/Prepare Maps.bat
similarity index 73%
rename from tools/mapmerge/prepare_map.bat
rename to tools/mapmerge/Prepare Maps.bat
index bfe1e6560e9..89e5a233ed2 100644
--- a/tools/mapmerge/prepare_map.bat
+++ b/tools/mapmerge/Prepare Maps.bat
@@ -7,6 +7,6 @@ cls
echo All dmm files in map_files directories have been backed up
echo Now you can make your changes...
echo ---
-echo Remember to run clean_map.bat just before you commit your changes!
+echo Remember to run Run_Map_Merge.bat just before you commit your changes!
echo ---
pause
diff --git a/tools/mapmerge/Run Map Merge.bat b/tools/mapmerge/Run Map Merge.bat
new file mode 100644
index 00000000000..2793b28a6b5
--- /dev/null
+++ b/tools/mapmerge/Run Map Merge.bat
@@ -0,0 +1,5 @@
+@echo off
+
+java -jar ../../tools/mapmerge/MapMerge.jar
+
+pause
\ No newline at end of file
diff --git a/tools/mapmerge/Source/.classpath b/tools/mapmerge/Source/.classpath
new file mode 100644
index 00000000000..a0cb530fa9d
--- /dev/null
+++ b/tools/mapmerge/Source/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tools/mapmerge/Source/.project b/tools/mapmerge/Source/.project
new file mode 100644
index 00000000000..df472fbdf11
--- /dev/null
+++ b/tools/mapmerge/Source/.project
@@ -0,0 +1,17 @@
+
+
+ MapMerger
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/tools/mapmerge/Source/.settings/org.eclipse.jdt.core.prefs b/tools/mapmerge/Source/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..3a21537071b
--- /dev/null
+++ b/tools/mapmerge/Source/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/tools/mapmerge/Source/META-INF/MANIFEST.MF b/tools/mapmerge/Source/META-INF/MANIFEST.MF
deleted file mode 100644
index 5aa53c2fa28..00000000000
--- a/tools/mapmerge/Source/META-INF/MANIFEST.MF
+++ /dev/null
@@ -1,4 +0,0 @@
-Manifest-Version: 1.0
-Created-By: 1.6.0_31 (Sun Microsystems Inc.)
-Main-Class: MapPatcher
-
diff --git a/tools/mapmerge/Source/bin/FileFinder.class b/tools/mapmerge/Source/bin/FileFinder.class
new file mode 100644
index 00000000000..ab01a656c45
Binary files /dev/null and b/tools/mapmerge/Source/bin/FileFinder.class differ
diff --git a/tools/mapmerge/Source/bin/MapMergerMain.class b/tools/mapmerge/Source/bin/MapMergerMain.class
new file mode 100644
index 00000000000..c563253301f
Binary files /dev/null and b/tools/mapmerge/Source/bin/MapMergerMain.class differ
diff --git a/tools/mapmerge/Source/src/FileFinder.java b/tools/mapmerge/Source/src/FileFinder.java
new file mode 100644
index 00000000000..0677b777843
--- /dev/null
+++ b/tools/mapmerge/Source/src/FileFinder.java
@@ -0,0 +1,25 @@
+import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+
+public class FileFinder extends SimpleFileVisitor {
+ private PathMatcher matcher;
+ public ArrayList foundPaths = new ArrayList<>();
+ public FileFinder(String pattern) {
+ matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Path name = file.getFileName();
+ if (matcher.matches(name)) {
+ foundPaths.add(file);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+}
\ No newline at end of file
diff --git a/tools/mapmerge/Source/src/MapMergerMain.java b/tools/mapmerge/Source/src/MapMergerMain.java
new file mode 100644
index 00000000000..0f38cc91ea5
--- /dev/null
+++ b/tools/mapmerge/Source/src/MapMergerMain.java
@@ -0,0 +1,57 @@
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+public class MapMergerMain {
+
+ private static Scanner input = new Scanner(System.in);
+
+ public static void main(String[] args) throws IOException{
+
+ System.out.print("Path to _maps folder: ");
+ String pathTo_maps = input.nextLine();
+ Path fileDir = Paths.get(pathTo_maps);
+ FileFinder finder = new FileFinder("*.dmm");
+ Files.walkFileTree(fileDir, finder);
+ ArrayList foundFiles = finder.foundPaths;
+ if (foundFiles.size() > 0) {
+ for(int num = 0;num < foundFiles.size();num++){
+ System.out.println(num + ": " + foundFiles.get(num));
+ }
+ }else{
+ System.out.println("No files were found!");
+ }
+ System.out.print("File to use: ");
+ int selection;
+ inputCheck:while(true){
+ while(!input.hasNextInt()){
+ String temp = input.next();
+ System.out.println(temp + " is not a valid int.");
+ }
+ selection = input.nextInt();
+ if(selection < 0 || selection >= foundFiles.size()){
+ if(selection < 0){
+ System.out.println("Use a number greater than 0!");
+ }else{
+ System.out.println("Use a number less than " + foundFiles.size() +"!");
+ }
+ continue inputCheck;
+ }else{
+ break inputCheck;
+ }
+ }
+
+ String newMap = foundFiles.get(selection) + "";
+ String oldMap = foundFiles.get(selection) + ".backup";
+ String[] passInto = new String[4];
+ passInto[0] = "-clean";
+ passInto[1] = oldMap;
+ passInto[2] = newMap;
+ passInto[3] = newMap;
+ MapPatcher.main(passInto);
+ }
+
+}
\ No newline at end of file
diff --git a/tools/mapmerge/Source/Location.java b/tools/mapmerge/Source/src/MapPatcher/Location.java
similarity index 100%
rename from tools/mapmerge/Source/Location.java
rename to tools/mapmerge/Source/src/MapPatcher/Location.java
diff --git a/tools/mapmerge/Source/Map.java b/tools/mapmerge/Source/src/MapPatcher/Map.java
similarity index 100%
rename from tools/mapmerge/Source/Map.java
rename to tools/mapmerge/Source/src/MapPatcher/Map.java
diff --git a/tools/mapmerge/Source/MapPatcher.java b/tools/mapmerge/Source/src/MapPatcher/MapPatcher.java
similarity index 100%
rename from tools/mapmerge/Source/MapPatcher.java
rename to tools/mapmerge/Source/src/MapPatcher/MapPatcher.java
diff --git a/tools/mapmerge/Source/SavingThread.java b/tools/mapmerge/Source/src/MapPatcher/SavingThread.java
similarity index 100%
rename from tools/mapmerge/Source/SavingThread.java
rename to tools/mapmerge/Source/src/MapPatcher/SavingThread.java
diff --git a/tools/mapmerge/clean_map.bat b/tools/mapmerge/clean_map.bat
deleted file mode 100644
index 8e1c9273d53..00000000000
--- a/tools/mapmerge/clean_map.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-@echo off
-cd ../../_maps/map_files/
-set /P MAPFILE=Please enter mapfile (relative to map_files folder):
-
-java -jar ../../tools/mapmerge/MapPatcher.jar -clean "%MAPFILE%.backup" "%MAPFILE%" "%MAPFILE%"
-
-pause
\ No newline at end of file
diff --git a/tools/mapmerge/install.txt b/tools/mapmerge/install.txt
deleted file mode 100644
index c225e68d706..00000000000
--- a/tools/mapmerge/install.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-1. Install java(http://www.java.com/en/download/index.jsp)
-2. Make sure java is in your PATH. To test this, open git bash, and type "java". If it says unknown command, you need to add JAVA/bin to your PATH variable (A guide for this can be found at https://www.java.com/en/download/help/path.xml ).
-
-Committing
-1. Before starting to edit the map, double-click "prepare_map.bat" in the tools/mapmerge/ directory.
-2. After finishing your edit, and before your commit, double-click "clean_map.bat" in the tools/mapmerge/ directory.
-
-This will make sure in the new version of your map, no paths are needlessly changed, thus instead of 8000 lines changed you'll get 50 lines changed. This not only reduces size of your commit, it also makes it possible to get an overview of your map changes on the "files changed" page in your pull request.
-
-Merging
-The easiest way to do merging is to install the merge driver. For this, you can just double-click "install_driver.bat" in the tools/mapmerge/ directory.
-
-Alternatively, open -tg-station/.git/config in a text editor, and paste the following lines to the end of it:
-
-[merge "merge-dmm"]
- name = mapmerge driver
- driver = ./tools/mapmerge/mapmerge.sh %O %A %B
-
-After this, merging maps should happen automagically unless there are conflicts(a tile that both you and someone else changed). If there are conflicts, you will unfortunately still be stuck with opening both versions in a map editor, and manually resolving the issues.
diff --git a/tools/mapmerge/install_driver.bat b/tools/mapmerge/install_driver.bat
deleted file mode 100644
index fa04dddff55..00000000000
--- a/tools/mapmerge/install_driver.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-@echo off
-echo. >> ../../.git/config
-echo [merge "merge-dmm"] >> ../../.git/config
-echo name = mapmerge driver >> ../../.git/config
-echo driver = ./tools/mapmerge/mapmerge.sh %O %A %B >> ../../.git/config
-echo. >> ../../.git/config
-
diff --git a/tools/mapmerge/mapmerge.sh b/tools/mapmerge/mapmerge.sh
deleted file mode 100644
index 145537f7ca7..00000000000
--- a/tools/mapmerge/mapmerge.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-java -jar tools/mapmerge/MapPatcher.jar -merge $1 $2 $3 $2
-if [ "$?" -gt 0 ]
-then
- echo "Unable to automatically resolve map conflicts, please merge manually."
- exit 1
-fi
-java -jar tools/mapmerge/MapPatcher.jar -clean $1 $2 $2
-
-exit 0