diff --git a/baystation12.dme b/baystation12.dme
index 92d393a37e..a8eeac7aed 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -622,7 +622,6 @@
#include "code\game\objects\items\stacks\nanopaste.dm"
#include "code\game\objects\items\stacks\rods.dm"
#include "code\game\objects\items\stacks\stack.dm"
-#include "code\game\objects\items\stacks\sheets\glass.dm"
#include "code\game\objects\items\stacks\sheets\leather.dm"
#include "code\game\objects\items\stacks\sheets\light.dm"
#include "code\game\objects\items\stacks\tiles\light.dm"
diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm
index f6d2481468..922275bcc9 100644
--- a/code/ZAS/Controller.dm
+++ b/code/ZAS/Controller.dm
@@ -281,8 +281,8 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
var/direct = !(block & ZONE_BLOCKED)
var/space = !istype(B)
- if(!space)
- if(min(A.zone.contents.len, B.zone.contents.len) < ZONE_MIN_SIZE || (direct && (equivalent_pressure(A.zone,B.zone) || current_cycle == 0)))
+ if(direct && !space)
+ if(min(A.zone.contents.len, B.zone.contents.len) <= ZONE_MIN_SIZE || equivalent_pressure(A.zone,B.zone) || current_cycle == 0)
merge(A.zone,B.zone)
return
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index e5e9370da3..fac5c75fc3 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -29,7 +29,7 @@
*/
-datum/mind
+/datum/mind
var/key
var/name //replaces mob/var/original_name
var/mob/living/current
@@ -58,459 +58,389 @@ datum/mind
// the world.time since the mob has been brigged, or -1 if not at all
var/brigged_since = -1
- New(var/key)
- src.key = key
-
//put this here for easier tracking ingame
var/datum/money_account/initial_account
- proc/transfer_to(mob/living/new_character)
- if(!istype(new_character))
- world.log << "## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn"
- if(current) //remove ourself from our old body's mind variable
- if(changeling)
- current.remove_changeling_powers()
- current.verbs -= /datum/changeling/proc/EvolutionMenu
- current.mind = null
+/datum/mind/New(var/key)
+ src.key = key
- nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
- if(new_character.mind) //remove any mind currently in our new body's mind variable
- new_character.mind.current = null
-
- current = new_character //link ourself to our new body
- new_character.mind = src //and link our new body to ourself
+/datum/mind/proc/transfer_to(mob/living/new_character)
+ if(!istype(new_character))
+ world.log << "## DEBUG: transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob. Please inform Carn"
+ if(current) //remove ourself from our old body's mind variable
if(changeling)
- new_character.make_changeling()
+ current.remove_changeling_powers()
+ current.verbs -= /datum/changeling/proc/EvolutionMenu
+ current.mind = null
- if(active)
- new_character.key = key //now transfer the key to link the client to our new body
+ nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
+ if(new_character.mind) //remove any mind currently in our new body's mind variable
+ new_character.mind.current = null
- proc/store_memory(new_text)
- memory += "[new_text]
"
+ current = new_character //link ourself to our new body
+ new_character.mind = src //and link our new body to ourself
- proc/show_memory(mob/recipient)
- var/output = "[current.real_name]'s Memory
"
- output += memory
+ if(changeling)
+ new_character.make_changeling()
- if(objectives.len>0)
- output += "
Objectives:"
+ if(active)
+ new_character.key = key //now transfer the key to link the client to our new body
- var/obj_count = 1
- for(var/datum/objective/objective in objectives)
- output += "Objective #[obj_count]: [objective.explanation_text]"
- obj_count++
+/datum/mind/proc/store_memory(new_text)
+ memory += "[new_text]
"
- recipient << browse(output,"window=memory")
+/datum/mind/proc/show_memory(mob/recipient)
+ var/output = "[current.real_name]'s Memory
"
+ output += memory
- proc/edit_memory()
- if(!ticker || !ticker.mode)
- alert("Not before round-start!", "Alert")
- return
+ if(objectives.len>0)
+ output += "
Objectives:"
- var/out = "[name][(current&&(current.real_name!=name))?" (as [current.real_name])":""]
"
- out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
"
- out += "Assigned role: [assigned_role]. Edit
"
- out += "
"
- out += "Factions and special roles:
"
- for(var/antag_type in all_antag_types)
- var/datum/antagonist/antag = all_antag_types[antag_type]
- out += "[antag.get_panel_entry(src)]"
- out += "
"
- out += "Objectives"
+ var/obj_count = 1
+ for(var/datum/objective/objective in objectives)
+ output += "Objective #[obj_count]: [objective.explanation_text]"
+ obj_count++
- if(objectives && objectives.len)
- var/num = 1
- for(var/datum/objective/O in objectives)
- out += "Objective #[num]: [O.explanation_text] "
- if(O.completed)
- out += "(complete)"
- else
- out += "(incomplete)"
- out += " \[toggle\]"
- out += " \[remove\]
"
- num++
- out += "
\[announce objectives\]"
+ recipient << browse(output,"window=memory")
- else
- out += "None."
- out += "
\[add\]"
- usr << browse(out, "window=edit_memory[src]")
+/datum/mind/proc/edit_memory()
+ if(!ticker || !ticker.mode)
+ alert("Not before round-start!", "Alert")
+ return
- Topic(href, href_list)
- if(!check_rights(R_ADMIN)) return
+ var/out = "[name][(current&&(current.real_name!=name))?" (as [current.real_name])":""]
"
+ out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
"
+ out += "Assigned role: [assigned_role]. Edit
"
+ out += "
"
+ out += "Factions and special roles:
"
+ for(var/antag_type in all_antag_types)
+ var/datum/antagonist/antag = all_antag_types[antag_type]
+ out += "[antag.get_panel_entry(src)]"
+ out += "
"
+ out += "Objectives"
- if(href_list["add_antagonist"])
- var/datum/antagonist/antag = all_antag_types[href_list["add_antagonist"]]
- if(antag) antag.add_antagonist(src)
-
- else if(href_list["remove_antagonist"])
- var/datum/antagonist/antag = all_antag_types[href_list["remove_antagonist"]]
- if(antag) antag.remove_antagonist(src)
-
- else if(href_list["equip_antagonist"])
- var/datum/antagonist/antag = all_antag_types[href_list["equip_antagonist"]]
- if(antag) antag.equip(src.current)
-
- else if(href_list["unequip_antagonist"])
- var/datum/antagonist/antag = all_antag_types[href_list["unequip_antagonist"]]
- if(antag) antag.unequip(src.current)
-
- else if(href_list["move_antag_to_spawn"])
- var/datum/antagonist/antag = all_antag_types[href_list["move_antag_to_spawn"]]
- if(antag) antag.place_mob(src.current)
-
- else if (href_list["role_edit"])
- var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in joblist
- if (!new_role) return
- assigned_role = new_role
-
- else if (href_list["memory_edit"])
- var/new_memo = sanitize(input("Write new memory", "Memory", memory) as null|message)
- if (isnull(new_memo)) return
- memory = new_memo
-
- else if (href_list["obj_edit"] || href_list["obj_add"])
- var/datum/objective/objective
- var/objective_pos
- var/def_value
-
- if (href_list["obj_edit"])
- objective = locate(href_list["obj_edit"])
- if (!objective) return
- objective_pos = objectives.Find(objective)
-
- //Text strings are easy to manipulate. Revised for simplicity.
- var/temp_obj_type = "[objective.type]"//Convert path into a text string.
- def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
- if(!def_value)//If it's a custom objective, it will be an empty string.
- def_value = "custom"
-
- var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "mercenary", "capture", "absorb", "custom")
- if (!new_obj_type) return
-
- var/datum/objective/new_objective = null
-
- switch (new_obj_type)
- if ("assassinate","protect","debrain", "harm", "brig")
- //To determine what to name the objective in explanation text.
- var/objective_type_capital = uppertext(copytext(new_obj_type, 1,2))//Capitalize first letter.
- var/objective_type_text = copytext(new_obj_type, 2)//Leave the rest of the text.
- var/objective_type = "[objective_type_capital][objective_type_text]"//Add them together into a text string.
-
- var/list/possible_targets = list("Free objective")
- for(var/datum/mind/possible_target in ticker.minds)
- if ((possible_target != src) && istype(possible_target.current, /mob/living/carbon/human))
- possible_targets += possible_target.current
-
- var/mob/def_target = null
- var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain)
- if (objective&&(objective.type in objective_list) && objective:target)
- def_target = objective:target.current
-
- var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
- if (!new_target) return
-
- var/objective_path = text2path("/datum/objective/[new_obj_type]")
- if (new_target == "Free objective")
- new_objective = new objective_path
- new_objective.owner = src
- new_objective:target = null
- new_objective.explanation_text = "Free objective"
- else
- new_objective = new objective_path
- new_objective.owner = src
- new_objective:target = new_target:mind
- //Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
- new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role=="MODE" ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
-
- if ("prevent")
- new_objective = new /datum/objective/block
- new_objective.owner = src
-
- if ("hijack")
- new_objective = new /datum/objective/hijack
- new_objective.owner = src
-
- if ("escape")
- new_objective = new /datum/objective/escape
- new_objective.owner = src
-
- if ("survive")
- new_objective = new /datum/objective/survive
- new_objective.owner = src
-
- if ("mercenary")
- new_objective = new /datum/objective/nuclear
- new_objective.owner = src
-
- if ("steal")
- if (!istype(objective, /datum/objective/steal))
- new_objective = new /datum/objective/steal
- new_objective.owner = src
- else
- new_objective = objective
- var/datum/objective/steal/steal = new_objective
- if (!steal.select_target())
- return
-
- if("download","capture","absorb")
- var/def_num
- if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]"))
- def_num = objective.target_amount
-
- var/target_number = input("Input target number:", "Objective", def_num) as num|null
- if (isnull(target_number))//Ordinarily, you wouldn't need isnull. In this case, the value may already exist.
- return
-
- switch(new_obj_type)
- if("download")
- new_objective = new /datum/objective/download
- new_objective.explanation_text = "Download [target_number] research levels."
- if("capture")
- new_objective = new /datum/objective/capture
- new_objective.explanation_text = "Accumulate [target_number] capture points."
- if("absorb")
- new_objective = new /datum/objective/absorb
- new_objective.explanation_text = "Absorb [target_number] compatible genomes."
- new_objective.owner = src
- new_objective.target_amount = target_number
-
- if ("custom")
- var/expl = sanitize(input("Custom objective:", "Objective", objective ? objective.explanation_text : "") as text|null)
- if (!expl) return
- new_objective = new /datum/objective
- new_objective.owner = src
- new_objective.explanation_text = expl
-
- if (!new_objective) return
-
- if (objective)
- objectives -= objective
- objectives.Insert(objective_pos, new_objective)
+ if(objectives && objectives.len)
+ var/num = 1
+ for(var/datum/objective/O in objectives)
+ out += "Objective #[num]: [O.explanation_text] "
+ if(O.completed)
+ out += "(complete)"
else
- objectives += new_objective
+ out += "(incomplete)"
+ out += " \[toggle\]"
+ out += " \[remove\]
"
+ num++
+ out += "
\[announce objectives\]"
- else if (href_list["obj_delete"])
- var/datum/objective/objective = locate(href_list["obj_delete"])
- if(!istype(objective)) return
- objectives -= objective
+ else
+ out += "None."
+ out += "
\[add\]"
+ usr << browse(out, "window=edit_memory[src]")
- else if(href_list["obj_completed"])
- var/datum/objective/objective = locate(href_list["obj_completed"])
- if(!istype(objective)) return
- objective.completed = !objective.completed
+/datum/mind/Topic(href, href_list)
+ if(!check_rights(R_ADMIN)) return
- else if(href_list["implant"])
- var/mob/living/carbon/human/H = current
+ if(href_list["add_antagonist"])
+ var/datum/antagonist/antag = all_antag_types[href_list["add_antagonist"]]
+ if(antag) antag.add_antagonist(src)
- BITSET(H.hud_updateflag, IMPLOYAL_HUD) // updates that players HUD images so secHUD's pick up they are implanted or not.
+ else if(href_list["remove_antagonist"])
+ var/datum/antagonist/antag = all_antag_types[href_list["remove_antagonist"]]
+ if(antag) antag.remove_antagonist(src)
- switch(href_list["implant"])
- if("remove")
- for(var/obj/item/weapon/implant/loyalty/I in H.contents)
- for(var/obj/item/organ/external/organs in H.organs)
- if(I in organs.implants)
- qdel(I)
- break
- H << "Your loyalty implant has been deactivated."
- log_admin("[key_name_admin(usr)] has de-loyalty implanted [current].")
- if("add")
- H << "You somehow have become the recepient of a loyalty transplant, and it just activated!"
- H.implant_loyalty(H, override = TRUE)
- log_admin("[key_name_admin(usr)] has loyalty implanted [current].")
+ else if(href_list["equip_antagonist"])
+ var/datum/antagonist/antag = all_antag_types[href_list["equip_antagonist"]]
+ if(antag) antag.equip(src.current)
+
+ else if(href_list["unequip_antagonist"])
+ var/datum/antagonist/antag = all_antag_types[href_list["unequip_antagonist"]]
+ if(antag) antag.unequip(src.current)
+
+ else if(href_list["move_antag_to_spawn"])
+ var/datum/antagonist/antag = all_antag_types[href_list["move_antag_to_spawn"]]
+ if(antag) antag.place_mob(src.current)
+
+ else if (href_list["role_edit"])
+ var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in joblist
+ if (!new_role) return
+ assigned_role = new_role
+
+ else if (href_list["memory_edit"])
+ var/new_memo = sanitize(input("Write new memory", "Memory", memory) as null|message)
+ if (isnull(new_memo)) return
+ memory = new_memo
+
+ else if (href_list["obj_edit"] || href_list["obj_add"])
+ var/datum/objective/objective
+ var/objective_pos
+ var/def_value
+
+ if (href_list["obj_edit"])
+ objective = locate(href_list["obj_edit"])
+ if (!objective) return
+ objective_pos = objectives.Find(objective)
+
+ //Text strings are easy to manipulate. Revised for simplicity.
+ var/temp_obj_type = "[objective.type]"//Convert path into a text string.
+ def_value = copytext(temp_obj_type, 19)//Convert last part of path into an objective keyword.
+ if(!def_value)//If it's a custom objective, it will be an empty string.
+ def_value = "custom"
+
+ var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "debrain", "protect", "prevent", "harm", "brig", "hijack", "escape", "survive", "steal", "download", "mercenary", "capture", "absorb", "custom")
+ if (!new_obj_type) return
+
+ var/datum/objective/new_objective = null
+
+ switch (new_obj_type)
+ if ("assassinate","protect","debrain", "harm", "brig")
+ //To determine what to name the objective in explanation text.
+ var/objective_type_capital = uppertext(copytext(new_obj_type, 1,2))//Capitalize first letter.
+ var/objective_type_text = copytext(new_obj_type, 2)//Leave the rest of the text.
+ var/objective_type = "[objective_type_capital][objective_type_text]"//Add them together into a text string.
+
+ var/list/possible_targets = list("Free objective")
+ for(var/datum/mind/possible_target in ticker.minds)
+ if ((possible_target != src) && istype(possible_target.current, /mob/living/carbon/human))
+ possible_targets += possible_target.current
+
+ var/mob/def_target = null
+ var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain)
+ if (objective&&(objective.type in objective_list) && objective:target)
+ def_target = objective:target.current
+
+ var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
+ if (!new_target) return
+
+ var/objective_path = text2path("/datum/objective/[new_obj_type]")
+ if (new_target == "Free objective")
+ new_objective = new objective_path
+ new_objective.owner = src
+ new_objective:target = null
+ new_objective.explanation_text = "Free objective"
else
- /*
- else if (href_list["monkey"])
- var/mob/living/L = current
- if (L.transforming)
- return
- switch(href_list["monkey"])
- if("healthy")
- if (usr.client.holder.rights & R_ADMIN)
- var/mob/living/carbon/human/H = current
- var/mob/living/carbon/monkey/M = current
- if (istype(H))
- log_admin("[key_name(usr)] attempting to monkeyize [key_name(current)]")
- message_admins("[key_name_admin(usr)] attempting to monkeyize [key_name_admin(current)]")
- src = null
- M = H.monkeyize()
- src = M.mind
- //world << "DEBUG: \"healthy\": M=[M], M.mind=[M.mind], src=[src]!"
- else if (istype(M) && length(M.viruses))
- for(var/datum/disease/D in M.viruses)
- D.cure(0)
- sleep(0) //because deleting of virus is done through spawn(0)
- if("infected")
- if (usr.client.holder.rights & R_ADMIN)
- var/mob/living/carbon/human/H = current
- var/mob/living/carbon/monkey/M = current
- if (istype(H))
- log_admin("[key_name(usr)] attempting to monkeyize and infect [key_name(current)]")
- message_admins("[key_name_admin(usr)] attempting to monkeyize and infect [key_name_admin(current)]", 1)
- src = null
- M = H.monkeyize()
- src = M.mind
- current.contract_disease(new /datum/disease/jungle_fever,1,0)
- else if (istype(M))
- current.contract_disease(new /datum/disease/jungle_fever,1,0)
- if("human")
- var/mob/living/carbon/monkey/M = current
- if (istype(M))
- for(var/datum/disease/D in M.viruses)
- if (istype(D,/datum/disease/jungle_fever))
- D.cure(0)
- sleep(0) //because deleting of virus is doing throught spawn(0)
- log_admin("[key_name(usr)] attempting to humanize [key_name(current)]")
- message_admins("[key_name_admin(usr)] attempting to humanize [key_name_admin(current)]")
- var/obj/item/weapon/dnainjector/m2h/m2h = new
- var/obj/item/weapon/implant/mobfinder = new(M) //hack because humanizing deletes mind --rastaf0
- src = null
- m2h.inject(M)
- src = mobfinder.loc:mind
- qdel(mobfinder)
- current.radiation -= 50
- */
- else if (href_list["silicon"])
- BITSET(current.hud_updateflag, SPECIALROLE_HUD)
- switch(href_list["silicon"])
+ new_objective = new objective_path
+ new_objective.owner = src
+ new_objective:target = new_target:mind
+ //Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
+ new_objective.explanation_text = "[objective_type] [new_target:real_name], the [new_target:mind:assigned_role=="MODE" ? (new_target:mind:special_role) : (new_target:mind:assigned_role)]."
- if("unemag")
- var/mob/living/silicon/robot/R = current
- if (istype(R))
+ if ("prevent")
+ new_objective = new /datum/objective/block
+ new_objective.owner = src
+
+ if ("hijack")
+ new_objective = new /datum/objective/hijack
+ new_objective.owner = src
+
+ if ("escape")
+ new_objective = new /datum/objective/escape
+ new_objective.owner = src
+
+ if ("survive")
+ new_objective = new /datum/objective/survive
+ new_objective.owner = src
+
+ if ("mercenary")
+ new_objective = new /datum/objective/nuclear
+ new_objective.owner = src
+
+ if ("steal")
+ if (!istype(objective, /datum/objective/steal))
+ new_objective = new /datum/objective/steal
+ new_objective.owner = src
+ else
+ new_objective = objective
+ var/datum/objective/steal/steal = new_objective
+ if (!steal.select_target())
+ return
+
+ if("download","capture","absorb")
+ var/def_num
+ if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]"))
+ def_num = objective.target_amount
+
+ var/target_number = input("Input target number:", "Objective", def_num) as num|null
+ if (isnull(target_number))//Ordinarily, you wouldn't need isnull. In this case, the value may already exist.
+ return
+
+ switch(new_obj_type)
+ if("download")
+ new_objective = new /datum/objective/download
+ new_objective.explanation_text = "Download [target_number] research levels."
+ if("capture")
+ new_objective = new /datum/objective/capture
+ new_objective.explanation_text = "Accumulate [target_number] capture points."
+ if("absorb")
+ new_objective = new /datum/objective/absorb
+ new_objective.explanation_text = "Absorb [target_number] compatible genomes."
+ new_objective.owner = src
+ new_objective.target_amount = target_number
+
+ if ("custom")
+ var/expl = sanitize(input("Custom objective:", "Objective", objective ? objective.explanation_text : "") as text|null)
+ if (!expl) return
+ new_objective = new /datum/objective
+ new_objective.owner = src
+ new_objective.explanation_text = expl
+
+ if (!new_objective) return
+
+ if (objective)
+ objectives -= objective
+ objectives.Insert(objective_pos, new_objective)
+ else
+ objectives += new_objective
+
+ else if (href_list["obj_delete"])
+ var/datum/objective/objective = locate(href_list["obj_delete"])
+ if(!istype(objective)) return
+ objectives -= objective
+
+ else if(href_list["obj_completed"])
+ var/datum/objective/objective = locate(href_list["obj_completed"])
+ if(!istype(objective)) return
+ objective.completed = !objective.completed
+
+ else if(href_list["implant"])
+ var/mob/living/carbon/human/H = current
+
+ BITSET(H.hud_updateflag, IMPLOYAL_HUD) // updates that players HUD images so secHUD's pick up they are implanted or not.
+
+ switch(href_list["implant"])
+ if("remove")
+ for(var/obj/item/weapon/implant/loyalty/I in H.contents)
+ for(var/obj/item/organ/external/organs in H.organs)
+ if(I in organs.implants)
+ qdel(I)
+ break
+ H << "Your loyalty implant has been deactivated."
+ log_admin("[key_name_admin(usr)] has de-loyalty implanted [current].")
+ if("add")
+ H << "You somehow have become the recepient of a loyalty transplant, and it just activated!"
+ H.implant_loyalty(H, override = TRUE)
+ log_admin("[key_name_admin(usr)] has loyalty implanted [current].")
+ else
+ else if (href_list["silicon"])
+ BITSET(current.hud_updateflag, SPECIALROLE_HUD)
+ switch(href_list["silicon"])
+
+ if("unemag")
+ var/mob/living/silicon/robot/R = current
+ if (istype(R))
+ R.emagged = 0
+ if (R.activated(R.module.emag))
+ R.module_active = null
+ if(R.module_state_1 == R.module.emag)
+ R.module_state_1 = null
+ R.contents -= R.module.emag
+ else if(R.module_state_2 == R.module.emag)
+ R.module_state_2 = null
+ R.contents -= R.module.emag
+ else if(R.module_state_3 == R.module.emag)
+ R.module_state_3 = null
+ R.contents -= R.module.emag
+ log_admin("[key_name_admin(usr)] has unemag'ed [R].")
+
+ if("unemagcyborgs")
+ if (istype(current, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/ai = current
+ for (var/mob/living/silicon/robot/R in ai.connected_robots)
R.emagged = 0
- if (R.activated(R.module.emag))
- R.module_active = null
- if(R.module_state_1 == R.module.emag)
- R.module_state_1 = null
- R.contents -= R.module.emag
- else if(R.module_state_2 == R.module.emag)
- R.module_state_2 = null
- R.contents -= R.module.emag
- else if(R.module_state_3 == R.module.emag)
- R.module_state_3 = null
- R.contents -= R.module.emag
- log_admin("[key_name_admin(usr)] has unemag'ed [R].")
+ if (R.module)
+ if (R.activated(R.module.emag))
+ R.module_active = null
+ if(R.module_state_1 == R.module.emag)
+ R.module_state_1 = null
+ R.contents -= R.module.emag
+ else if(R.module_state_2 == R.module.emag)
+ R.module_state_2 = null
+ R.contents -= R.module.emag
+ else if(R.module_state_3 == R.module.emag)
+ R.module_state_3 = null
+ R.contents -= R.module.emag
+ log_admin("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.")
- if("unemagcyborgs")
- if (istype(current, /mob/living/silicon/ai))
- var/mob/living/silicon/ai/ai = current
- for (var/mob/living/silicon/robot/R in ai.connected_robots)
- R.emagged = 0
- if (R.module)
- if (R.activated(R.module.emag))
- R.module_active = null
- if(R.module_state_1 == R.module.emag)
- R.module_state_1 = null
- R.contents -= R.module.emag
- else if(R.module_state_2 == R.module.emag)
- R.module_state_2 = null
- R.contents -= R.module.emag
- else if(R.module_state_3 == R.module.emag)
- R.module_state_3 = null
- R.contents -= R.module.emag
- log_admin("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.")
-
- else if (href_list["common"])
- switch(href_list["common"])
- if("undress")
- for(var/obj/item/W in current)
- current.drop_from_inventory(W)
- if("takeuplink")
- take_uplink()
- memory = null//Remove any memory they may have had.
- if("crystals")
- if (usr.client.holder.rights & R_FUN)
- var/obj/item/device/uplink/hidden/suplink = find_syndicate_uplink()
- var/crystals
+ else if (href_list["common"])
+ switch(href_list["common"])
+ if("undress")
+ for(var/obj/item/W in current)
+ current.drop_from_inventory(W)
+ if("takeuplink")
+ take_uplink()
+ memory = null//Remove any memory they may have had.
+ if("crystals")
+ if (usr.client.holder.rights & R_FUN)
+ var/obj/item/device/uplink/hidden/suplink = find_syndicate_uplink()
+ var/crystals
+ if (suplink)
+ crystals = suplink.uses
+ crystals = input("Amount of telecrystals for [key]","Operative uplink", crystals) as null|num
+ if (!isnull(crystals))
if (suplink)
- crystals = suplink.uses
- crystals = input("Amount of telecrystals for [key]","Operative uplink", crystals) as null|num
- if (!isnull(crystals))
- if (suplink)
- suplink.uses = crystals
+ suplink.uses = crystals
- else if (href_list["obj_announce"])
- var/obj_count = 1
- current << "Your current objectives:"
- for(var/datum/objective/objective in objectives)
- current << "Objective #[obj_count]: [objective.explanation_text]"
- obj_count++
- edit_memory()
-/*
- proc/clear_memory(var/silent = 1)
- var/datum/game_mode/current_mode = ticker.mode
+ else if (href_list["obj_announce"])
+ var/obj_count = 1
+ current << "\blue Your current objectives:"
+ for(var/datum/objective/objective in objectives)
+ current << "Objective #[obj_count]: [objective.explanation_text]"
+ obj_count++
+ edit_memory()
- // remove traitor uplinks
- var/list/L = current.get_contents()
- for (var/t in L)
- if (istype(t, /obj/item/device/pda))
- if (t:uplink) qdel(t:uplink)
- t:uplink = null
- else if (istype(t, /obj/item/device/radio))
- if (t:traitorradio) qdel(t:traitorradio)
- t:traitorradio = null
- t:traitor_frequency = 0.0
- else if (istype(t, /obj/item/weapon/SWF_uplink) || istype(t, /obj/item/weapon/syndicate_uplink))
- if (t:origradio)
- var/obj/item/device/radio/R = t:origradio
- R.loc = current.loc
- R.traitorradio = null
- R.traitor_frequency = 0.0
- qdel(t)
+/datum/mind/proc/find_syndicate_uplink()
+ var/list/L = current.get_contents()
+ for (var/obj/item/I in L)
+ if (I.hidden_uplink)
+ return I.hidden_uplink
+ return null
- // remove wizards spells
- //If there are more special powers that need removal, they can be procced into here./N
- current.spellremove(current)
-
- // clear memory
- memory = ""
- special_role = null
-
-*/
-
- proc/find_syndicate_uplink()
- var/list/L = current.get_contents()
- for (var/obj/item/I in L)
- if (I.hidden_uplink)
- return I.hidden_uplink
- return null
-
- proc/take_uplink()
- var/obj/item/device/uplink/hidden/H = find_syndicate_uplink()
- if(H)
- qdel(H)
+/datum/mind/proc/take_uplink()
+ var/obj/item/device/uplink/hidden/H = find_syndicate_uplink()
+ if(H)
+ qdel(H)
- // check whether this mind's mob has been brigged for the given duration
- // have to call this periodically for the duration to work properly
- proc/is_brigged(duration)
- var/turf/T = current.loc
- if(!istype(T))
- brigged_since = -1
- return 0
-
- var/is_currently_brigged = 0
-
- if(istype(T.loc,/area/security/brig))
- is_currently_brigged = 1
- for(var/obj/item/weapon/card/id/card in current)
+// check whether this mind's mob has been brigged for the given duration
+// have to call this periodically for the duration to work properly
+/datum/mind/proc/is_brigged(duration)
+ var/turf/T = current.loc
+ if(!istype(T))
+ brigged_since = -1
+ return 0
+ var/is_currently_brigged = 0
+ if(istype(T.loc,/area/security/brig))
+ is_currently_brigged = 1
+ for(var/obj/item/weapon/card/id/card in current)
+ is_currently_brigged = 0
+ break // if they still have ID they're not brigged
+ for(var/obj/item/device/pda/P in current)
+ if(P.id)
is_currently_brigged = 0
break // if they still have ID they're not brigged
- for(var/obj/item/device/pda/P in current)
- if(P.id)
- is_currently_brigged = 0
- break // if they still have ID they're not brigged
- if(!is_currently_brigged)
- brigged_since = -1
- return 0
+ if(!is_currently_brigged)
+ brigged_since = -1
+ return 0
- if(brigged_since == -1)
- brigged_since = world.time
+ if(brigged_since == -1)
+ brigged_since = world.time
- return (duration <= world.time - brigged_since)
+ return (duration <= world.time - brigged_since)
+/datum/mind/proc/reset()
+ assigned_role = null
+ special_role = null
+ role_alt_title = null
+ assigned_job = null
+ //faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know.
+ changeling = null
+ initial_account = null
+ objectives = list()
+ special_verbs = list()
+ has_been_rev = 0
+ rev_cooldown = 0
+ brigged_since = -1
//Antagonist role check
/mob/living/proc/check_special_role(role)
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index d8c776bc36..8f048db043 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -130,11 +130,11 @@
/mob/living/silicon/ai/proc/ai_camera_track(var/target_name in trackable_mobs())
set category = "AI Commands"
- set name = "Track With Camera"
+ set name = "Follow With Camera"
set desc = "Select who you would like to track."
if(src.stat == 2)
- src << "You can't track with camera because you are dead!"
+ src << "You can't follow [target_name] with cameras because you are dead!"
return
if(!target_name)
src.cameraFollow = null
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index 3ea9b5157f..56b7b241c1 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -393,9 +393,9 @@
occupant.ckey = null
//Make an announcement and log the person entering storage.
- control_computer.frozen_crew += "[occupant.real_name], [occupant.mind.assigned_role] - [worldtime2text()]"
+ control_computer.frozen_crew += "[occupant.real_name], [occupant.mind.role_alt_title] - [worldtime2text()]"
- announce.autosay("[occupant.real_name], [occupant.mind.assigned_role] [on_store_message]", "[on_store_name]")
+ announce.autosay("[occupant.real_name], [occupant.mind.role_alt_title], [on_store_message]", "[on_store_name]")
visible_message("\The [initial(name)] hums and hisses as it moves [occupant.real_name] into storage.", 3)
// Delete the mob.
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 0570211526..55cf5cdc15 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -123,6 +123,15 @@ Class Procs:
/obj/machinery/Destroy()
machines -= src
+ if(component_parts)
+ for(var/atom/A in component_parts)
+ if(A.loc == src) // If the components are inside the machine, delete them.
+ qdel(A)
+ else // Otherwise we assume they were dropped to the ground during deconstruction, and were not removed from the component_parts list by deconstruction code.
+ component_parts -= A
+ if(contents) // The same for contents.
+ for(var/atom/A in contents)
+ qdel(A)
..()
/obj/machinery/process()//If you dont use process or power why are you here
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index d302738176..fbdb7667a1 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -1058,6 +1058,21 @@ var/global/list/obj/item/device/pda/PDAs = list()
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")
new_message = 1
+/obj/item/device/pda/verb/verb_reset_pda()
+ set category = "Object"
+ set name = "Reset PDA"
+ set src in usr
+
+ if(issilicon(usr))
+ return
+
+ if(can_use(usr))
+ mode = 0
+ nanomanager.update_uis(src)
+ usr << "You press the reset button on \the [src]."
+ else
+ usr << "You cannot do this while restrained."
+
/obj/item/device/pda/verb/verb_remove_id()
set category = "Object"
set name = "Remove id"
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
index d51a9a1e3b..7c21c9e9f5 100644
--- a/code/game/objects/items/weapons/tools.dm
+++ b/code/game/objects/items/weapons/tools.dm
@@ -262,6 +262,8 @@
//Removes fuel from the welding tool. If a mob is passed, it will perform an eyecheck on the mob. This should probably be renamed to use()
/obj/item/weapon/weldingtool/proc/remove_fuel(var/amount = 1, var/mob/M = null)
+ if(!welding)
+ return 0
if(get_fuel() >= amount)
reagents.remove_reagent("fuel", amount)
if(M)
@@ -292,7 +294,7 @@
var/turf/T = get_turf(src)
//If we're turning it on
if(set_welding && !welding)
- if (remove_fuel(1))
+ if (get_fuel() > 0)
if(M)
M << "You switch the [src] on."
else if(T)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 7d2ca17eb9..68aeecd912 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -220,8 +220,11 @@
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.remove_fuel(0,user))
- user << "You need more welding fuel to complete this task."
- return
+ if(!WT.isOn())
+ return
+ else
+ user << "You need more welding fuel to complete this task."
+ return
new /obj/item/stack/material/steel(src.loc)
for(var/mob/M in viewers(src))
M.show_message("\The [src] has been cut apart by [user] with \the [WT].", 3, "You hear welding.", 2)
@@ -239,8 +242,11 @@
else if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.remove_fuel(0,user))
- user << "You need more welding fuel to complete this task."
- return
+ if(!WT.isOn())
+ return
+ else
+ user << "You need more welding fuel to complete this task."
+ return
src.welded = !src.welded
src.update_icon()
for(var/mob/M in viewers(src))
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index cc154918e6..008d86d8ad 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -111,9 +111,12 @@
"You have [anchored ? "fastened the grille to" : "unfastened the grill from"] the floor.")
return
-//window placing begin
- else if(istype(W,/obj/item/stack/material/glass))
- var/obj/item/stack/material/glass/ST = W
+//window placing begin //TODO CONVERT PROPERLY TO MATERIAL DATUM
+ else if(istype(W,/obj/item/stack/material))
+ var/obj/item/stack/material/ST = W
+ if(!ST.material.created_window)
+ return 0
+
var/dir_to_set = 1
if(loc == user.loc)
dir_to_set = user.dir
@@ -143,7 +146,7 @@
user << "There is already a window facing this way there."
return
- var/wtype = ST.created_window
+ var/wtype = ST.material.created_window
if (ST.use(1))
var/obj/structure/window/WD = new wtype(loc, dir_to_set, 1)
user << "You place the [WD] on [src]."
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index ef4fa997c8..b415a317fc 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -177,6 +177,10 @@ var/list/admin_verbs_debug = list(
/client/proc/toggledebuglogs,
/client/proc/SDQL_query,
/client/proc/SDQL2_query,
+ /client/proc/Jump,
+ /client/proc/jumptomob,
+ /client/proc/jumptocoord,
+ /client/proc/dsay
)
var/list/admin_verbs_paranoid_debug = list(
diff --git a/code/modules/admin/player_notes.dm b/code/modules/admin/player_notes.dm
index a00a208d3b..c5a54694c8 100644
--- a/code/modules/admin/player_notes.dm
+++ b/code/modules/admin/player_notes.dm
@@ -27,26 +27,6 @@ datum/admins/proc/notes_gethtml(var/ckey)
. += "[dir]
"
return
-
-//handles adding notes to the end of a ckey's buffer
-//originally had seperate entries such as var/by to record who left the note and when
-//but the current bansystem is a heap of dung.
-/proc/notes_add(var/ckey, var/note)
- if(!ckey)
- ckey = ckey(input(usr,"Who would you like to add notes for?","Enter a ckey",null) as text|null)
- if(!ckey) return
-
- if(!note)
- note = html_encode(input(usr,"Enter your note:","Enter some text",null) as message|null)
- if(!note) return
-
- var/savefile/notesfile = new(NOTESFILE)
- if(!notesfile) return
- notesfile.cd = "/[ckey]"
- notesfile.eof = 1 //move to the end of the buffer
- notesfile << "[time2text(world.realtime,"DD-MMM-YYYY")] | [note][(usr && usr.ckey)?" ~[usr.ckey]":""]"
- return
-
//handles removing entries from the buffer, or removing the entire directory if no start_index is given
/proc/notes_remove(var/ckey, var/start_index, var/end_index)
var/savefile/notesfile = new(NOTESFILE)
@@ -85,7 +65,7 @@ datum/admins/proc/notes_gethtml(var/ckey)
//Hijacking this file for BS12 playernotes functions. I like this ^ one systemm alright, but converting sounds too bothersome~ Chinsky.
-/proc/notes_add(var/key, var/note, var/mob/usr)
+/proc/notes_add(var/key, var/note, var/mob/user)
if (!key || !note)
return
@@ -111,9 +91,9 @@ datum/admins/proc/notes_gethtml(var/ckey)
var/day_loc = findtext(full_date, time2text(world.timeofday, "DD"))
var/datum/player_info/P = new
- if (usr)
- P.author = usr.key
- P.rank = usr.client.holder.rank
+ if (user)
+ P.author = user.key
+ P.rank = user.client.holder.rank
else
P.author = "Adminbot"
P.rank = "Friendly Robot"
@@ -123,8 +103,8 @@ datum/admins/proc/notes_gethtml(var/ckey)
infos += P
info << infos
- message_admins("\blue [key_name_admin(usr)] has edited [key]'s notes.")
- log_admin("[key_name(usr)] has edited [key]'s notes.")
+ message_admins("\blue [key_name_admin(user)] has edited [key]'s notes.")
+ log_admin("[key_name(user)] has edited [key]'s notes.")
qdel(info)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 65d466164b..38dfc463b3 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -85,6 +85,7 @@
banreason = "[banreason] (CUSTOM CID)"
else
message_admins("Ban process: A mob matching [playermob.ckey] was found at location [playermob.x], [playermob.y], [playermob.z]. Custom ip and computer id fields replaced with the ip and computer id from the located mob")
+ notes_add(playermob.ckey,banreason,usr)
DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey, banip, bancid )
@@ -671,7 +672,7 @@
msg = job
else
msg += ", [job]"
- notes_add(M.ckey, "Banned from [msg] - [reason]")
+ notes_add(M.ckey, "Banned from [msg] - [reason]", usr)
message_admins("\blue [key_name_admin(usr)] banned [key_name_admin(M)] from [msg] for [mins] minutes", 1)
M << "\redYou have been jobbanned by [usr.client.ckey] from: [msg]."
M << "\red The reason is: [reason]"
@@ -692,7 +693,7 @@
jobban_fullban(M, job, "[reason]; By [usr.ckey] on [time2text(world.realtime)]")
if(!msg) msg = job
else msg += ", [job]"
- notes_add(M.ckey, "Banned from [msg] - [reason]")
+ notes_add(M.ckey, "Banned from [msg] - [reason]", usr)
message_admins("\blue [key_name_admin(usr)] banned [key_name_admin(M)] from [msg]", 1)
M << "\redYou have been jobbanned by [usr.client.ckey] from: [msg]."
M << "\red The reason is: [reason]"
@@ -746,25 +747,7 @@
message_admins("\blue [key_name_admin(usr)] booted [key_name_admin(M)].", 1)
//M.client = null
qdel(M.client)
-/*
- //Player Notes
- else if(href_list["notes"])
- var/ckey = href_list["ckey"]
- if(!ckey)
- var/mob/M = locate(href_list["mob"])
- if(ismob(M))
- ckey = M.ckey
- switch(href_list["notes"])
- if("show")
- notes_show(ckey)
- if("add")
- notes_add(ckey,href_list["text"])
- notes_show(ckey)
- if("remove")
- notes_remove(ckey,text2num(href_list["from"]),text2num(href_list["to"]))
- notes_show(ckey)
-*/
else if(href_list["removejobban"])
if(!check_rights(R_BAN)) return
@@ -799,6 +782,7 @@
return
AddBan(M.ckey, M.computer_id, reason, usr.ckey, 1, mins)
ban_unban_log_save("[usr.client.ckey] has banned [M.ckey]. - Reason: [reason] - This will be removed in [mins] minutes.")
+ notes_add(M.ckey,"[usr.client.ckey] has banned [M.ckey]. - Reason: [reason] - This will be removed in [mins] minutes.",usr)
M << "\redYou have been banned by [usr.client.ckey].\nReason: [reason]."
M << "\red This is a temporary ban, it will be removed in [mins] minutes."
feedback_inc("ban_tmp",1)
@@ -831,6 +815,7 @@
else
M << "\red No ban appeals URL has been set."
ban_unban_log_save("[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a permanent ban.")
+ notes_add(M.ckey,"[usr.client.ckey] has permabanned [M.ckey]. - Reason: [reason] - This is a permanent ban.",usr)
log_admin("[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.")
message_admins("\blue[usr.client.ckey] has banned [M.ckey].\nReason: [reason]\nThis is a permanent ban.")
feedback_inc("ban_perma",1)
diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm
index e84543e88f..e579ca1544 100644
--- a/code/modules/admin/verbs/adminjump.dm
+++ b/code/modules/admin/verbs/adminjump.dm
@@ -8,8 +8,7 @@
set name = "Jump to Area"
set desc = "Area to jump to"
set category = "Admin"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
@@ -25,8 +24,7 @@
/client/proc/jumptoturf(var/turf/T in world)
set name = "Jump to Turf"
set category = "Admin"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
log_admin("[key_name(usr)] jumped to [T.x],[T.y],[T.z] in [T.loc]")
@@ -42,8 +40,7 @@
set category = "Admin"
set name = "Jump to Mob"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
@@ -65,8 +62,7 @@
set category = "Admin"
set name = "Jump to Coordinate"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if (config.allow_admin_jump)
@@ -86,8 +82,7 @@
set category = "Admin"
set name = "Jump to Key"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
@@ -111,8 +106,7 @@
set category = "Admin"
set name = "Get Mob"
set desc = "Mob to teleport"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
log_admin("[key_name(usr)] teleported [key_name(M)]")
@@ -128,8 +122,7 @@
set name = "Get Key"
set desc = "Key to teleport"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
if(config.allow_admin_jump)
@@ -155,8 +148,7 @@
/client/proc/sendmob(var/mob/M in sortmobs())
set category = "Admin"
set name = "Send Mob"
- if(!check_rights(R_ADMIN))
- usr << "Only administrators may use this command."
+ if(!check_rights(R_ADMIN|R_MOD|R_DEBUG))
return
var/area/A = input(usr, "Pick an area.", "Pick an area") in return_sorted_areas()
if(A)
diff --git a/code/modules/admin/verbs/deadsay.dm b/code/modules/admin/verbs/deadsay.dm
index b3b6e3fdae..9739d0bed4 100644
--- a/code/modules/admin/verbs/deadsay.dm
+++ b/code/modules/admin/verbs/deadsay.dm
@@ -18,16 +18,7 @@
if (src.handle_spam_prevention(msg,MUTE_DEADCHAT))
return
- var/stafftype = null
-
- if (src.holder.rights & R_MOD)
- stafftype = "MOD"
-
- if (src.holder.rights & R_MENTOR)
- stafftype = "MENTOR"
-
- if (src.holder.rights & R_ADMIN)
- stafftype = "ADMIN"
+ var/stafftype = uppertext(holder.rank)
msg = sanitize(msg)
log_admin("[key_name(src)] : [msg]")
diff --git a/code/modules/hydroponics/_hydro_setup.dm b/code/modules/hydroponics/_hydro_setup.dm
index a3fd4604a6..4641aa3ace 100644
--- a/code/modules/hydroponics/_hydro_setup.dm
+++ b/code/modules/hydroponics/_hydro_setup.dm
@@ -55,4 +55,5 @@
#define TRAIT_PRODUCT_COLOUR 35
#define TRAIT_BIOLUM 36
#define TRAIT_BIOLUM_COLOUR 37
-#define TRAIT_IMMUTABLE 38
\ No newline at end of file
+#define TRAIT_IMMUTABLE 38
+#define TRAIT_FLESH_COLOUR 39
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index c2a06af587..977059ab95 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -167,8 +167,8 @@
return
/obj/item/weapon/reagent_containers/food/snacks/grown/throw_impact(atom/hit_atom)
- ..()
if(seed) seed.thrown_at(src,hit_atom)
+ ..()
/obj/item/weapon/reagent_containers/food/snacks/grown/attackby(var/obj/item/weapon/W, var/mob/user)
@@ -194,9 +194,11 @@
else if(seed.chems)
if(istype(W,/obj/item/weapon/material/hatchet) && !isnull(seed.chems["woodpulp"]))
user.show_message("You make planks out of \the [src]!", 1)
+ var/flesh_colour = seed.get_trait(TRAIT_FLESH_COLOUR)
+ if(!flesh_colour) flesh_colour = seed.get_trait(TRAIT_PRODUCT_COLOUR)
for(var/i=0,i<2,i++)
var/obj/item/stack/material/wood/NG = new (user.loc)
- NG.color = seed.get_trait(TRAIT_PRODUCT_COLOUR)
+ if(flesh_colour) NG.color = flesh_colour
for (var/obj/item/stack/material/wood/G in user.loc)
if(G==NG)
continue
@@ -221,6 +223,15 @@
new /obj/item/weapon/reagent_containers/food/snacks/soydope(get_turf(src))
qdel(src)
return
+ else if(seed.get_trait(TRAIT_FLESH_COLOUR))
+ user << "You slice up \the [src]."
+ var/slices = rand(3,5)
+ var/reagents_to_transfer = round(reagents.total_volume/slices)
+ for(var/i=i;i<=slices;i++)
+ var/obj/item/weapon/reagent_containers/food/snacks/fruit_slice/F = new(get_turf(src),seed)
+ if(reagents_to_transfer) reagents.trans_to_obj(F,reagents_to_transfer)
+ qdel(src)
+ return
..()
/obj/item/weapon/reagent_containers/food/snacks/grown/attack(var/mob/living/carbon/M, var/mob/user, var/def_zone)
@@ -301,9 +312,11 @@
if(seed.kitchen_tag == "grass")
user.show_message("You make a grass tile out of \the [src]!", 1)
+ var/flesh_colour = seed.get_trait(TRAIT_FLESH_COLOUR)
+ if(!flesh_colour) flesh_colour = seed.get_trait(TRAIT_PRODUCT_COLOUR)
for(var/i=0,i<2,i++)
var/obj/item/stack/tile/grass/G = new (user.loc)
- G.color = seed.get_trait(TRAIT_PRODUCT_COLOUR)
+ if(flesh_colour) G.color = flesh_colour
for (var/obj/item/stack/tile/grass/NG in user.loc)
if(G==NG)
continue
@@ -358,3 +371,35 @@
/obj/item/weapon/reagent_containers/food/snacks/grown/ambrosiavulgaris
plantname = "ambrosia"
+
+/obj/item/weapon/reagent_containers/food/snacks/fruit_slice
+ name = "fruit slice"
+ desc = "A slice of some tasty fruit."
+ icon = 'icons/obj/hydroponics_misc.dmi'
+ icon_state = ""
+
+var/list/fruit_icon_cache = list()
+
+/obj/item/weapon/reagent_containers/food/snacks/fruit_slice/New(var/newloc, var/datum/seed/S)
+ ..(newloc)
+ // Need to go through and make a general image caching controller. Todo.
+ if(!istype(S))
+ qdel(src)
+ return
+
+ name = "[S.seed_name] slice"
+ desc = "A slice of \a [S.seed_name]. Tasty, probably."
+
+ var/rind_colour = S.get_trait(TRAIT_PRODUCT_COLOUR)
+ var/flesh_colour = S.get_trait(TRAIT_FLESH_COLOUR)
+ if(!flesh_colour) flesh_colour = rind_colour
+ if(!fruit_icon_cache["rind-[rind_colour]"])
+ var/image/I = image(icon,"fruit_rind")
+ I.color = rind_colour
+ fruit_icon_cache["rind-[rind_colour]"] = I
+ overlays |= fruit_icon_cache["rind-[rind_colour]"]
+ if(!fruit_icon_cache["slice-[rind_colour]"])
+ var/image/I = image(icon,"fruit_slice")
+ I.color = flesh_colour
+ fruit_icon_cache["slice-[rind_colour]"] = I
+ overlays |= fruit_icon_cache["slice-[rind_colour]"]
diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm
index 1cf969a090..d540d64b38 100644
--- a/code/modules/hydroponics/seed.dm
+++ b/code/modules/hydroponics/seed.dm
@@ -169,8 +169,9 @@
if(get_trait(TRAIT_BIOLUM_COLOUR))
clr = get_trait(TRAIT_BIOLUM_COLOUR)
splat.set_light(get_trait(TRAIT_BIOLUM), l_color = clr)
- if(get_trait(TRAIT_PRODUCT_COLOUR))
- splat.color = get_trait(TRAIT_PRODUCT_COLOUR)
+ var/flesh_colour = get_trait(TRAIT_FLESH_COLOUR)
+ if(!flesh_colour) flesh_colour = get_trait(TRAIT_PRODUCT_COLOUR)
+ if(flesh_colour) splat.color = get_trait(TRAIT_PRODUCT_COLOUR)
if(chems)
for(var/mob/living/M in T.contents)
@@ -229,7 +230,8 @@
for(var/mob/living/M in T.contents)
apply_special_effect(M)
splatter(T,thrown)
- origin_turf.visible_message("The [thrown.name] explodes!")
+ if(origin_turf)
+ origin_turf.visible_message("The [thrown.name] explodes!")
qdel(thrown)
return
@@ -242,7 +244,8 @@
if(get_trait(TRAIT_JUICY) && splatted)
splatter(origin_turf,thrown)
- origin_turf.visible_message("The [thrown.name] splatters against [target]!")
+ if(origin_turf)
+ origin_turf.visible_message("The [thrown.name] splatters against [target]!")
qdel(thrown)
/datum/seed/proc/handle_environment(var/turf/current_turf, var/datum/gas_mixture/environment, var/light_supplied, var/check_only)
@@ -637,7 +640,7 @@
if(GENE_STRUCTURE)
traits_to_copy = list(TRAIT_PLANT_ICON,TRAIT_PRODUCT_ICON,TRAIT_HARVEST_REPEAT)
if(GENE_FRUIT)
- traits_to_copy = list(TRAIT_STINGS,TRAIT_EXPLOSIVE,TRAIT_JUICY)
+ traits_to_copy = list(TRAIT_STINGS,TRAIT_EXPLOSIVE,TRAIT_FLESH_COLOUR,TRAIT_JUICY)
if(GENE_SPECIAL)
traits_to_copy = list(TRAIT_TELEPORTING)
diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm
index cfbf024eda..b8b0530788 100644
--- a/code/modules/hydroponics/seed_datums.dm
+++ b/code/modules/hydroponics/seed_datums.dm
@@ -244,6 +244,7 @@
set_trait(TRAIT_PRODUCT_ICON,"apple")
set_trait(TRAIT_PRODUCT_COLOUR,"#FF540A")
set_trait(TRAIT_PLANT_ICON,"tree2")
+ set_trait(TRAIT_FLESH_COLOUR,"#E8E39B")
/datum/seed/apple/poison
name = "poisonapple"
@@ -804,6 +805,7 @@
set_trait(TRAIT_PRODUCT_COLOUR,"#326B30")
set_trait(TRAIT_PLANT_COLOUR,"#257522")
set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_FLESH_COLOUR,"#F22C2C")
/datum/seed/pumpkin
name = "pumpkin"
@@ -842,6 +844,7 @@
set_trait(TRAIT_PRODUCT_ICON,"treefruit")
set_trait(TRAIT_PRODUCT_COLOUR,"#3AF026")
set_trait(TRAIT_PLANT_ICON,"tree")
+ set_trait(TRAIT_FLESH_COLOUR,"#3AF026")
/datum/seed/citrus/lemon
name = "lemon"
@@ -854,6 +857,7 @@
..()
set_trait(TRAIT_PRODUCES_POWER,1)
set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226")
+ set_trait(TRAIT_FLESH_COLOUR,"#F0E226")
/datum/seed/citrus/orange
name = "orange"
@@ -865,6 +869,7 @@
/datum/seed/citrus/orange/New()
..()
set_trait(TRAIT_PRODUCT_COLOUR,"#FFC20A")
+ set_trait(TRAIT_FLESH_COLOUR,"#FFC20A")
/datum/seed/grass
name = "grass"
diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm
index e62a96c2ce..87894c6d73 100644
--- a/code/modules/hydroponics/spreading/spreading.dm
+++ b/code/modules/hydroponics/spreading/spreading.dm
@@ -196,16 +196,19 @@
layer = 3
density = 0
-/obj/effect/plant/proc/calc_dir(turf/location = loc)
+/obj/effect/plant/proc/calc_dir()
set background = 1
+ var/turf/T = get_turf(src)
+ if(!istype(T)) return
+
var/direction = 16
for(var/wallDir in cardinal)
- var/turf/newTurf = get_step(location,wallDir)
+ var/turf/newTurf = get_step(T,wallDir)
if(newTurf.density)
direction |= wallDir
- for(var/obj/effect/plant/shroom in location)
+ for(var/obj/effect/plant/shroom in T.contents)
if(shroom == src)
continue
if(shroom.floor) //special
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index c41b6fc449..82d55960df 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -47,6 +47,19 @@
return 0
..(S,tamount,1)
+/obj/item/stack/material/attack_self(var/mob/user)
+ if(!material.build_windows(user, src))
+ ..()
+
+/obj/item/stack/material/attackby(var/obj/item/W, var/mob/user)
+ if(istype(W,/obj/item/stack/cable_coil))
+ material.build_wired_product(user, W, src)
+ return
+ else if(istype(W, /obj/item/stack/rods))
+ material.build_rod_product(user, W, src)
+ return
+ return ..()
+
/obj/item/stack/material/iron
name = "iron"
icon_state = "sheet-silver"
@@ -75,7 +88,7 @@
default_type = "phoron"
/obj/item/stack/material/plastic
- name = "Plastic"
+ name = "plastic"
icon_state = "sheet-plastic"
default_type = "plastic"
@@ -151,3 +164,27 @@
singular_name = "leather piece"
icon_state = "sheet-leather"
default_type = "leather"
+
+/obj/item/stack/material/glass
+ name = "glass"
+ singular_name = "glass sheet"
+ icon_state = "sheet-glass"
+ default_type = "glass"
+
+/obj/item/stack/material/glass/reinforced
+ name = "reinforced glass"
+ singular_name = "reinforced glass sheet"
+ icon_state = "sheet-rglass"
+ default_type = "reinforced glass"
+
+/obj/item/stack/material/glass/phoronglass
+ name = "phoron glass"
+ singular_name = "phoron glass sheet"
+ icon_state = "sheet-phoronglass"
+ default_type = "phoron glass"
+
+/obj/item/stack/material/glass/phoronrglass
+ name = "reinforced phoron glass"
+ singular_name = "reinforced phoron glass sheet"
+ icon_state = "sheet-phoronrglass"
+ default_type = "reinforced phoron glass"
diff --git a/code/modules/materials/material_synth.dm b/code/modules/materials/material_synth.dm
index a0977e69c5..23b0e7e546 100644
--- a/code/modules/materials/material_synth.dm
+++ b/code/modules/materials/material_synth.dm
@@ -13,20 +13,26 @@
matter = null
/obj/item/stack/material/cyborg/plastic
+ icon_state = "sheet-plastic"
default_type = "plastic"
/obj/item/stack/material/cyborg/steel
+ icon_state = "sheet-metal"
default_type = "steel"
/obj/item/stack/material/cyborg/plasteel
+ icon_state = "sheet-plasteel"
default_type = "plasteel"
/obj/item/stack/material/cyborg/wood
+ icon_state = "sheet-wood"
default_type = "wood"
/obj/item/stack/material/cyborg/glass
+ icon_state = "sheet-glass"
default_type = "glass"
/obj/item/stack/material/cyborg/glass/reinforced
+ icon_state = "sheet-rglass"
default_type = "reinforced glass"
charge_costs = list(500, 1000)
\ No newline at end of file
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index 7e0a8ef71a..802ac7ccc4 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -76,6 +76,12 @@ var/list/name_to_material
var/conductive = 1 // Objects with this var add CONDUCTS to flags on spawn.
var/list/composite_material // If set, object matter var will be a list containing these values.
+ // Placeholder vars for the time being, todo properly integrate windows/light tiles/rods.
+ var/created_window
+ var/rod_product
+ var/wire_product
+ var/list/window_options = list()
+
// Damage values.
var/hardness = 60 // Prob of wall destruction by hulk, used for edge damage in weapons.
var/weight = 20 // Determines blunt damage/throwforce for weapons.
@@ -89,6 +95,37 @@ var/list/name_to_material
// Wallrot crumble message.
var/rotting_touch_message = "crumbles under your touch"
+// Placeholders for light tiles and rglass.
+/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+ if(!rod_product)
+ user << "You cannot make anything out of \the [target_stack]"
+ return
+ if(used_stack.get_amount() < 1 || target_stack.get_amount() < 1)
+ user << "You need one rod and one sheet of [display_name] to make anything useful."
+ return
+ used_stack.use(1)
+ target_stack.use(1)
+ var/obj/item/stack/S = new rod_product(get_turf(user))
+ S.add_fingerprint(user)
+ S.add_to_stacks(user)
+ if(!(user.l_hand && user.r_hand))
+ user.put_in_hands(S)
+
+/material/proc/build_wired_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+ if(!wire_product)
+ user << "You cannot make anything out of \the [target_stack]"
+ return
+ if(used_stack.get_amount() < 5 || target_stack.get_amount() < 1)
+ user << "You need five wires and one sheet of [display_name] to make anything useful."
+ return
+
+ used_stack.use(5)
+ target_stack.use(1)
+ user << "You attach wire to the [name]."
+ var/obj/item/product = new wire_product(get_turf(user))
+ if(!(user.l_hand && user.r_hand))
+ user.put_in_hands(product)
+
// Make sure we have a display name and shard icon even if they aren't explicitly set.
/material/New()
..()
@@ -99,6 +136,10 @@ var/list/name_to_material
if(!shard_icon)
shard_icon = shard_type
+// This is a placeholder for proper integration of windows/windoors into the system.
+/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+ return 0
+
// Weapons handle applying a divisor for this value locally.
/material/proc/get_blunt_damage()
return weight //todo
@@ -271,7 +312,7 @@ var/list/name_to_material
hardness = 80
weight = 23
stack_origin_tech = list(TECH_MATERIAL = 2)
- composite_material = list() //todo
+ composite_material = list(DEFAULT_WALL_MATERIAL = 3750, "platinum" = 3750) //todo
/material/glass
name = "glass"
@@ -286,21 +327,82 @@ var/list/name_to_material
weight = 15
door_icon_base = "stone"
destruction_desc = "shatters"
+ window_options = list("One Direction", "Full Window")
+ created_window = /obj/structure/window/basic
+ wire_product = /obj/item/stack/light_w
+ rod_product = /obj/item/stack/material/glass/reinforced
-/material/glass/phoron
- name = "phoron glass"
- stack_type = /obj/item/stack/material/glass/phoronglass
- flags = MATERIAL_BRITTLE
- ignition_point = 300
- integrity = 200 // idk why but phoron windows are strong, so.
- icon_colour = "#FC2BC5"
- stack_origin_tech = list(TECH_MATERIAL = 3, TECH_PHORON = 2)
+/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
-/material/glass/phoron/reinforced
- name = "reinforced phoron glass"
- stack_type = /obj/item/stack/material/glass/phoronrglass
- stack_origin_tech = list(TECH_MATERIAL = 4, TECH_PHORON = 2)
- composite_material = list() //todo
+ if(!user || !used_stack || !created_window || !window_options.len)
+ return 0
+
+ if(!user.IsAdvancedToolUser())
+ user << "This task is too complex for your clumsy hands."
+ return 1
+
+ var/turf/T = user.loc
+ if(!istype(T))
+ user << "You must be standing on open flooring to build a window."
+ return 1
+
+ var/title = "Sheet-[used_stack.name] ([used_stack.get_amount()] sheet\s left)"
+ var/choice = input(title, "What would you like to construct?") as null|anything in window_options
+
+ if(!choice || !used_stack || !user || used_stack.loc != user || user.stat || user.loc != T)
+ return 1
+
+ // Get data for building windows here.
+ var/list/possible_directions = cardinal.Copy()
+ var/window_count = 0
+ for (var/obj/structure/window/check_window in user.loc)
+ window_count++
+ possible_directions -= check_window.dir
+
+ // Get the closest available dir to the user's current facing.
+ var/build_dir = SOUTHWEST //Default to southwest for fulltile windows.
+ var/failed_to_build
+
+ if(window_count >= 4)
+ failed_to_build = 1
+ else
+ if(choice in list("One Direction","Windoor"))
+ if(possible_directions.len)
+ for(var/direction in list(user.dir, turn(user.dir,90), turn(user.dir,180), turn(user.dir,270) ))
+ if(direction in possible_directions)
+ build_dir = direction
+ break
+ else
+ failed_to_build = 1
+ if(!failed_to_build && choice == "Windoor")
+ if(!is_reinforced())
+ user << "This material is not reinforced enough to use for a door."
+ return
+ if((locate(/obj/structure/windoor_assembly) in T.contents) || (locate(/obj/machinery/door/window) in T.contents))
+ failed_to_build = 1
+ if(failed_to_build)
+ user << "There is no room in this location."
+ return 1
+
+ var/build_path = /obj/structure/windoor_assembly
+ var/sheets_needed = 4
+ if(choice == "Windoor")
+ sheets_needed = 5
+ build_dir = user.dir
+ else
+ build_path = created_window
+
+ if(used_stack.get_amount() < sheets_needed)
+ user << "You need at least [sheets_needed] sheets to build this."
+ return 1
+
+ // Build the structure and update sheet count etc.
+ used_stack.use(sheets_needed)
+ new build_path(T, build_dir, 1)
+ return 1
+
+/material/glass/proc/is_reinforced()
+ return (hardness > 35) //todo
/material/glass/reinforced
name = "reinforced glass"
@@ -313,8 +415,36 @@ var/list/name_to_material
tableslam_noise = 'sound/effects/Glasshit.ogg'
hardness = 40
weight = 30
+ stack_origin_tech = "materials=2"
+ composite_material = list(DEFAULT_WALL_MATERIAL = 1875,"glass" = 3750)
+ window_options = list("One Direction", "Full Window", "Windoor")
+ created_window = /obj/structure/window/reinforced
+ wire_product = null
+ rod_product = null
+
+/material/glass/phoron
+ name = "phoron glass"
+ stack_type = /obj/item/stack/material/glass/phoronglass
+ flags = MATERIAL_BRITTLE
+ ignition_point = 300
+ integrity = 200 // idk why but phoron windows are strong, so.
+ icon_colour = "#FC2BC5"
+ stack_origin_tech = list(TECH_MATERIAL = 3, TECH_PHORON = 2)
+ created_window = /obj/structure/window/phoronbasic
+ wire_product = null
+ rod_product = /obj/item/stack/material/glass/phoronrglass
+
+/material/glass/phoron/reinforced
+ name = "reinforced phoron glass"
+ stack_type = /obj/item/stack/material/glass/phoronrglass
+ stack_origin_tech = list(TECH_MATERIAL = 4, TECH_PHORON = 2)
+ composite_material = list() //todo
+ created_window = /obj/structure/window/phoronreinforced
+ hardness = 40
+ weight = 30
stack_origin_tech = list(TECH_MATERIAL = 2)
composite_material = list() //todo
+ rod_product = null
/material/plastic
name = "plastic"
diff --git a/code/modules/mob/freelook/mask/update_triggers.dm b/code/modules/mob/freelook/mask/update_triggers.dm
index a8e68058fd..8100a309a2 100644
--- a/code/modules/mob/freelook/mask/update_triggers.dm
+++ b/code/modules/mob/freelook/mask/update_triggers.dm
@@ -35,7 +35,7 @@
cultnet.updateVisibility(src, 0)
/mob/living/death(gibbed, deathmessage="seizes up and falls limp...")
- if(..())
+ if(..(gibbed, deathmessage))
// If true, the mob went from living to dead (assuming everyone has been overriding as they should...)
cultnet.updateVisibility(src)
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
index 05da370fc8..9e3a127136 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -53,6 +53,29 @@
if(!searching || (src.brainmob && src.brainmob.key))
return
searching = 0
+/obj/item/device/mmi/digital/posibrain/proc/transfer_personality(var/mob/candidate)
+ announce_ghost_joinleave(candidate, 0, "They are occupying a positronic brain now.")
+ src.searching = 0
+ src.brainmob.mind = candidate.mind
+ src.brainmob.ckey = candidate.ckey
+ src.brainmob.mind.reset()
+ src.name = "positronic brain ([src.brainmob.name])"
+ src.brainmob << "You are a positronic brain, brought into existence on [station_name()]."
+ src.brainmob << "As a synthetic intelligence, you answer to all crewmembers, as well as the AI."
+ src.brainmob << "Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm."
+ src.brainmob << "Use say :b to speak to other artificial intelligences."
+ src.brainmob.mind.assigned_role = "Positronic Brain"
+
+ var/turf/T = get_turf_or_move(src.loc)
+ for (var/mob/M in viewers(T))
+ M.show_message("\blue The positronic brain chimes quietly.")
+ icon_state = "posibrain-occupied"
+
+/obj/item/device/mmi/digital/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
+
+ if(src.brainmob && src.brainmob.key) return
+
+ src.searching = 0
icon_state = "posibrain"
var/turf/T = get_turf(src)
T.visible_message("\The [src] brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?")
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index b0a27ad52f..9d54b25198 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -186,6 +186,19 @@
src.reset_view(C)
return 1
+/mob/living/silicon/pai/verb/reset_record_view()
+ set category = "pAI Commands"
+ set name = "Reset Records Software"
+
+ securityActive1 = null
+ securityActive2 = null
+ security_cannotfind = 0
+ medicalActive1 = null
+ medicalActive2 = null
+ medical_cannotfind = 0
+ nanomanager.update_uis(src)
+ usr << "You reset your record-viewing software."
+
/mob/living/silicon/pai/cancel_camera()
set category = "pAI Commands"
set name = "Cancel Camera View"
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index e2ec5059a2..4b33818033 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -295,7 +295,7 @@
if(!O.force)
visible_message("[user] gently taps [src] with \the [O].")
return
-
+
if(O.force > resistance)
var/damage = O.force
if (O.damtype == HALLOSS)
@@ -306,8 +306,8 @@
adjustBruteLoss(damage)
else
usr << "[src] has been attacked with the [O] by [user].")
+
+ visible_message("\The [src] has been attacked with the [O] by [user].")
user.do_attack_animation(src)
/mob/living/simple_animal/movement_delay()
@@ -327,10 +327,10 @@
if(statpanel("Status") && show_stat_health)
stat(null, "Health: [round((health / maxHealth) * 100)]%")
-/mob/living/simple_animal/death(gibbed, deathmessage="")
+/mob/living/simple_animal/death(gibbed, deathmessage = "dies!")
icon_state = icon_dead
density = 0
- return ..()
+ return ..(gibbed,deathmessage)
/mob/living/simple_animal/ex_act(severity)
if(!blinded)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 2264f60a54..83ae948ef3 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -376,7 +376,8 @@
return
M.key = key
-// M.Login() //wat
+ if(M.mind)
+ M.mind.reset()
return
/client/verb/changes()
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index e6add5089c..e778c42fcf 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -26,6 +26,27 @@ var/list/organ_cache = list()
var/datum/dna/dna
var/datum/species/species
+/obj/item/organ/Destroy()
+ if(!owner)
+ return ..()
+
+ if((owner.internal_organs) && (src in owner.internal_organs))
+ owner.internal_organs -= src
+
+ if((owner.internal_organs_by_name) && (src in owner.internal_organs_by_name))
+ owner.internal_organs_by_name -= src
+
+ if((owner.organs) && (src in owner.organs))
+ owner.organs -= src
+
+ if((owner.organs_by_name) && (src in owner.organs_by_name))
+ owner.organs_by_name -= src
+
+ if(src in owner.contents)
+ owner.contents -= src
+
+ return ..()
+
/obj/item/organ/proc/update_health()
return
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index cd44a09eeb..a4ab332221 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -51,6 +51,20 @@
var/can_grasp
var/can_stand
+/obj/item/organ/external/Destroy()
+ if(parent && parent.children)
+ parent.children -= src
+
+ if(children)
+ for(var/obj/item/organ/external/C in children)
+ qdel(C)
+
+ if(internal_organs)
+ for(var/obj/item/organ/O in internal_organs)
+ qdel(O)
+
+ return ..()
+
/obj/item/organ/external/attack_self(var/mob/user)
if(!contents.len)
return ..()
diff --git a/code/modules/power/breaker_box.dm b/code/modules/power/breaker_box.dm
index 2faa50a4e6..5930dd53e7 100644
--- a/code/modules/power/breaker_box.dm
+++ b/code/modules/power/breaker_box.dm
@@ -19,6 +19,11 @@
var/RCon_tag = "NO_TAG"
var/update_locked = 0
+/obj/machinery/power/breakerbox/Destroy()
+ ..()
+ for(var/obj/nano_module/rcon/R in world)
+ R.FindDevices()
+
/obj/machinery/power/breakerbox/activated
icon_state = "bbox_on"
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index 3b9d094bda..7d51af8e35 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -17,6 +17,8 @@
/obj/machinery/power/Destroy()
disconnect_from_network()
+ disconnect_terminal()
+
..()
///////////////////////////////
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index 6c64730eb6..5ce02cf18d 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -84,10 +84,12 @@
return
-/obj/machinery/power/smes/Destroy()
+/obj/machinery/power/smes/disconnect_terminal()
if(terminal)
- disconnect_terminal()
- ..()
+ terminal.master = null
+ terminal = null
+ return 1
+ return 0
/obj/machinery/power/smes/update_icon()
overlays.Cut()
diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm
index 94e628bad9..36924d9ae7 100644
--- a/code/modules/power/smes_construction.dm
+++ b/code/modules/power/smes_construction.dm
@@ -75,6 +75,13 @@
charge = 0
should_be_mapped = 1
+/obj/machinery/power/smes/buildable/Destroy()
+ ..()
+ qdel(wires)
+ for(var/obj/nano_module/rcon/R in world)
+ R.FindDevices()
+
+
// Proc: process()
// Parameters: None
// Description: Uses parent process, but if grounding wire is cut causes sparks to fly around.
@@ -343,6 +350,7 @@
M.icon_state = "box_1"
for(var/obj/I in component_parts)
I.loc = src.loc
+ component_parts -= I
qdel(src)
return
diff --git a/icons/mob/species/unathi/tail.dmi b/icons/mob/species/unathi/tail.dmi
index 97ae78393a..eba37dba6a 100644
Binary files a/icons/mob/species/unathi/tail.dmi and b/icons/mob/species/unathi/tail.dmi differ
diff --git a/icons/obj/hydroponics_misc.dmi b/icons/obj/hydroponics_misc.dmi
new file mode 100644
index 0000000000..a5c594d93f
Binary files /dev/null and b/icons/obj/hydroponics_misc.dmi differ
diff --git a/icons/turf/wall_masks.dmi b/icons/turf/wall_masks.dmi
index c7fd0f0e81..0094e605b8 100644
Binary files a/icons/turf/wall_masks.dmi and b/icons/turf/wall_masks.dmi differ
diff --git a/tools/dmitool/dmitool.jar b/tools/dmitool/dmitool.jar
index 34bdb5bdd4..c7df4d8b7f 100644
Binary files a/tools/dmitool/dmitool.jar and b/tools/dmitool/dmitool.jar differ
diff --git a/tools/dmitool/dmitool.py b/tools/dmitool/dmitool.py
new file mode 100644
index 0000000000..390f0d745f
--- /dev/null
+++ b/tools/dmitool/dmitool.py
@@ -0,0 +1,94 @@
+""" Python 2.7 wrapper for dmitool.
+"""
+
+import os
+from subprocess import Popen, PIPE
+
+_JAVA_PATH = ["java"]
+_DMITOOL_CMD = ["-jar", "dmitool.jar"]
+
+def _dmitool_call(*dmitool_args, **popen_args):
+ return Popen(_JAVA_PATH + _DMITOOL_CMD + [str(arg) for arg in dmitool_args], **popen_args)
+
+def _safe_parse(dict, key, deferred_value):
+ try:
+ dict[key] = deferred_value()
+ except Exception as e:
+ print "Could not parse property '%s': %s"%(key, e)
+ return e
+ return False
+
+def version():
+ """ Returns the version as a string. """
+ stdout, stderr = _dmitool_call("version", stdout=PIPE).communicate()
+ return str(stdout).strip()
+
+def help():
+ """ Returns the help text as a string. """
+ stdout, stderr = _dmitool_call("help", stdout=PIPE).communicate()
+ return str(stdout).strip()
+
+def info(filepath):
+ """ Totally not a hack that parses the output from dmitool into a dictionary.
+ May break at any moment.
+ """
+ subproc = _dmitool_call("info", filepath, stdout=PIPE)
+ stdout, stderr = subproc.communicate()
+
+ result = {}
+ data = stdout.split(os.linesep)[1:]
+ #for s in data: print s
+
+ #parse header line
+ if len(data) > 0:
+ header = data.pop(0).split(",")
+ #don't need to parse states, it's redundant
+ _safe_parse(result, "images", lambda: int(header[0].split()[0].strip()))
+ _safe_parse(result, "size", lambda: header[2].split()[1].strip())
+
+ #parse state information
+ states = []
+ for item in data:
+ if not len(item): continue
+
+ stateinfo = {}
+ item = item.split(",", 3)
+ _safe_parse(stateinfo, "name", lambda: item[0].split()[1].strip(" \""))
+ _safe_parse(stateinfo, "dirs", lambda: int(item[1].split()[0].strip()))
+ _safe_parse(stateinfo, "frames", lambda: int(item[2].split()[0].strip()))
+ if len(item) > 3:
+ stateinfo["misc"] = item[3]
+
+ states.append(stateinfo)
+
+ result["states"] = states
+ return result
+
+def extract_state(input_path, output_path, icon_state, direction=None, frame=None):
+ """ Extracts an icon state as a png to a given path.
+ If provided direction should be a string, one of S, N, E, W, SE, SW, NE, NW.
+ If provided frame should be a frame number or a string of two frame number separated by a dash.
+ """
+ args = ["extract", input_path, icon_state, output_path]
+ if direction is not None: args.extend(("direction" , str(direction)))
+ if frame is not None: args.extend(("frame" , str(frame)))
+ return _dmitool_call(*args)
+
+def import_state(target_path, input_path, icon_state, replace=False, delays=None, rewind=False, loop=None, ismovement=False, direction=None, frame=None):
+ """ Inserts an input png given by the input_path into the target_path.
+ """
+ args = ["import", target_path, icon_state, input_path]
+
+ if replace: args.append("nodup")
+ if rewind: args.append("rewind")
+ if ismovement: args.append("movement")
+ if delays: args.extend(("delays", ",".join(delays)))
+ if direction is not None: args.extend(("direction", direction))
+ if frame is not None: args.extend(("frame", frame))
+
+ if loop in ("inf", "infinity"):
+ args.append("loop")
+ elif loop:
+ args.extend(("loopn", loop))
+
+ return _dmitool_call(*args)
diff --git a/tools/dmitool/src/main/java/dmitool/IconState.java b/tools/dmitool/src/main/java/dmitool/IconState.java
index c3eb2cff21..2a2202c71c 100644
--- a/tools/dmitool/src/main/java/dmitool/IconState.java
+++ b/tools/dmitool/src/main/java/dmitool/IconState.java
@@ -175,7 +175,7 @@ public class IconState {
}
int pxW = in.imgInfo.cols;
int pxH = in.imgInfo.rows;
- int frames = pxW / w;
+ int frames = pxW / w; //frames are read along the X axis, dirs along the Y, much like export.
int dirs = pxH / h;
// make sure the size is an integer multiple
@@ -203,7 +203,7 @@ public class IconState {
px[bY][bX + 3]);
}
}
- images[imageY + imageX*dirs] = new NonPalettedImage(w, h, pixels);
+ images[_getIndex(imageY, imageX, dirs)] = new NonPalettedImage(w, h, pixels);
}
}
@@ -211,6 +211,38 @@ public class IconState {
return new IconState(name, dirs, frames, images, delays, rewind, loop, hotspot, movement);
}
+
+ //Converts a desired dir and frame to an index into the images array.
+ public int getIndex(int dir, int frame) {
+ return _getIndex(dir, frame, dirs);
+ }
+
+ private static int _getIndex(int dir, int frame, int totalDirs) {
+ return dir + frame*totalDirs;
+ }
+
+ public void insertDir(int dir, Image[] splice) {
+ int maxFrame = frames < splice.length? frames: splice.length;
+ for(int frameIdx = 0; frameIdx < maxFrame; frameIdx++) {
+ insertImage(dir, frameIdx, splice[frameIdx]);
+ }
+ }
+
+ public void insertFrame(int frame, Image[] splice) {
+ int maxDir = dirs < splice.length? dirs: splice.length;
+ for(int dirIdx = 0; dirIdx < maxDir; dirIdx++) {
+ insertImage(dirIdx, frame, splice[dirIdx]);
+ }
+ }
+
+ public void insertImage(int dir, int frame, Image splice) {
+ if(frame < 0 || frame >= frames)
+ throw new IllegalArgumentException("Provided frame is out of range: " + frame);
+ if(dir < 0 || dir >= dirs)
+ throw new IllegalArgumentException("Provided dir is out of range: " + dir);
+
+ images[getIndex(dir, frame)] = splice;
+ }
}
@@ -244,6 +276,5 @@ public class IconState {
-
diff --git a/tools/dmitool/src/main/java/dmitool/Main.java b/tools/dmitool/src/main/java/dmitool/Main.java
index 493d7b58fe..fe6048ca3b 100644
--- a/tools/dmitool/src/main/java/dmitool/Main.java
+++ b/tools/dmitool/src/main/java/dmitool/Main.java
@@ -59,6 +59,7 @@ public class Main {
"\t movement | move | mov | m : [state] should be marked as a movement state\n" +
"\t delays L | delay L | del L | d L : use the list L as a comma-separated list of delays (e.g. '1,1,2,2,1')\n" +
"\t hotspot H | hs H | h H : use H as the hotspot for this state\n" +
+ "\t direction D | dir D : replaces D with the image from [in], instead of the entire state. D can be 0-7 or S, N, E, etc. If the state does not already exist, this is ignored\n" +
"";
public static void main(String[] args) throws FileNotFoundException, IOException, DMIException {
@@ -270,6 +271,8 @@ public class Main {
boolean movement = false;
String hotspot = null;
float[] delays = null;
+ String replaceDir = null;
+ String replaceFrame = null;
while(!argq.isEmpty()) {
String s = argq.pollFirst();
switch(s.toLowerCase()) {
@@ -341,6 +344,24 @@ public class Main {
return;
}
break;
+ case "dir":
+ case "direction":
+ if(!argq.isEmpty()) {
+ replaceDir = argq.pollFirst();
+ } else {
+ System.out.println("Argument '" + s + "' requires a direction argument following it!");
+ return;
+ }
+ break;
+ case "f":
+ case "frame":
+ if(!argq.isEmpty()) {
+ replaceFrame = argq.pollFirst();
+ } else {
+ System.out.println("Argument '" + s + "' requires a frame argument following it!");
+ return;
+ }
+ break;
default:
System.out.println("Unknown import argument '" + s + "', ignoring.");
break;
@@ -352,12 +373,46 @@ public class Main {
if(VERBOSITY >= 0) toImportTo.printInfo();
IconState is = IconState.importFromPNG(toImportTo, new FileInputStream(pngFile), stateName, delays, rewind, loop, hotspot, movement);
- if(noDup) {
- if(!toImportTo.setIconState(is)) {
+ //image insertion
+ if(replaceDir != null || replaceFrame != null) {
+
+ IconState targetIs = toImportTo.getIconState(stateName);
+ if(targetIs == null) {
+ System.out.println("'direction' or 'frame' specified and no icon state '" + stateName + "' found, aborting!");
+ return;
+ }
+ if(is.images.length == 0) {
+ System.out.println("'direction' or 'frame' specified and imported is empty, aborting!");
+ return;
+ }
+
+ if(!noDup) targetIs = targetIs.clone();
+
+ int dirToReplace, frameToReplace;
+ if(replaceDir != null && replaceFrame != null) {
+ frameToReplace = parseFrame(replaceFrame, targetIs);
+ dirToReplace = parseDir(replaceDir, targetIs);
+ targetIs.insertImage(dirToReplace, frameToReplace, is.images[0]);
+ }
+ else if(replaceDir != null) {
+ dirToReplace = parseDir(replaceDir, targetIs);
+ targetIs.insertDir(dirToReplace, is.images);
+ }
+ else if(replaceFrame != null) {
+ frameToReplace = parseFrame(replaceFrame, targetIs);
+ targetIs.insertFrame(frameToReplace, is.images);
+ }
+
+ if(!noDup) toImportTo.addIconState(null, targetIs);
+ }
+ else {
+ if(noDup) {
+ if(!toImportTo.setIconState(is)) {
+ toImportTo.addIconState(null, is);
+ }
+ } else {
toImportTo.addIconState(null, is);
}
- } else {
- toImportTo.addIconState(null, is);
}
if(VERBOSITY >= 0) toImportTo.printInfo();