diff --git a/code/_macros.dm b/code/_macros.dm
index 7e8d581b90..e8caac8345 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -7,6 +7,8 @@
#define isanimal(A) istype(A, /mob/living/simple_animal)
+#define isairlock(A) istype(A, /obj/machinery/door/airlock)
+
#define isbrain(A) istype(A, /mob/living/carbon/brain)
#define iscarbon(A) istype(A, /mob/living/carbon)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index bd817baf41..d456c52e71 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -21,7 +21,7 @@ var/list/gamemode_cache = list()
var/log_pda = 0 // log pda messages
var/log_hrefs = 0 // logs all links clicked in-game. Could be used for debugging and tracking down exploits
var/log_runtime = 0 // logs world.log to a file
- var/sql_enabled = 1 // for sql switching
+ var/sql_enabled = 0 // for sql switching
var/allow_admin_ooccolor = 0 // Allows admins with relevant permissions to have their own ooc colour
var/allow_vote_restart = 0 // allow votes to restart
var/ert_admin_call_only = 0
@@ -289,7 +289,7 @@ var/list/gamemode_cache = list()
config.log_access = 1
if ("sql_enabled")
- config.sql_enabled = text2num(value)
+ config.sql_enabled = 1
if ("log_say")
config.log_say = 1
diff --git a/code/controllers/hooks-defs.dm b/code/controllers/hooks-defs.dm
index 001372b4e3..e330024475 100644
--- a/code/controllers/hooks-defs.dm
+++ b/code/controllers/hooks-defs.dm
@@ -1,87 +1,87 @@
-/**
- * Startup hook.
- * Called in world.dm when the server starts.
- */
-/hook/startup
-
-/**
- * Roundstart hook.
- * Called in gameticker.dm when a round starts.
- */
-/hook/roundstart
-
-/**
- * Roundend hook.
- * Called in gameticker.dm when a round ends.
- */
-/hook/roundend
-
-/**
- * Death hook.
- * Called in death.dm when someone dies.
- * Parameters: var/mob/living/carbon/human, var/gibbed
- */
-/hook/death
-
-/**
- * Cloning hook.
- * Called in cloning.dm when someone is brought back by the wonders of modern science.
- * Parameters: var/mob/living/carbon/human
- */
-/hook/clone
-
-/**
- * Debrained hook.
- * Called in brain_item.dm when someone gets debrained.
- * Parameters: var/obj/item/organ/brain
- */
-/hook/debrain
-
-/**
- * Borged hook.
- * Called in robot_parts.dm when someone gets turned into a cyborg.
- * Parameters: var/mob/living/silicon/robot
- */
-/hook/borgify
-
-/**
- * Podman hook.
- * Called in podmen.dm when someone is brought back as a Diona.
- * Parameters: var/mob/living/carbon/alien/diona
- */
-/hook/harvest_podman
-
-/**
- * Payroll revoked hook.
- * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
- * Parameters: var/datum/money_account
- */
-/hook/revoke_payroll
-
-/**
- * Account suspension hook.
- * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
- * Parameters: var/datum/money_account
- */
-/hook/change_account_status
-
-/**
- * Employee reassignment hook.
- * Called in card.dm when someone's card is reassigned at the HoP's desk.
- * Parameters: var/obj/item/weapon/card/id
- */
-/hook/reassign_employee
-
-/**
- * Employee terminated hook.
- * Called in card.dm when someone's card is terminated at the HoP's desk.
- * Parameters: var/obj/item/weapon/card/id
- */
-/hook/terminate_employee
-
-/**
- * Crate sold hook.
- * Called in supplyshuttle.dm when a crate is sold on the shuttle.
- * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
- */
-/hook/sell_crate
+/**
+ * Startup hook.
+ * Called in world.dm when the server starts.
+ */
+/hook/startup
+
+/**
+ * Roundstart hook.
+ * Called in gameticker.dm when a round starts.
+ */
+/hook/roundstart
+
+/**
+ * Roundend hook.
+ * Called in gameticker.dm when a round ends.
+ */
+/hook/roundend
+
+/**
+ * Death hook.
+ * Called in death.dm when someone dies.
+ * Parameters: var/mob/living/carbon/human, var/gibbed
+ */
+/hook/death
+
+/**
+ * Cloning hook.
+ * Called in cloning.dm when someone is brought back by the wonders of modern science.
+ * Parameters: var/mob/living/carbon/human
+ */
+/hook/clone
+
+/**
+ * Debrained hook.
+ * Called in brain_item.dm when someone gets debrained.
+ * Parameters: var/obj/item/organ/brain
+ */
+/hook/debrain
+
+/**
+ * Borged hook.
+ * Called in robot_parts.dm when someone gets turned into a cyborg.
+ * Parameters: var/mob/living/silicon/robot
+ */
+/hook/borgify
+
+/**
+ * Podman hook.
+ * Called in podmen.dm when someone is brought back as a Diona.
+ * Parameters: var/mob/living/carbon/alien/diona
+ */
+/hook/harvest_podman
+
+/**
+ * Payroll revoked hook.
+ * Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
+ * Parameters: var/datum/money_account
+ */
+/hook/revoke_payroll
+
+/**
+ * Account suspension hook.
+ * Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
+ * Parameters: var/datum/money_account
+ */
+/hook/change_account_status
+
+/**
+ * Employee reassignment hook.
+ * Called in card.dm when someone's card is reassigned at the HoP's desk.
+ * Parameters: var/obj/item/weapon/card/id
+ */
+/hook/reassign_employee
+
+/**
+ * Employee terminated hook.
+ * Called in card.dm when someone's card is terminated at the HoP's desk.
+ * Parameters: var/obj/item/weapon/card/id
+ */
+/hook/terminate_employee
+
+/**
+ * Crate sold hook.
+ * Called in supplyshuttle.dm when a crate is sold on the shuttle.
+ * Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
+ */
+/hook/sell_crate
diff --git a/code/controllers/observer_listener/atom/observer.dm b/code/controllers/observer_listener/atom/observer.dm
new file mode 100644
index 0000000000..da38580414
--- /dev/null
+++ b/code/controllers/observer_listener/atom/observer.dm
@@ -0,0 +1,31 @@
+#define OBSERVER_EVENT_DESTROY "OnDestroy"
+
+/atom
+ var/list/observer_events
+
+/atom/Destroy()
+ var/list/destroy_listeners = get_listener_list_from_event(OBSERVER_EVENT_DESTROY)
+ if(destroy_listeners)
+ for(var/destroy_listener in destroy_listeners)
+ call(destroy_listener, destroy_listeners[destroy_listener])(src)
+
+ for(var/list/listeners in observer_events)
+ listeners.Cut()
+
+ return ..()
+
+/atom/proc/register(var/event, var/procOwner, var/proc_call)
+ var/list/listeners = get_listener_list_from_event(event)
+ listeners[procOwner] = proc_call
+
+/atom/proc/unregister(var/event, var/procOwner)
+ var/list/listeners = get_listener_list_from_event(event)
+ listeners -= procOwner
+
+/atom/proc/get_listener_list_from_event(var/observer_event)
+ if(!observer_events) observer_events = list()
+ var/list/listeners = observer_events[observer_event]
+ if(!listeners)
+ listeners = list()
+ observer_events[observer_event] = listeners
+ return listeners
diff --git a/code/controllers/observer_listener/datum/observer.dm b/code/controllers/observer_listener/datum/observer.dm
new file mode 100644
index 0000000000..61f6fbf180
--- /dev/null
+++ b/code/controllers/observer_listener/datum/observer.dm
@@ -0,0 +1,28 @@
+/*
+#define OBSERVER_EVENT_DESTROY "OnDestroy"
+
+/datum
+ var/list/observer_events
+
+/datum/Destroy()
+ for(var/list/listeners in observer_events)
+ listeners.Cut()
+
+ return ..()
+
+/datum/proc/register(var/event, var/procOwner, var/proc_call)
+ var/list/listeners = get_listener_list_from_event(event)
+ listeners[procOwner] = proc_call
+
+/datum/proc/unregister(var/event, var/procOwner)
+ var/list/listeners = get_listener_list_from_event(event)
+ listeners -= procOwner
+
+/datum/proc/get_listener_list_from_event(var/observer_event)
+ if(!observer_events) observer_events = list()
+ var/list/listeners = observer_events[observer_event]
+ if(!listeners)
+ listeners = list()
+ observer_events[observer_event] = listeners
+ return listeners
+*/
diff --git a/code/game/gamemodes/changeling/absorbed_dna.dm b/code/game/gamemodes/changeling/absorbed_dna.dm
index bdf243b412..3c23f0270c 100644
--- a/code/game/gamemodes/changeling/absorbed_dna.dm
+++ b/code/game/gamemodes/changeling/absorbed_dna.dm
@@ -4,11 +4,13 @@
var/speciesName
var/list/languages
var/identifying_gender
+ var/list/flavour_texts
-/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages, var/newIdentifying_Gender)
+/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages, var/newIdentifying_Gender, var/list/newFlavour)
..()
name = newName
dna = newDNA
speciesName = newSpecies
languages = newLanguages
- identifying_gender = newIdentifying_Gender
\ No newline at end of file
+ identifying_gender = newIdentifying_Gender
+ flavour_texts = newFlavour ? newFlavour.Copy() : null
\ No newline at end of file
diff --git a/code/game/gamemodes/changeling/changeling_powers.dm b/code/game/gamemodes/changeling/changeling_powers.dm
index ae5ede1566..a89fe95d95 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -85,7 +85,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
var/mob/living/carbon/human/H = src
if(istype(H))
- var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages, H.identifying_gender)
+ var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages, H.identifying_gender, H.flavor_texts)
absorbDNA(newDNA)
return 1
diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm
index 16f34357b5..e75020fc59 100644
--- a/code/game/gamemodes/changeling/powers/absorb.dm
+++ b/code/game/gamemodes/changeling/powers/absorb.dm
@@ -71,7 +71,7 @@
src.verbs += /mob/proc/changeling_respec
src << "We can now re-adapt, reverting our evolution so that we may start anew, if needed."
- var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages)
+ var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages, T.identifying_gender, T.flavor_texts)
absorbDNA(newDNA)
if(T.mind && T.mind.changeling)
diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm
index 0eec3ed213..57a55e2e21 100644
--- a/code/game/gamemodes/changeling/powers/transform.dm
+++ b/code/game/gamemodes/changeling/powers/transform.dm
@@ -37,11 +37,9 @@
if(ishuman(src))
var/mob/living/carbon/human/H = src
H.b_type = "AB+" //For some reason we have two blood types on the mob.
- for(var/flavor in H.flavor_texts) //Nulls out flavor text, so we don't keep our previous mob's flavor.
- flavor = null
H.identifying_gender = chosen_dna.identifying_gender
+ H.flavor_texts = chosen_dna.flavour_texts ? chosen_dna.flavour_texts.Copy() : null
src.real_name = chosen_dna.name
- src.flavor_text = ""
src.UpdateAppearance()
domutcheck(src, null)
changeling_update_languages(changeling.absorbed_languages)
diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm
index 7f82a34f1c..831edadcbf 100644
--- a/code/game/machinery/kitchen/microwave.dm
+++ b/code/game/machinery/kitchen/microwave.dm
@@ -327,7 +327,7 @@
src.updateUsrDialog()
/obj/machinery/microwave/proc/dispose()
- for (var/obj/O in (contents-component_parts))
+ for (var/obj/O in ((contents-component_parts)-circuit))
O.loc = src.loc
if (src.reagents.total_volume)
src.dirty++
diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm
index 74f60a3a72..7d8e75764c 100644
--- a/code/game/machinery/lightswitch.dm
+++ b/code/game/machinery/lightswitch.dm
@@ -13,6 +13,7 @@
var/on = 1
var/area/area = null
var/otherarea = null
+ var/image/overlay
/obj/machinery/light_switch/New()
..()
@@ -31,14 +32,18 @@
/obj/machinery/light_switch/proc/updateicon()
+ if(!overlay)
+ overlay = image(icon, "light1-overlay", LIGHTING_LAYER+0.1)
+
+ overlays.Cut()
if(stat & NOPOWER)
icon_state = "light-p"
set_light(0)
- layer = OBJ_LAYER
else
icon_state = "light[on]"
- set_light(2, 1.5, on ? "#82FF4C" : "#F86060")
- layer = LIGHTING_LAYER+0.1
+ overlay.icon_state = "light[on]-overlay"
+ overlays += overlay
+ set_light(2, 0.1, on ? "#82FF4C" : "#F86060")
/obj/machinery/light_switch/examine(mob/user)
if(..(user, 1))
diff --git a/code/game/machinery/pda_multicaster.dm b/code/game/machinery/pda_multicaster.dm
new file mode 100644
index 0000000000..a7d5c780c3
--- /dev/null
+++ b/code/game/machinery/pda_multicaster.dm
@@ -0,0 +1,101 @@
+/obj/machinery/pda_multicaster
+ name = "\improper PDA multicaster"
+ desc = "This machine mirrors messages sent to it to specific departments."
+ icon = 'icons/obj/stationobjs.dmi'
+ icon_state = "controller"
+ density = 1
+ anchored = 1
+ circuit = /obj/item/weapon/circuitboard/telecomms/pda_multicaster
+ use_power = 1
+ idle_power_usage = 750
+ var/on = 1 // If we're currently active,
+ var/toggle = 1 // If we /should/ be active or not,
+ var/list/internal_PDAs = list() // Assoc list of PDAs inside of this, with the department name being the index,
+
+/obj/machinery/pda_multicaster/New()
+ ..()
+ internal_PDAs = list("command" = new /obj/item/device/pda/multicaster/command(src),
+ "security" = new /obj/item/device/pda/multicaster/security(src),
+ "engineering" = new /obj/item/device/pda/multicaster/engineering(src),
+ "medical" = new /obj/item/device/pda/multicaster/medical(src),
+ "research" = new /obj/item/device/pda/multicaster/research(src),
+ "cargo" = new /obj/item/device/pda/multicaster/cargo(src),
+ "civilian" = new /obj/item/device/pda/multicaster/civilian(src))
+
+/obj/machinery/pda_multicaster/prebuilt/New()
+ ..()
+
+ component_parts = list()
+ component_parts += new /obj/item/weapon/circuitboard/telecomms/pda_multicaster(src)
+ component_parts += new /obj/item/weapon/stock_parts/subspace/ansible(src)
+ component_parts += new /obj/item/weapon/stock_parts/subspace/filter(src)
+ component_parts += new /obj/item/weapon/stock_parts/manipulator(src)
+ component_parts += new /obj/item/weapon/stock_parts/subspace/treatment(src)
+ component_parts += new /obj/item/stack/cable_coil(src, 2)
+ RefreshParts()
+
+/obj/machinery/pda_multicaster/Destroy()
+ for(var/atom/movable/AM in contents)
+ qdel(AM)
+ ..()
+
+/obj/machinery/pda_multicaster/update_icon()
+ if(on)
+ icon_state = initial(icon_state)
+ else
+ icon_state = "[initial(icon_state)]-p"
+
+/obj/machinery/pda_multicaster/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/screwdriver))
+ default_deconstruction_screwdriver(user, I)
+ else if(istype(I, /obj/item/weapon/crowbar))
+ default_deconstruction_crowbar(user, I)
+ else
+ ..()
+
+/obj/machinery/pda_multicaster/attack_ai(mob/user)
+ attack_hand(user)
+
+/obj/machinery/pda_multicaster/attack_hand(mob/user)
+ toggle_power(user)
+
+/obj/machinery/pda_multicaster/proc/toggle_power(mob/user)
+ toggle = !toggle
+ visible_message("\the [user] turns \the [src] [toggle ? "on" : "off"].")
+ update_power()
+ if(!toggle)
+ var/msg = "[usr.client.key] ([usr]) has turned [src] off, at [x],[y],[z]."
+ message_admins(msg)
+ log_game(msg)
+
+/obj/machinery/pda_multicaster/proc/update_PDAs(var/turn_off)
+ for(var/obj/item/device/pda/pda in contents)
+ pda.toff = turn_off
+
+/obj/machinery/pda_multicaster/proc/update_power()
+ if(toggle)
+ if(stat & (BROKEN|NOPOWER|EMPED))
+ on = 0
+ update_PDAs(1) // 1 being to turn off.
+ idle_power_usage = 0
+ else
+ on = 1
+ update_PDAs(0)
+ idle_power_usage = 750
+ else
+ on = 0
+ update_PDAs(1)
+ idle_power_usage = 0
+ update_icon()
+
+/obj/machinery/pda_multicaster/process()
+ update_power()
+
+/obj/machinery/pda_multicaster/emp_act(severity)
+ if(!(stat & EMPED))
+ stat |= EMPED
+ var/duration = (300 * 10)/severity
+ spawn(rand(duration - 20, duration + 20))
+ stat &= ~EMPED
+ update_icon()
+ ..()
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index fcb52986a4..01fc592690 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -213,10 +213,10 @@ steam.start() -- spawns the effect
icon = 'icons/effects/effects.dmi'
icon_state = "sparks"
-/obj/effect/effect/smoke/illumination/New(var/newloc, var/brightness=15, var/lifetime=10)
+/obj/effect/effect/smoke/illumination/New(var/newloc, var/lifetime=10, var/range=null, var/power=null, var/color=null)
time_to_live=lifetime
..()
- set_light(brightness)
+ set_light(range, power, color)
/////////////////////////////////////////////
// Bad smoke
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index a3db6b15a1..f0bb82efd0 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -163,6 +163,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
/obj/item/device/pda/shaftminer
icon_state = "pda-miner"
+ default_cartridge = /obj/item/weapon/cartridge/miner
/obj/item/device/pda/syndicate
default_cartridge = /obj/item/weapon/cartridge/syndicate
@@ -172,6 +173,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
hidden = 1
/obj/item/device/pda/chaplain
+ default_cartridge = /obj/item/weapon/cartridge/service
icon_state = "pda-holy"
ttone = "holy"
@@ -181,13 +183,15 @@ var/global/list/obj/item/device/pda/PDAs = list()
ttone = "..."
/obj/item/device/pda/botanist
- //default_cartridge = /obj/item/weapon/cartridge/botanist
+ default_cartridge = /obj/item/weapon/cartridge/service
icon_state = "pda-hydro"
/obj/item/device/pda/roboticist
+ default_cartridge = /obj/item/weapon/cartridge/signal/science
icon_state = "pda-robot"
/obj/item/device/pda/librarian
+ default_cartridge = /obj/item/weapon/cartridge/service
icon_state = "pda-libb"
desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader."
note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!"
@@ -200,9 +204,11 @@ var/global/list/obj/item/device/pda/PDAs = list()
note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!"
/obj/item/device/pda/chef
+ default_cartridge = /obj/item/weapon/cartridge/service
icon_state = "pda-chef"
/obj/item/device/pda/bar
+ default_cartridge = /obj/item/weapon/cartridge/service
icon_state = "pda-bar"
/obj/item/device/pda/atmos
@@ -304,6 +310,99 @@ var/global/list/obj/item/device/pda/PDAs = list()
ttone = "assist"
+// Used for the PDA multicaster, which mirrors messages sent to it to a specific department,
+/obj/item/device/pda/multicaster
+ ownjob = "Relay"
+ icon_state = "NONE"
+ ttone = "data"
+ detonate = 0
+ news_silent = 1
+ var/list/cartridges_to_send_to = list()
+
+// This is what actually mirrors the message,
+/obj/item/device/pda/multicaster/new_message(var/sending_unit, var/sender, var/sender_job, var/message)
+ if(sender)
+ var/list/targets = list()
+ for(var/obj/item/device/pda/pda in PDAs)
+ if(pda.cartridge && pda.owner && is_type_in_list(pda.cartridge, cartridges_to_send_to))
+ targets |= pda
+ if(targets.len)
+ for(var/obj/item/device/pda/target in targets)
+ create_message(target, sender, sender_job, message)
+
+// This has so much copypasta,
+/obj/item/device/pda/multicaster/create_message(var/obj/item/device/pda/P, var/original_sender, var/original_job, var/t)
+ t = sanitize(t, MAX_MESSAGE_LEN, 0)
+ t = replace_characters(t, list(""" = "\""))
+ if (!t || !istype(P))
+ return
+
+ if (isnull(P)||P.toff || toff)
+ return
+
+ last_text = world.time
+ var/datum/reception/reception = get_reception(src, P, t)
+ t = reception.message
+
+ if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable,
+ if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level?,
+ return
+ var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]")
+ if (send_result)
+ return
+
+ P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]")))
+
+ if(!P.conversations.Find("\ref[src]"))
+ P.conversations.Add("\ref[src]")
+
+ P.new_message(src, "[original_sender] \[Relayed\]", original_job, t, 0)
+
+ else
+ return
+
+/obj/item/device/pda/multicaster/command/New()
+ ..()
+ owner = "Command Department"
+ name = "Command Department (Relay)"
+ cartridges_to_send_to = command_cartridges
+
+/obj/item/device/pda/multicaster/security/New()
+ ..()
+ owner = "Security Department"
+ name = "Security Department (Relay)"
+ cartridges_to_send_to = security_cartridges
+
+/obj/item/device/pda/multicaster/engineering/New()
+ ..()
+ owner = "Engineering Department"
+ name = "Engineering Department (Relay)"
+ cartridges_to_send_to = engineering_cartridges
+
+/obj/item/device/pda/multicaster/medical/New()
+ ..()
+ owner = "Medical Department"
+ name = "Medical Department (Relay)"
+ cartridges_to_send_to = medical_cartridges
+
+/obj/item/device/pda/multicaster/research/New()
+ ..()
+ owner = "Research Department"
+ name = "Research Department (Relay)"
+ cartridges_to_send_to = research_cartridges
+
+/obj/item/device/pda/multicaster/cargo/New()
+ ..()
+ owner = "Cargo Department"
+ name = "Cargo Department (Relay)"
+ cartridges_to_send_to = cargo_cartridges
+
+/obj/item/device/pda/multicaster/civilian/New()
+ ..()
+ owner = "Civilian Services Department"
+ name = "Civilian Services Department (Relay)"
+ cartridges_to_send_to = civilian_cartridges
+
/*
* The Actual PDA
*/
@@ -932,7 +1031,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
message += "Your [P] bleeps loudly."
j = prob(10)
- if(j) //This kills the PDA
+ if(j && detonate) //This kills the PDA
qdel(P)
if(message)
message += "It melts in a puddle of plastic."
@@ -1046,8 +1145,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
/obj/item/device/pda/proc/new_message_from_pda(var/obj/item/device/pda/sending_device, var/message)
new_message(sending_device, sending_device.owner, sending_device.ownjob, message)
-/obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message)
- var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" (Reply)"
+/obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message, var/reply = 1)
+ var/reception_message = "\icon[src] Message from [sender] ([sender_job]), \"[message]\" ([reply ? "Reply" : "Unable to Reply"])"
new_info(message_silent, ttone, reception_message)
log_pda("[usr] (PDA: [sending_unit]) sent \"[message]\" to [name]")
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index 5d576959fb..a0e37e28b8 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -1,3 +1,48 @@
+var/list/command_cartridges = list(
+ /obj/item/weapon/cartridge/captain,
+ /obj/item/weapon/cartridge/hop,
+ /obj/item/weapon/cartridge/hos,
+ /obj/item/weapon/cartridge/ce,
+ /obj/item/weapon/cartridge/rd,
+ /obj/item/weapon/cartridge/head,
+ /obj/item/weapon/cartridge/lawyer // Internal Affaris,
+ )
+
+var/list/security_cartridges = list(
+ /obj/item/weapon/cartridge/security,
+ /obj/item/weapon/cartridge/detective,
+ /obj/item/weapon/cartridge/hos
+ )
+
+var/list/engineering_cartridges = list(
+ /obj/item/weapon/cartridge/engineering,
+ /obj/item/weapon/cartridge/atmos,
+ /obj/item/weapon/cartridge/ce
+ )
+
+var/list/medical_cartridges = list(
+ /obj/item/weapon/cartridge/medical,
+ /obj/item/weapon/cartridge/chemistry,
+ /obj/item/weapon/cartridge/cmo
+ )
+
+var/list/research_cartridges = list(
+ /obj/item/weapon/cartridge/signal/science,
+ /obj/item/weapon/cartridge/rd
+ )
+
+var/list/cargo_cartridges = list(
+ /obj/item/weapon/cartridge/quartermaster, // This also covers cargo-techs, apparently,
+ /obj/item/weapon/cartridge/miner,
+ /obj/item/weapon/cartridge/hop
+ )
+
+var/list/civilian_cartridges = list(
+ /obj/item/weapon/cartridge/janitor,
+ /obj/item/weapon/cartridge/service,
+ /obj/item/weapon/cartridge/hop
+ )
+
/obj/item/weapon/cartridge
name = "generic cartridge"
desc = "A data cartridge for portable microcomputers."
@@ -98,6 +143,10 @@
access_flora = 1
*/
+/obj/item/weapon/cartridge/service
+ name = "\improper Serv-U Pro"
+ desc = "A data cartridge designed to serve YOU!"
+
/obj/item/weapon/cartridge/signal
name = "generic signaler cartridge"
desc = "A data cartridge with an integrated radio signaler module."
@@ -124,6 +173,11 @@
icon_state = "cart-q"
access_quartermaster = 1
+/obj/item/weapon/cartridge/miner
+ name = "\improper Drill-Jockey 4.5"
+ desc = "It's covered in some sort of sand."
+ icon_state = "cart-q"
+
/obj/item/weapon/cartridge/head
name = "\improper Easy-Record DELUXE"
icon_state = "cart-h"
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index da512f9449..0024a05c62 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -60,6 +60,10 @@
else //can only use it 5 times a minute
user << "*click* *click*"
return
+
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.do_attack_animation(M)
+
playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
var/flashfail = 0
@@ -112,6 +116,7 @@
/obj/item/device/flash/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0)
if(!user || !clown_check(user)) return
+
if(broken)
user.show_message("The [src.name] is broken", 2)
return
@@ -131,6 +136,7 @@
else //can only use it 5 times a minute
user.show_message("*click* *click*", 2)
return
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
flick("flash2", src)
if(user && isrobot(user))
diff --git a/code/game/objects/items/devices/hacktool.dm b/code/game/objects/items/devices/hacktool.dm
new file mode 100644
index 0000000000..0cf4af6c74
--- /dev/null
+++ b/code/game/objects/items/devices/hacktool.dm
@@ -0,0 +1,100 @@
+/obj/item/device/multitool/hacktool
+ var/is_hacking = 0
+ var/max_known_targets
+
+ var/in_hack_mode = 0
+ var/list/known_targets
+ var/list/supported_types
+ var/datum/topic_state/default/must_hack/hack_state
+
+/obj/item/device/multitool/hacktool/New()
+ ..()
+ known_targets = list()
+ max_known_targets = 5 + rand(1,3)
+ supported_types = list(/obj/machinery/door/airlock)
+ hack_state = new(src)
+
+/obj/item/device/multitool/hacktool/Destroy()
+ for(var/T in known_targets)
+ var/atom/target = T
+ target.unregister(OBSERVER_EVENT_DESTROY, src)
+ known_targets.Cut()
+ qdel(hack_state)
+ hack_state = null
+ return ..()
+
+/obj/item/device/multitool/hacktool/attackby(var/obj/W, var/mob/user)
+ if(isscrewdriver(W))
+ in_hack_mode = !in_hack_mode
+ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
+ else
+ ..()
+
+/obj/item/device/multitool/hacktool/resolve_attackby(atom/A, mob/user)
+ sanity_check()
+
+ if(!in_hack_mode)
+ return ..()
+
+ if(!attempt_hack(user, A))
+ return 0
+
+ A.ui_interact(user, state = hack_state)
+ return 1
+
+/obj/item/device/multitool/hacktool/proc/attempt_hack(var/mob/user, var/atom/target)
+ if(is_hacking)
+ user << "You are already hacking!"
+ return 0
+ if(!is_type_in_list(target, supported_types))
+ user << "\icon[src] Unable to hack this target!"
+ return 0
+ var/found = known_targets.Find(target)
+ if(found)
+ known_targets.Swap(1, found) // Move the last hacked item first
+ return 1
+
+ user << "You begin hacking \the [target]..."
+ is_hacking = 1
+ // On average hackin takes ~30 seconds. Fairly small random span to avoid people simply aborting and trying again
+ var/hack_result = do_after(user, (20 SECONDS + rand(0, 10 SECONDS) + rand(0, 10 SECONDS)))
+ is_hacking = 0
+
+ if(hack_result && in_hack_mode)
+ user << "Your hacking attempt was succesful!"
+ playsound(src.loc, 'sound/piano/A#6.ogg', 75)
+ else
+ user << "Your hacking attempt failed!"
+ return 0
+
+ known_targets.Insert(1, target) // Insert the newly hacked target first,
+ target.register(OBSERVER_EVENT_DESTROY, src, /obj/item/device/multitool/hacktool/proc/on_target_destroy)
+ return 1
+
+/obj/item/device/multitool/hacktool/proc/sanity_check()
+ if(max_known_targets < 1) max_known_targets = 1
+ // Cut away the oldest items if the capacity has been reached
+ if(known_targets.len > max_known_targets)
+ for(var/i = (max_known_targets + 1) to known_targets.len)
+ var/atom/A = known_targets[i]
+ A.unregister(OBSERVER_EVENT_DESTROY, src)
+ known_targets.Cut(max_known_targets + 1)
+
+/obj/item/device/multitool/hacktool/proc/on_target_destroy(var/target)
+ known_targets -= target
+
+/datum/topic_state/default/must_hack
+ var/obj/item/device/multitool/hacktool/hacktool
+
+/datum/topic_state/default/must_hack/New(var/hacktool)
+ src.hacktool = hacktool
+ ..()
+
+/datum/topic_state/default/must_hack/Destroy()
+ hacktool = null
+ return ..()
+
+/datum/topic_state/default/must_hack/can_use_topic(var/src_object, var/mob/user)
+ if(!hacktool || !hacktool.in_hack_mode || !(src_object in hacktool.known_targets))
+ return STATUS_CLOSE
+ return ..()
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 867e64f446..e7cb6f3475 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -20,4 +20,4 @@
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage
- var/obj/machinery/clonepod/connecting //same for cryopod linkage
\ No newline at end of file
+ var/obj/machinery/clonepod/connecting //same for cryopod linkage
diff --git a/code/game/objects/items/devices/uplink_items.dm b/code/game/objects/items/devices/uplink_items.dm
index bc9666990b..b0ee3689a1 100644
--- a/code/game/objects/items/devices/uplink_items.dm
+++ b/code/game/objects/items/devices/uplink_items.dm
@@ -411,6 +411,14 @@ datum/uplink_item/dd_SortValue()
item_cost = 3
path = /obj/item/weapon/card/emag
+/datum/uplink_item/item/tools/hacking_tool
+ name = "Door Hacking Tool"
+ item_cost = 2
+ path = /obj/item/device/multitool/hacktool
+ desc = "Appears and functions as a standard multitool until the mode is toggled by applying a screwdriver appropriately. \
+ When in hacking mode this device will grant full access to any standard airlock within 20 to 40 seconds. \
+ This device will also be able to immediately access the last 6 to 8 hacked airlocks."
+
/datum/uplink_item/item/tools/clerical
name = "Morphic Clerical Kit"
item_cost = 3
diff --git a/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm b/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm
index 43b654d58d..8a7516f476 100644
--- a/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm
+++ b/code/game/objects/items/weapons/circuitboards/machinery/telecomms.dm
@@ -87,3 +87,14 @@
/obj/item/weapon/stock_parts/subspace/crystal = 1,
/obj/item/weapon/stock_parts/subspace/treatment = 2,
/obj/item/stack/cable_coil = 2)
+
+/obj/item/weapon/circuitboard/telecomms/pda_multicaster
+ name = T_BOARD("pda multicaster")
+ build_path = "/obj/machinery/pda_multicaster"
+ origin_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2, TECH_BLUESPACE = 2)
+ req_components = list(
+ /obj/item/weapon/stock_parts/subspace/ansible = 1,
+ /obj/item/weapon/stock_parts/subspace/filter = 1,
+ /obj/item/weapon/stock_parts/manipulator = 1,
+ /obj/item/weapon/stock_parts/subspace/treatment = 1,
+ /obj/item/stack/cable_coil = 2)
diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm
index a95d3b1382..17616942c1 100644
--- a/code/game/objects/items/weapons/grenades/flashbang.dm
+++ b/code/game/objects/items/weapons/grenades/flashbang.dm
@@ -22,13 +22,13 @@
B.update_icon()
new/obj/effect/effect/sparks(src.loc)
- new/obj/effect/effect/smoke/illumination(src.loc, brightness=15)
+ new/obj/effect/effect/smoke/illumination(src.loc, 5, range=30, power=30, color="#FFFFFF")
qdel(src)
return
proc/bang(var/turf/T , var/mob/living/carbon/M) // Added a new proc called 'bang' that takes a location and a person to be banged.
M << "BANG" // Called during the loop that bangs people in lockers/containers and when banging
- playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, 5) // people in normal view. Could theroetically be called during other explosions.
+ playsound(src.loc, 'sound/effects/bang.ogg', 50, 1, 30) // people in normal view. Could theroetically be called during other explosions.
// -- Polymorph
//Checking for protections
diff --git a/code/game/objects/items/weapons/material/kitchen.dm b/code/game/objects/items/weapons/material/kitchen.dm
index b5c966ebd5..ff1d347c74 100644
--- a/code/game/objects/items/weapons/material/kitchen.dm
+++ b/code/game/objects/items/weapons/material/kitchen.dm
@@ -57,6 +57,8 @@
name = "fork"
desc = "It's a fork. Sure is pointy."
icon_state = "fork"
+ sharp = 1
+ edge = 0
/obj/item/weapon/material/kitchen/utensil/fork/plastic
default_material = "plastic"
diff --git a/code/game/objects/items/weapons/material/misc.dm b/code/game/objects/items/weapons/material/misc.dm
index 80d3771f0e..dcd33fa172 100644
--- a/code/game/objects/items/weapons/material/misc.dm
+++ b/code/game/objects/items/weapons/material/misc.dm
@@ -1,7 +1,7 @@
/obj/item/weapon/material/harpoon
name = "harpoon"
sharp = 1
- edge = 1
+ edge = 0
desc = "Tharr she blows!"
icon_state = "harpoon"
item_state = "harpoon"
diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm
index 52b949cf35..f821ab1db6 100644
--- a/code/game/objects/items/weapons/material/twohanded.dm
+++ b/code/game/objects/items/weapons/material/twohanded.dm
@@ -68,7 +68,7 @@
/obj/item/weapon/material/twohanded/update_icon()
icon_state = "[base_icon][wielded]"
item_state = icon_state
-
+
/obj/item/weapon/material/twohanded/dropped()
..()
if(wielded)
@@ -119,7 +119,7 @@
unwielded_force_divisor = 0.65 // 14 when unwielded based on above
thrown_force_divisor = 1.5 // 20 when thrown with weight 15 (glass)
throw_speed = 3
- edge = 1
+ edge = 0
sharp = 1
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "poked", "jabbed", "torn", "gored")
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
index a79d6575e5..a9e6192796 100644
--- a/code/game/objects/items/weapons/tools.dm
+++ b/code/game/objects/items/weapons/tools.dm
@@ -46,6 +46,7 @@
throw_range = 5
matter = list(DEFAULT_WALL_MATERIAL = 75)
attack_verb = list("stabbed")
+ sharp = 1
suicide_act(mob/user)
viewers(user) << pick("\The [user] is stabbing the [src.name] into \his temple! It looks like \he's trying to commit suicide.", \
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 8ce2a88f24..2dcb1ddaad 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -55,6 +55,9 @@
/obj/structure/displaycase/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
+ user.do_attack_animation(src)
+ playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1)
src.health -= W.force
src.healthcheck()
..()
diff --git a/code/game/turfs/flooring/flooring.dm b/code/game/turfs/flooring/flooring.dm
index 369f42fc38..ad7a0f91ce 100644
--- a/code/game/turfs/flooring/flooring.dm
+++ b/code/game/turfs/flooring/flooring.dm
@@ -69,7 +69,7 @@ var/list/flooring_types
name = "carpet"
icon_base = "bcarpet"
build_type = null
- flags = TURF_HAS_EDGES | TURF_HAS_CORNERS | TURF_REMOVE_CROWBAR | TURF_CAN_BURN
+ flags = TURF_HAS_EDGES | TURF_REMOVE_CROWBAR
/decl/flooring/tiling
name = "floor"
diff --git a/code/game/verbs/ignore.dm b/code/game/verbs/ignore.dm
index b772bd4e81..c154628087 100644
--- a/code/game/verbs/ignore.dm
+++ b/code/game/verbs/ignore.dm
@@ -10,6 +10,10 @@
if(key_to_ignore in prefs.ignored_players)
usr << "[key_to_ignore] is already being ignored."
return
+ if(key_to_ignore == usr.ckey)
+ usr <<"You can't ignore yourself."
+ return
+
prefs.ignored_players |= key_to_ignore
prefs.save_preferences()
usr << "Now ignoring [key_to_ignore]."
diff --git a/code/modules/client/preference_setup/general/01_basic.dm b/code/modules/client/preference_setup/general/01_basic.dm
index 701f24dc2e..2588836df5 100644
--- a/code/modules/client/preference_setup/general/01_basic.dm
+++ b/code/modules/client/preference_setup/general/01_basic.dm
@@ -41,7 +41,8 @@ datum/preferences/proc/set_biological_gender(var/gender)
pref.be_random_name = sanitize_integer(pref.be_random_name, 0, 1, initial(pref.be_random_name))
/datum/category_item/player_setup_item/general/basic/content()
- . = "Name: "
+ . = list()
+ . += "Name: "
. += "[pref.real_name]
"
. += "Randomize Name
"
. += "Always Random Name: [pref.be_random_name ? "Yes" : "No"]"
@@ -52,6 +53,7 @@ datum/preferences/proc/set_biological_gender(var/gender)
. += "Spawn Point: [pref.spawnpoint]
"
if(config.allow_Metadata)
. += "OOC Notes: Edit
"
+ . = jointext(.,null)
/datum/category_item/player_setup_item/general/basic/OnTopic(var/href,var/list/href_list, var/mob/user)
var/datum/species/S = all_species[pref.species]
diff --git a/code/modules/client/preference_setup/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index ef9b419d97..0f26f2d55b 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -73,6 +73,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
if(!pref.rlimb_data) pref.rlimb_data = list()
/datum/category_item/player_setup_item/general/body/content(var/mob/user)
+ . = list()
pref.update_preview_icon()
if(pref.preview_icon_front && pref.preview_icon_side)
user << browse_rsc(pref.preview_icon_front, "preview_icon.png")
@@ -186,6 +187,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
if(has_flag(mob_species, HAS_SKIN_COLOR))
. += "
Body Color
"
. += "Change Color
"
+ . = jointext(.,null)
/datum/category_item/player_setup_item/general/body/proc/has_flag(var/datum/species/mob_species, var/flag)
return mob_species && (mob_species.appearance_flags & flag)
diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/client/preference_setup/global/02_settings.dm
index 60eeeb144e..c7635cbb91 100644
--- a/code/modules/client/preference_setup/global/02_settings.dm
+++ b/code/modules/client/preference_setup/global/02_settings.dm
@@ -61,9 +61,9 @@
. += "
| [client_pref.description]: | "
if(pref_mob.is_preference_enabled(client_pref.key))
- . += "[client_pref.enabled_description] | [client_pref.disabled_description] | "
+ . += "[client_pref.enabled_description] | [client_pref.disabled_description] | "
else
- . += "[client_pref.enabled_description] | [client_pref.disabled_description] | "
+ . += "[client_pref.enabled_description] | [client_pref.disabled_description] | "
. += "
"
. += ""
diff --git a/code/modules/client/preference_setup/global/05_ooc.dm b/code/modules/client/preference_setup/global/05_ooc.dm
index 08aa97836a..1b9d45dc89 100644
--- a/code/modules/client/preference_setup/global/05_ooc.dm
+++ b/code/modules/client/preference_setup/global/05_ooc.dm
@@ -9,7 +9,7 @@
/datum/category_item/player_setup_item/player_global/ooc/save_preferences(var/savefile/S)
S["ignored_players"] << pref.ignored_players
-
+/*
/datum/category_item/player_setup_item/player_global/ooc/sanitize_preferences()
if(isnull(pref.ignored_players))
pref.ignored_players = list()
@@ -32,7 +32,11 @@
var/player_to_ignore = input(user, "Who do you want to ignore?","Ignore") as null|text
if(player_to_ignore)
player_to_ignore = sanitize(ckey(player_to_ignore))
+ if(player_to_ignore == user.ckey)
+ user <<"You can't ignore yourself."
+ return TOPIC_REFRESH
pref.ignored_players |= player_to_ignore
return TOPIC_REFRESH
return ..()
+*/
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm
index e8794a4256..cd1e3eff4c 100644
--- a/code/modules/client/preference_setup/loadout/loadout.dm
+++ b/code/modules/client/preference_setup/loadout/loadout.dm
@@ -82,6 +82,7 @@ var/list/gear_datums = list()
total_cost += G.cost
/datum/category_item/player_setup_item/loadout/content()
+ . = list()
var/total_cost = 0
if(pref.gear && pref.gear.len)
for(var/i = 1; i <= pref.gear.len; i++)
@@ -92,8 +93,8 @@ var/list/gear_datums = list()
var/fcolor = "#3366CC"
if(total_cost < MAX_GEAR_COST)
fcolor = "#E67300"
- . += list()
- . += ""
+
+ . += ""
. += "| [total_cost]/[MAX_GEAR_COST] loadout points spent. \[Clear Loadout\] |
"
. += "| "
@@ -105,9 +106,18 @@ var/list/gear_datums = list()
else
. += " |"
if(category == current_tab)
- . += " [category] "
+ . += " [category] "
else
- . += " [category] "
+ var/datum/loadout_category/LC = loadout_categories[category]
+ var/make_orange = FALSE
+ for(var/thing in LC.gear)
+ if(thing in pref.gear)
+ make_orange = TRUE
+ break
+ if(make_orange)
+ . += " [category] "
+ else
+ . += " [category] "
. += " |
"
var/datum/loadout_category/LC = loadout_categories[current_tab]
@@ -117,7 +127,7 @@ var/list/gear_datums = list()
for(var/gear_name in LC.gear)
var/datum/gear/G = LC.gear[gear_name]
var/ticked = (G.display_name in pref.gear)
- . += "| [G.display_name] | "
+ . += "
| [G.display_name] | "
. += "[G.cost] | "
. += "[G.description] |
"
if(ticked)
diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm
index 79e6a1ec7f..9f814743ae 100644
--- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm
@@ -12,55 +12,81 @@
whitelisted = "Unathi"
sort_category = "Xenowear"
-/datum/gear/ears/skrell
- display_name = "headtail-wear, female, chain (Skrell)"
+/datum/gear/ears/skrell/chains //Chains
+ display_name = "headtail chain selection (Skrell)"
path = /obj/item/clothing/ears/skrell/chain
sort_category = "Xenowear"
whitelisted = "Skrell"
-/datum/gear/ears/skrell/plate
- display_name = "headtail-wear, male, bands (Skrell)"
+/datum/gear/ears/skrell/chains/New()
+ ..()
+ var/list/chaintypes = list()
+ for(var/chain_style in typesof(/obj/item/clothing/ears/skrell/chain))
+ var/obj/item/clothing/ears/skrell/chain/chain = chain_style
+ chaintypes[initial(chain.name)] = chain
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(chaintypes))
+
+/datum/gear/ears/skrell/bands
+ display_name = "headtail band selection (Skrell)"
path = /obj/item/clothing/ears/skrell/band
+ sort_category = "Xenowear"
+ whitelisted = "Skrell"
-/datum/gear/ears/skrell/cloth //male/red
- display_name = "headtail-wear, male, red, cloth (Skrell)"
+/datum/gear/ears/skrell/bands/New()
+ ..()
+ var/list/bandtypes = list()
+ for(var/band_style in typesof(/obj/item/clothing/ears/skrell/band))
+ var/obj/item/clothing/ears/skrell/band/band = band_style
+ bandtypes[initial(band.name)] = band
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(bandtypes))
+
+/datum/gear/ears/skrell/cloth/male
+ display_name = "male headtail cloth selection (Skrell)"
path = /obj/item/clothing/ears/skrell/cloth_male
+ sort_category = "Xenowear"
+ whitelisted = "Skrell"
-/datum/gear/ears/skrell/cloth/male //black
- display_name = "headtail-wear, male, black, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_male/black
-
-/datum/gear/ears/skrell/cloth/male/blue
- display_name = "headtail-wear, male, blue, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_male/blue
-
-/datum/gear/ears/skrell/cloth/male/green
- display_name = "headtail-wear, male, green, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_male/green
-
-/datum/gear/ears/skrell/cloth/male/pink
- display_name = "headtail-wear, male, pink, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_male/pink
+/datum/gear/ears/skrell/cloth/male/New()
+ ..()
+ var/list/clothtypes = list()
+ for(var/cloth_style in typesof(/obj/item/clothing/ears/skrell/cloth_male))
+ var/obj/item/clothing/ears/skrell/cloth_male/cloth = cloth_style
+ clothtypes[initial(cloth.name)] = cloth
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(clothtypes))
/datum/gear/ears/skrell/cloth/female
- display_name = "headtail-wear, female, red, cloth (Skrell)"
+ display_name = "female headtail cloth selection (Skrell)"
path = /obj/item/clothing/ears/skrell/cloth_female
+ sort_category = "Xenowear"
+ whitelisted = "Skrell"
-/datum/gear/ears/skrell/cloth/female/black
- display_name = "headtail-wear, female, black, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_female/black
+/datum/gear/ears/skrell/cloth/female/New()
+ ..()
+ var/list/clothtypes = list()
+ for(var/cloth_style in typesof(/obj/item/clothing/ears/skrell/cloth_female))
+ var/obj/item/clothing/ears/skrell/cloth_female/cloth = cloth_style
+ clothtypes[initial(cloth.name)] = cloth
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(clothtypes))
-/datum/gear/ears/skrell/cloth/female/blue
- display_name = "headtail-wear, female, blue, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_female/blue
-
-/datum/gear/ears/skrell/cloth/female/green
- display_name = "headtail-wear, female, green, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_female/green
-
-/datum/gear/ears/skrell/cloth/female/pink
- display_name = "headtail-wear, female, pink, cloth (Skrell)"
- path = /obj/item/clothing/ears/skrell/cloth_female/pink
+/datum/gear/ears/skrell/colored/band
+ display_name = "Colored bands (Skrell)"
+ path = /obj/item/clothing/ears/skrell/colored/band
+ sort_category = "Xenowear"
+ whitelisted = "Skrell"
+
+/datum/gear/ears/skrell/colored/band/New()
+ ..()
+ gear_tweaks = list(gear_tweak_free_color_choice)
+
+/datum/gear/ears/skrell/colored/chain
+ display_name = "Colored chain (Skrell)"
+ path = /obj/item/clothing/ears/skrell/colored/chain
+ sort_category = "Xenowear"
+ whitelisted = "Skrell"
+
+/datum/gear/ears/skrell/colored/chain/New()
+ ..()
+ gear_tweaks = list(gear_tweak_free_color_choice)
/datum/gear/uniform/teshari
display_name = "smock, grey (Teshari)"
diff --git a/code/modules/client/preference_setup/occupation/occupation.dm b/code/modules/client/preference_setup/occupation/occupation.dm
index b177b7773f..b74e7035b3 100644
--- a/code/modules/client/preference_setup/occupation/occupation.dm
+++ b/code/modules/client/preference_setup/occupation/occupation.dm
@@ -58,6 +58,7 @@
if(!job_master)
return
+ . = list()
. += ""
. += "Choose occupation chances
Unavailable occupations are crossed out.
"
. += "| " // Table within a table for alignment, also allows you to easily add more columns.
@@ -125,21 +126,20 @@
if(job.alt_titles)
. += " |
|   | \[[pref.GetPlayerAltTitle(job)]\] |
"
. += ""
-
. += "
"
-
- . += "
"
+ . += "
"
switch(pref.alternate_option)
if(GET_RANDOM_JOB)
- . += "
Get random job if preferences unavailable
"
+ . += "Get random job if preferences unavailable"
if(BE_ASSISTANT)
- . += "
Be assistant if preference unavailable
"
+ . += "Be assistant if preference unavailable"
if(RETURN_TO_LOBBY)
- . += "
Return to lobby if preference unavailable
"
+ . += "Return to lobby if preference unavailable"
- . += "\[Reset\]"
+ . += "\[Reset\]"
. += ""
+ . = jointext(.,null)
/datum/category_item/player_setup_item/occupation/OnTopic(href, href_list, user)
if(href_list["reset_jobs"])
diff --git a/code/modules/client/preference_setup/skills/skills.dm b/code/modules/client/preference_setup/skills/skills.dm
index 8370f35668..7255e25bc4 100644
--- a/code/modules/client/preference_setup/skills/skills.dm
+++ b/code/modules/client/preference_setup/skills/skills.dm
@@ -19,6 +19,7 @@
if(pref.used_skillpoints < 0) pref.used_skillpoints = 0
/datum/category_item/player_setup_item/skills/content()
+ . = list()
. += "Select your Skills
"
. += "Current skill level: [pref.GetSkillClass(pref.used_skillpoints)] ([pref.used_skillpoints])
"
. += "Use preconfigured skillset
"
@@ -30,16 +31,22 @@
var/level = pref.skills[S.ID]
. += ""
. += "| [S.name] | "
- . += "\[Untrained\] | "
+ . += skill_to_button(S, "Untrained", level, SKILL_NONE)
// secondary skills don't have an amateur level
if(S.secondary)
. += " | "
else
- . += "\[Amateur\] | "
- . += "\[Trained\] | "
- . += "\[Professional\] | "
+ . += skill_to_button(S, "Amateur", level, SKILL_BASIC)
+ . += skill_to_button(S, "Trained", level, SKILL_ADEPT)
+ . += skill_to_button(S, "Professional", level, SKILL_EXPERT)
. += "
"
. += ""
+ . = jointext(.,null)
+
+/datum/category_item/player_setup_item/proc/skill_to_button(var/skill, var/level_name, var/current_level, var/selection_level)
+ if(current_level == selection_level)
+ return "[level_name] | "
+ return "[level_name] | "
/datum/category_item/player_setup_item/skills/OnTopic(href, href_list, user)
if(href_list["skillinfo"])
diff --git a/code/modules/clothing/ears/skrell.dm b/code/modules/clothing/ears/skrell.dm
index 59428fa5d9..e8bc3e8534 100644
--- a/code/modules/clothing/ears/skrell.dm
+++ b/code/modules/clothing/ears/skrell.dm
@@ -11,73 +11,135 @@
species_restricted = list("Skrell")
/obj/item/clothing/ears/skrell/chain
- name = "skrell headtail chains"
+ name = "Gold headtail chains"
desc = "A delicate golden chain worn by female skrell to decorate their head tails."
icon_state = "skrell_chain"
item_state = "skrell_chain"
-
+
+/obj/item/clothing/ears/skrell/chain/silver
+ name = "Silver headtail chains"
+ desc = "A delicate silver chain worn by female skrell to decorate their head tails."
+ icon_state = "skrell_chain_sil"
+ item_state = "skrell_chain_sil"
+
+/obj/item/clothing/ears/skrell/chain/bluejewels
+ name = "Blue jeweled golden headtail chains"
+ desc = "A delicate golden chain adorned with blue jewels worn by female skrell to decorate their head tails."
+ icon_state = "skrell_chain_bjewel"
+ item_state = "skrell_chain_bjewel"
+
+/obj/item/clothing/ears/skrell/chain/redjewels
+ name = "Red jeweled golden headtail chains"
+ desc = "A delicate golden chain adorned with red jewels worn by female skrell to decorate their head tails."
+ icon_state = "skrell_chain_rjewel"
+ item_state = "skrell_chain_rjewel"
+
+/obj/item/clothing/ears/skrell/chain/ebony
+ name = "Ebony headtail chains"
+ desc = "A delicate ebony chain worn by female skrell to decorate their head tails."
+ icon_state = "skrell_chain_ebony"
+ item_state = "skrell_chain_ebony"
+
/obj/item/clothing/ears/skrell/band
- name = "skrell headtail bands"
+ name = "Gold headtail bands"
desc = "Golden metallic bands worn by male skrell to adorn their head tails."
icon_state = "skrell_band"
item_state = "skrell_band"
+
+/obj/item/clothing/ears/skrell/band/silver
+ name = "Silver headtail bands"
+ desc = "Silver metallic bands worn by male skrell to adorn their head tails."
+ icon_state = "skrell_band_sil"
+ item_state = "skrell_band_sil"
+
+/obj/item/clothing/ears/skrell/band/bluejewels
+ name = "Blue jeweled golden headtail bands"
+ desc = "Golden metallic bands adorned with blue jewels worn by male skrell to adorn their head tails."
+ icon_state = "skrell_band_bjewel"
+ item_state = "skrell_band_bjewel"
+
+/obj/item/clothing/ears/skrell/band/redjewels
+ name = "Red jeweled golden headtail bands"
+ desc = "Golden metallic bands adorned with red jewels worn by male skrell to adorn their head tails."
+ icon_state = "skrell_band_rjewel"
+ item_state = "skrell_band_rjewel"
+
+/obj/item/clothing/ears/skrell/band/ebony
+ name = "Ebony headtail bands"
+ desc = "Ebony bands worn by male skrell to adorn their head tails."
+ icon_state = "skrell_band_ebony"
+ item_state = "skrell_band_ebony"
+/obj/item/clothing/ears/skrell/colored/band
+ name = "Colored headtail bands"
+ desc = "Metallic bands worn by male skrell to adorn their head tails."
+ icon_state = "skrell_band_sil"
+ item_state = "skrell_band_sil"
+
+/obj/item/clothing/ears/skrell/colored/chain
+ name = "Colored headtail chains"
+ desc = "A delicate chain worn by female skrell to decorate their head tails."
+ icon_state = "skrell_chain_sil"
+ item_state = "skrell_chain_sil"
+
/obj/item/clothing/ears/skrell/cloth_female
- name = "skrell headtail cloth"
+ name = "red headtail cloth"
desc = "A cloth shawl worn by female skrell draped around their head tails."
icon_state = "skrell_cloth_female"
item_state = "skrell_cloth_female"
/obj/item/clothing/ears/skrell/cloth_female/black
- name = "skrell headtail cloth"
- desc = "A cloth shawl worn by female skrell draped around their head tails."
+ name = "black headtail cloth"
icon_state = "skrell_cloth_black_female"
item_state = "skrell_cloth_black_female"
/obj/item/clothing/ears/skrell/cloth_female/blue
- name = "skrell headtail cloth"
- desc = "A cloth shawl worn by female skrell draped around their head tails."
+ name = "blue headtail cloth"
icon_state = "skrell_cloth_blue_female"
item_state = "skrell_cloth_blue_female"
/obj/item/clothing/ears/skrell/cloth_female/green
- name = "skrell headtail cloth"
- desc = "A cloth shawl worn by female skrell draped around their head tails."
+ name = "green headtail cloth"
icon_state = "skrell_cloth_green_female"
item_state = "skrell_cloth_green_female"
/obj/item/clothing/ears/skrell/cloth_female/pink
- name = "skrell headtail cloth"
- desc = "A cloth shawl worn by female skrell draped around their head tails."
+ name = "pink headtail cloth"
icon_state = "skrell_cloth_pink_female"
item_state = "skrell_cloth_pink_female"
+/obj/item/clothing/ears/skrell/cloth_female/lightblue
+ name = "light blue headtail cloth"
+ icon_state = "skrell_cloth_lblue_female"
+ item_state = "skrell_cloth_lblue_female"
+
/obj/item/clothing/ears/skrell/cloth_male
- name = "skrell headtail cloth"
+ name = "red headtail cloth"
desc = "A cloth band worn by male skrell around their head tails."
icon_state = "skrell_cloth_male"
item_state = "skrell_cloth_male"
/obj/item/clothing/ears/skrell/cloth_male/black
- name = "skrell headtail cloth"
- desc = "A cloth band worn by male skrell around their head tails."
+ name = "black headtail cloth"
icon_state = "skrell_cloth_black_male"
item_state = "skrell_cloth_black_male"
/obj/item/clothing/ears/skrell/cloth_male/blue
- name = "skrell headtail cloth"
- desc = "A cloth band worn by male skrell around their head tails."
+ name = "blue headtail cloth"
icon_state = "skrell_cloth_blue_male"
item_state = "skrell_cloth_blue_male"
/obj/item/clothing/ears/skrell/cloth_male/green
- name = "skrell headtail cloth"
- desc = "A cloth band worn by male skrell around their head tails."
+ name = "green headtail cloth"
icon_state = "skrell_cloth_green_male"
item_state = "skrell_cloth_green_male"
/obj/item/clothing/ears/skrell/cloth_male/pink
- name = "skrell headtail cloth"
- desc = "A cloth band worn by male skrell around their head tails."
+ name = "pink headtail cloth"
icon_state = "skrell_cloth_pink_male"
- item_state = "skrell_cloth_pink_male"
\ No newline at end of file
+ item_state = "skrell_cloth_pink_male"
+
+/obj/item/clothing/ears/skrell/cloth_male/lightblue
+ name = "light blue headtail cloth"
+ icon_state = "skrell_cloth_lblue_male"
+ item_state = "skrell_cloth_lblue_male"
\ No newline at end of file
diff --git a/code/modules/economy/economy_misc.dm b/code/modules/economy/economy_misc.dm
index 8c39fcac8d..1e87b98e4c 100644
--- a/code/modules/economy/economy_misc.dm
+++ b/code/modules/economy/economy_misc.dm
@@ -48,11 +48,12 @@
/var/list/economic_species_modifier = list(
- /datum/species/human = 10,
- /datum/species/skrell = 12,
- /datum/species/teshari = 9, // Skrell sponsored,
- /datum/species/tajaran = 7,
- /datum/species/unathi = 7
+ /datum/species/human = 10,
+ /datum/species/skrell = 12,
+ /datum/species/teshari = 9, // Skrell sponsored,
+ /datum/species/tajaran = 7,
+ /datum/species/unathi = 7,
+ /datum/species/diona = 7
)
//---- The following corporations are friendly with NanoTrasen and loosely enable trade and travel:
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 0fb90dbc75..4195f963c2 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -561,13 +561,15 @@ var/global/list/damage_icon_parts = list()
/mob/living/carbon/human/update_inv_glasses(var/update_icons=1)
if(glasses)
-
+ var/image/standing
if(glasses.icon_override)
- overlays_standing[GLASSES_LAYER] = image("icon" = glasses.icon_override, "icon_state" = "[glasses.icon_state]")
+ standing = image("icon" = glasses.icon_override, "icon_state" = "[glasses.icon_state]")
else if(glasses.sprite_sheets && glasses.sprite_sheets[species.get_bodytype(src)])
- overlays_standing[GLASSES_LAYER]= image("icon" = glasses.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[glasses.icon_state]")
+ standing = image("icon" = glasses.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[glasses.icon_state]")
else
- overlays_standing[GLASSES_LAYER]= image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]")
+ standing = image("icon" = 'icons/mob/eyes.dmi', "icon_state" = "[glasses.icon_state]")
+ standing.color = glasses.color
+ overlays_standing[GLASSES_LAYER] = standing
else
overlays_standing[GLASSES_LAYER] = null
@@ -580,29 +582,37 @@ var/global/list/damage_icon_parts = list()
return
if(l_ear || r_ear)
+ var/image/both = image("icon" = null)
+
if(l_ear)
-
+ var/image/standing
var/t_type = l_ear.icon_state
if(l_ear.icon_override)
t_type = "[t_type]_l"
- overlays_standing[EARS_LAYER] = image("icon" = l_ear.icon_override, "icon_state" = "[t_type]")
+ standing = image("icon" = l_ear.icon_override, "icon_state" = "[t_type]")
else if(l_ear.sprite_sheets && l_ear.sprite_sheets[species.get_bodytype(src)])
t_type = "[t_type]_l"
- overlays_standing[EARS_LAYER] = image("icon" = l_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]")
+ standing = image("icon" = l_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]")
else
- overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
-
+ standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
+ standing.color = l_ear.color
+ both.overlays += standing
+
if(r_ear)
-
+ var/image/standing
var/t_type = r_ear.icon_state
if(r_ear.icon_override)
t_type = "[t_type]_r"
- overlays_standing[EARS_LAYER] = image("icon" = r_ear.icon_override, "icon_state" = "[t_type]")
+ standing = image("icon" = r_ear.icon_override, "icon_state" = "[t_type]")
else if(r_ear.sprite_sheets && r_ear.sprite_sheets[species.get_bodytype(src)])
t_type = "[t_type]_r"
- overlays_standing[EARS_LAYER] = image("icon" = r_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]")
+ standing = image("icon" = r_ear.sprite_sheets[species.get_bodytype(src)], "icon_state" = "[t_type]")
else
- overlays_standing[EARS_LAYER] = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
+ standing = image("icon" = 'icons/mob/ears.dmi', "icon_state" = "[t_type]")
+ standing.color = r_ear.color
+ both.overlays += standing
+
+ overlays_standing[EARS_LAYER] = both
else
overlays_standing[EARS_LAYER] = null
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 53927668f8..0052b77578 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -31,9 +31,9 @@
if(!ticker || ticker.current_state <= GAME_STATE_PREGAME)
if(ready)
- output += "\[ Ready | Not Ready \]
"
+ output += "\[ Ready | Not Ready \]
"
else
- output += "\[ Ready | Not Ready \]
"
+ output += "\[ Ready | Not Ready \]
"
else
output += "View the Crew Manifest
"
@@ -62,8 +62,7 @@
output += ""
- //src << browse(output,"window=playersetup;size=210x280;can_close=0")
- panel = new(src, "New Player","New Player", 210, 280, src)
+ panel = new(src, "Welcome","Welcome", 210, 280, src)
panel.set_window_options("can_close=0")
panel.set_content(output)
panel.open()
diff --git a/code/modules/organs/wound.dm b/code/modules/organs/wound.dm
index 3cf3ecb239..2c97bf4cfc 100644
--- a/code/modules/organs/wound.dm
+++ b/code/modules/organs/wound.dm
@@ -13,6 +13,8 @@
var/damage = 0
// ticks of bleeding left.
var/bleed_timer = 0
+ // Above this amount wounds you will need to treat the wound to stop bleeding, regardless of bleed_timer
+ var/bleed_threshold = 30
// amount of damage the current wound type requires(less means we need to apply the next healing stage)
var/min_damage = 0
@@ -187,7 +189,7 @@
return 0 //incompatible damage types
if (src.amount > 1)
- return 0
+ return 0//merged wounds cannot be worsened.
//with 1.5*, a shallow cut will be able to carry at most 30 damage,
//37.5 for a deep cut
@@ -208,8 +210,8 @@
if (bandaged||clamped)
return 0
- if (wound_damage() <= 30 && bleed_timer <= 0)
- return 0 //Bleed timer has run out. Wounds with more than 30 damage don't stop bleeding on their own.
+ if (bleed_timer <= 0 && wound_damage() <= bleed_threshold)
+ return 0 //Bleed timer has run out. Once a wound is big enough though, you'll need a bandage to stop it
return 1
@@ -264,8 +266,9 @@
return null //no wound
/** CUTS **/
-/datum/wound/cut/bleeding()
- return ..() || wound_damage() >= 5
+/datum/wound/cut
+ bleed_threshold = 5
+ damage_type = CUT
/datum/wound/cut/small
// link wound descriptions to amounts of damage
@@ -273,40 +276,34 @@
// The major cut types have the max_bleeding_stage set to the clot stage (which is accordingly given the "blood soaked" descriptor).
max_bleeding_stage = 3
stages = list("ugly ripped cut" = 20, "ripped cut" = 10, "cut" = 5, "healing cut" = 2, "small scab" = 0)
- damage_type = CUT
/datum/wound/cut/deep
max_bleeding_stage = 3
stages = list("ugly deep ripped cut" = 25, "deep ripped cut" = 20, "deep cut" = 15, "clotted cut" = 8, "scab" = 2, "fresh skin" = 0)
- damage_type = CUT
/datum/wound/cut/flesh
max_bleeding_stage = 4
stages = list("ugly ripped flesh wound" = 35, "ugly flesh wound" = 30, "flesh wound" = 25, "blood soaked clot" = 15, "large scab" = 5, "fresh skin" = 0)
- damage_type = CUT
/datum/wound/cut/gaping
max_bleeding_stage = 3
stages = list("gaping wound" = 50, "large blood soaked clot" = 25, "blood soaked clot" = 15, "small angry scar" = 5, "small straight scar" = 0)
- damage_type = CUT
/datum/wound/cut/gaping_big
max_bleeding_stage = 3
stages = list("big gaping wound" = 60, "healing gaping wound" = 40, "large blood soaked clot" = 25, "large angry scar" = 10, "large straight scar" = 0)
- damage_type = CUT
datum/wound/cut/massive
max_bleeding_stage = 3
stages = list("massive wound" = 70, "massive healing wound" = 50, "massive blood soaked clot" = 25, "massive angry scar" = 10, "massive jagged scar" = 0)
- damage_type = CUT
/** PUNCTURES **/
+/datum/wound/puncture
+ bleed_threshold = 5
+ damage_type = PIERCE
+
/datum/wound/puncture/can_worsen(damage_type, damage)
- return 0
-/datum/wound/puncture/can_merge(var/datum/wound/other)
- return 0
-/datum/wound/puncture/bleeding()
- return ..() || wound_damage() >= 5
+ return 0 //puncture wounds cannot be enlargened
/datum/wound/puncture/small
max_bleeding_stage = 2
@@ -334,41 +331,36 @@ datum/wound/puncture/massive
damage_type = PIERCE
/** BRUISES **/
-/datum/wound/bruise/bleeding()
- return ..() || wound_damage() >= 20
-
/datum/wound/bruise
stages = list("monumental bruise" = 80, "huge bruise" = 50, "large bruise" = 30,
"moderate bruise" = 20, "small bruise" = 10, "tiny bruise" = 5)
+ bleed_threshold = 20
max_bleeding_stage = 3 //only large bruise and above can bleed.
autoheal_cutoff = 30
damage_type = BRUISE
/** BURNS **/
/datum/wound/burn
+ damage_type = BURN
max_bleeding_stage = 0
+
/datum/wound/burn/bleeding()
return 0
/datum/wound/burn/moderate
stages = list("ripped burn" = 10, "moderate burn" = 5, "healing moderate burn" = 2, "fresh skin" = 0)
- damage_type = BURN
/datum/wound/burn/large
stages = list("ripped large burn" = 20, "large burn" = 15, "healing large burn" = 5, "fresh skin" = 0)
- damage_type = BURN
/datum/wound/burn/severe
stages = list("ripped severe burn" = 35, "severe burn" = 30, "healing severe burn" = 10, "burn scar" = 0)
- damage_type = BURN
/datum/wound/burn/deep
stages = list("ripped deep burn" = 45, "deep burn" = 40, "healing deep burn" = 15, "large burn scar" = 0)
- damage_type = BURN
/datum/wound/burn/carbonised
stages = list("carbonised area" = 50, "healing carbonised area" = 20, "massive burn scar" = 0)
- damage_type = BURN
/** INTERNAL BLEEDING **/
/datum/wound/internal_bleeding
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index d56c298b6c..66155da7ea 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -14,7 +14,7 @@
kill_count = 15 //if the shell hasn't hit anything after travelling this far it just explodes.
var/flash_range = 0
var/brightness = 7
- var/light_duration = 5
+ var/light_colour = "#ffffff"
/obj/item/projectile/energy/flash/on_impact(var/atom/A)
var/turf/T = flash_range? src.loc : get_turf(A)
@@ -29,16 +29,25 @@
playsound(src, 'sound/effects/snap.ogg', 50, 1)
src.visible_message("\The [src] explodes in a bright flash!")
- new /obj/effect/decal/cleanable/ash(src.loc) //always use src.loc so that ash doesn't end up inside windows
- new /obj/effect/effect/sparks(T)
- new /obj/effect/effect/smoke/illumination(T, brightness=max(flash_range*2, brightness), lifetime=light_duration)
+ var/datum/effect/effect/system/spark_spread/sparks = PoolOrNew(/datum/effect/effect/system/spark_spread)
+ sparks.set_up(2, 1, T)
+ sparks.start()
+ new /obj/effect/decal/cleanable/ash(src.loc) //always use src.loc so that ash doesn't end up inside windows
+ new /obj/effect/effect/smoke/illumination(T, 5, brightness, brightness, light_colour)
//blinds people like the flash round, but can also be used for temporary illumination
/obj/item/projectile/energy/flash/flare
damage = 10
flash_range = 1
- brightness = 9 //similar to a flare
- light_duration = 200
+ brightness = 15
+
+/obj/item/projectile/energy/flash/flare/on_impact(var/atom/A)
+ light_colour = pick("#e58775", "#ffffff", "#90ff90", "#a09030")
+
+ ..() //initial flash
+
+ //residual illumination
+ new /obj/effect/effect/smoke/illumination(src.loc, rand(190,240) SECONDS, range=8, power=3, color=light_colour) //same lighting power as flare
/obj/item/projectile/energy/electrode
name = "electrode"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
index 26b58eed31..4c3e461a27 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm
@@ -375,6 +375,24 @@
/datum/reagent/sugar/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
M.nutrition += removed * 3
+ var/effective_dose = dose
+ if(issmall(M))
+ effective_dose *= 2
+
+ if(alien == IS_UNATHI)
+ if(effective_dose < 2)
+ if(effective_dose == metabolism * 2 || prob(5))
+ M.emote("yawn")
+ else if(effective_dose < 5)
+ M.eye_blurry = max(M.eye_blurry, 10)
+ else if(effective_dose < 20)
+ if(prob(50))
+ M.Weaken(2)
+ M.drowsyness = max(M.drowsyness, 20)
+ else
+ M.sleeping = max(M.sleeping, 20)
+ M.drowsyness = max(M.drowsyness, 60)
+
/datum/reagent/sulfur
name = "Sulfur"
id = "sulfur"
diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
index 637470e7cc..be96e6665a 100644
--- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
+++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm
@@ -17,6 +17,8 @@
affect_ingest(M, alien, removed)
/datum/reagent/nutriment/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ switch(alien)
+ if(IS_UNATHI) removed *= 0.5
if(issmall(M)) removed *= 2 // Small bodymass, more effect from lower volume.
M.heal_organ_damage(0.5 * removed, 0)
M.nutrition += nutriment_factor * removed // For hunger and fatness
@@ -42,6 +44,8 @@
if(IS_TESHARI)
..(M, alien, removed*1.2) // Teshari get a bit more nutrition from meat.
return
+ if(IS_UNATHI)
+ ..(M, alien, removed*2.25) //Unathi get most of their nutrition from meat.
..()
/datum/reagent/nutriment/protein/affect_blood(var/mob/living/carbon/M, var/alien, var/removed)
@@ -62,6 +66,27 @@
nutriment_factor = 10
color = "#FFFF00"
+/datum/reagent/honey/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+
+ var/effective_dose = dose
+ if(issmall(M))
+ effective_dose *= 2
+
+ if(alien == IS_UNATHI)
+ if(effective_dose < 2)
+ if(effective_dose == metabolism * 2 || prob(5))
+ M.emote("yawn")
+ else if(effective_dose < 5)
+ M.eye_blurry = max(M.eye_blurry, 10)
+ else if(effective_dose < 20)
+ if(prob(50))
+ M.Weaken(2)
+ M.drowsyness = max(M.drowsyness, 20)
+ else
+ M.sleeping = max(M.sleeping, 20)
+ M.drowsyness = max(M.drowsyness, 60)
+
/datum/reagent/nutriment/flour
name = "flour"
id = "flour"
@@ -396,6 +421,27 @@
glass_name = "glass of grape juice"
glass_desc = "It's grrrrrape!"
+/datum/reagent/juice/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+
+ var/effective_dose = dose/2
+ if(issmall(M))
+ effective_dose *= 2
+
+ if(alien == IS_UNATHI)
+ if(effective_dose < 2)
+ if(effective_dose == metabolism * 2 || prob(5))
+ M.emote("yawn")
+ else if(effective_dose < 5)
+ M.eye_blurry = max(M.eye_blurry, 10)
+ else if(effective_dose < 20)
+ if(prob(50))
+ M.Weaken(2)
+ M.drowsyness = max(M.drowsyness, 20)
+ else
+ M.sleeping = max(M.sleeping, 20)
+ M.drowsyness = max(M.drowsyness, 60)
+
/datum/reagent/drink/juice/lemon
name = "Lemon Juice"
id = "lemonjuice"
@@ -765,6 +811,27 @@
glass_desc = "Glorious brainfreezing mixture."
glass_center_of_mass = list("x"=16, "y"=7)
+/datum/reagent/milkshake/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed)
+ ..()
+
+ var/effective_dose = dose/2
+ if(issmall(M))
+ effective_dose *= 2
+
+ if(alien == IS_UNATHI)
+ if(effective_dose < 2)
+ if(effective_dose == metabolism * 2 || prob(5))
+ M.emote("yawn")
+ else if(effective_dose < 5)
+ M.eye_blurry = max(M.eye_blurry, 10)
+ else if(effective_dose < 20)
+ if(prob(50))
+ M.Weaken(2)
+ M.drowsyness = max(M.drowsyness, 20)
+ else
+ M.sleeping = max(M.sleeping, 20)
+ M.drowsyness = max(M.drowsyness, 60)
+
/datum/reagent/drink/rewriter
name = "Rewriter"
description = "The secret of the sanctuary of the Libarian..."
diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm
index f178a6a45b..7ea873c8d0 100644
--- a/code/modules/surgery/implant.dm
+++ b/code/modules/surgery/implant.dm
@@ -153,8 +153,12 @@
max_duration = 100
can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
- var/obj/item/organ/internal/brain/sponge = target.internal_organs_by_name["brain"]
- return ..() && (!sponge || !sponge.damage)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(affected.organ_tag == BP_HEAD)
+ var/obj/item/organ/internal/brain/sponge = target.internal_organs_by_name["brain"]
+ return ..() && (!sponge || !sponge.damage)
+ else
+ return ..()
begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
diff --git a/code/world.dm b/code/world.dm
index d82b636e87..bfa399fe2a 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -558,8 +558,9 @@ var/failed_db_connections = 0
var/failed_old_db_connections = 0
/hook/startup/proc/connectDB()
- if(!config.sql_enabled) return 1
- if(!setup_database_connection())
+ if(!config.sql_enabled)
+ world.log << "SQL connection disabled in config."
+ else if(!setup_database_connection())
world.log << "Your server failed to establish a connection with the feedback database."
else
world.log << "Feedback database connection established."
@@ -601,8 +602,9 @@ proc/establish_db_connection()
/hook/startup/proc/connectOldDB()
- if(!config.sql_enabled) return 1
- if(!setup_old_database_connection())
+ if(!config.sql_enabled)
+ world.log << "SQL connection disabled in config."
+ else if(!setup_old_database_connection())
world.log << "Your server failed to establish a connection with the SQL database."
else
world.log << "SQL database connection established."
diff --git a/config/example/config.txt b/config/example/config.txt
index c1ce782235..ec93429827 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -67,8 +67,8 @@ LOG_PDA
## log admin warning messages
##LOG_ADMINWARN ## Also duplicates a bunch of other messages.
-## sql switching
-SQL_ENABLED 1
+## Enable/disable SQL connection (comment out to disable)
+SQL_ENABLED
## disconnect players who did nothing during the set amount of minutes
# KICK_INACTIVE 10
diff --git a/html/changelog.html b/html/changelog.html
index 38b2166002..3ef596ac8c 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -53,6 +53,17 @@
-->
+
12 May 2016
+
Yoshax updated:
+
+ - Doubles the maximum length of records and names to 6144 & 52, respectively. Also increases book length to 12288. (All numbers are in characters.)
+ - Makes various services in the antag uplink purchasable once again. This includes the fake crew arrival.
+ - Neckgrabs will no longer force people to the ground. In addition, weakened people can no longer resist.
+ - All vending machines now have a small chance of vending an additional item.
+ - Smoke from smoke bombs now lasts approximately 3 times as long and spawns some more smoke to make a heavier cloud.
+ - Smoke from smoke bombs now properly does a small amount of oxygen loss damage. This damage is per cloud of smoke.
+
+
05 May 2016
Datraen updated:
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index eb9a43d8ae..2e9cb1594e 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -2257,3 +2257,17 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
records and such. '
- tweak: Smoke grenades can now have their smoke color set by using a multitool
on them.
+2016-05-12:
+ Yoshax:
+ - tweak: Doubles the maximum length of records and names to 6144 & 52, respectively.
+ Also increases book length to 12288. (All numbers are in characters.)
+ - bugfix: Makes various services in the antag uplink purchasable once again. This
+ includes the fake crew arrival.
+ - bugifx: Neckgrabs will no longer force people to the ground. In addition, weakened
+ people can no longer resist.
+ - rscadd: All vending machines now have a small chance of vending an additional
+ item.
+ - tweak: Smoke from smoke bombs now lasts approximately 3 times as long and spawns
+ some more smoke to make a heavier cloud.
+ - bugfix: Smoke from smoke bombs now properly does a small amount of oxygen loss
+ damage. This damage is per cloud of smoke.
diff --git a/html/changelogs/HarpyEagle - lightingadditions.yml b/html/changelogs/HarpyEagle - lightingadditions.yml
new file mode 100644
index 0000000000..8cf4b825e3
--- /dev/null
+++ b/html/changelogs/HarpyEagle - lightingadditions.yml
@@ -0,0 +1,38 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: HarpyEagle
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - tweak: "Shotgun flare illumination now lasts longer, around 3-4 minutes."
+ - bugfix: "Fixed attack animation playing when using flashes even if the flash was not actually used due to being broken or recharging."
+ - bugfix: "Fixed lightswitches layering over darkness. Now only the light layers above shadow. Lightswitch illumination is now much more subtle."
diff --git a/html/changelogs/Yoshax - smokefix.yml b/html/changelogs/Yoshax - changelingflavortext.yml
similarity index 84%
rename from html/changelogs/Yoshax - smokefix.yml
rename to html/changelogs/Yoshax - changelingflavortext.yml
index 4e5be137a9..430ab2d979 100644
--- a/html/changelogs/Yoshax - smokefix.yml
+++ b/html/changelogs/Yoshax - changelingflavortext.yml
@@ -33,5 +33,4 @@ delete-after: True
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- - tweak: "Smoke from smoke bombs now lasts approximately 3 times as long and spawns some more smoke to make a heavier cloud."
- - bugfix: "Smoke from smoe bombs now properly does a small amount of oxloss. This damage is per cloud of smoke."
\ No newline at end of file
+ - rscadd: "Changelings will now store and apply the flavor text of their victims when they absorb and transform into them."
diff --git a/html/changelogs/Yoshax - featuresandfixes.txt b/html/changelogs/Yoshax - dionarights.yml
similarity index 73%
rename from html/changelogs/Yoshax - featuresandfixes.txt
rename to html/changelogs/Yoshax - dionarights.yml
index 14389bfc92..705a4dbbaa 100644
--- a/html/changelogs/Yoshax - featuresandfixes.txt
+++ b/html/changelogs/Yoshax - dionarights.yml
@@ -33,8 +33,4 @@ delete-after: True
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- - tweak: "Doubles the maximum length of records and names to 6144 & 52, resptively. Also increases book nelngth to 12288. (All numbers are in charatcers.)
- - bugfix: "Makes various services in the antag uplink purchasable once again. This includes the fake crew arrival."
- - bugifx: "Neckgrabs will no longer force people to the ground. In addition, weakened people can no longer resist."
- - rscadd: "All vending machines now have a small chance of vending an additional item."
-
+ - rscadd: "Gives Diona a starting funds wage the same as Tajaran and Unathi."
\ No newline at end of file
diff --git a/html/changelogs/Yoshax - surgeryfix.yml b/html/changelogs/Yoshax - surgeryfix.yml
new file mode 100644
index 0000000000..af529c37df
--- /dev/null
+++ b/html/changelogs/Yoshax - surgeryfix.yml
@@ -0,0 +1,36 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Yoshax
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - bugfix: "Brain damage no longer prevent implant removal surgery."
diff --git a/icons/mob/ears.dmi b/icons/mob/ears.dmi
index eeabb79eb4..7326be690e 100644
Binary files a/icons/mob/ears.dmi and b/icons/mob/ears.dmi differ
diff --git a/icons/obj/clothing/ears.dmi b/icons/obj/clothing/ears.dmi
index 318c17d9be..a2c81adfbe 100644
Binary files a/icons/obj/clothing/ears.dmi and b/icons/obj/clothing/ears.dmi differ
diff --git a/icons/obj/power.dmi b/icons/obj/power.dmi
index 099070a4fc..80d768dfe5 100644
Binary files a/icons/obj/power.dmi and b/icons/obj/power.dmi differ
diff --git a/maps/polaris-3.dmm b/maps/polaris-3.dmm
index 3e4489a897..b9a4285c6d 100644
--- a/maps/polaris-3.dmm
+++ b/maps/polaris-3.dmm
@@ -233,6 +233,7 @@
"ey" = (/obj/machinery/airlock_sensor/airlock_interior{frequency = 1381; id_tag = "server_access_in_sensor"; name = "interior sensor"; pixel_y = 25},/obj/structure/sign/securearea{desc = "A warning sign which reads 'SERVER ROOM'."; name = "SERVER ROOM"; pixel_y = 32},/turf/simulated/floor/bluegrid{name = "Mainframe Base"; nitrogen = 100; oxygen = 0; temperature = 80},/area/tcommsat/chamber)
"ez" = (/turf/simulated/floor/tiled/dark{nitrogen = 100; oxygen = 0; temperature = 80},/area/tcommsat/chamber)
"eA" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'SERVER ROOM'."; name = "SERVER ROOM"; pixel_y = 32},/turf/simulated/floor/bluegrid{name = "Mainframe Base"; nitrogen = 100; oxygen = 0; temperature = 80},/area/tcommsat/chamber)
+"eB" = (/obj/machinery/pda_multicaster/prebuilt,/turf/simulated/floor/tiled/dark{nitrogen = 100; oxygen = 0; temperature = 80},/area/tcommsat/chamber)
"eC" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/tcomsat)
"eD" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/lattice,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/space,/area/tcomsat)
"eE" = (/obj/machinery/atmospherics/pipe/simple/hidden/black,/turf/simulated/floor/tiled/dark{nitrogen = 100; oxygen = 0; temperature = 80},/area/tcommsat/chamber)
@@ -541,7 +542,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYaaaaaTaTaTaTaTaTaTaTaTcecgcfclclcncncnefdSfldGfmfofnfpewfqfhfxewfsfrftfudGfvfwdyfIfyfzfAclclchcgciaTaTaTaTaTaTaTaTaTaaaabYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYaaaaaTaaaaaaaaaaaaaTaabqaabqclclcocncocRdScXdGerfEfDezeEezerezeEezfFfGerdGcRemfHfLfJfKfMclclbqaabqaaaTaaaaaaaaaaaaaTaaaabYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYaacacacacacacacacacacabqaabqclclcocncocReVcXdGerezezezeEezerezeEezezezerdGcRemcXeLfNfOfPclclbqaabqcacacacacacacacacacaaabYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYaTcbcbcbcbcbcbcbcbcbcbboaTbqclclcocncocRdScXdGerfRfQfTfSezezezfUfWfVfXerdGcRemcXfYeFeHclclclbqaTblccccccccccccccccccccaTbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYaTcbcbcbcbcbcbcbcbcbcbboaTbqclclcocncocRdScXdGerfRfQfTfSezeBezfUfWfVfXerdGcRemcXfYeFeHclclclbqaTblccccccccccccccccccccaTbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYaacdcdcdcdcdcdcdcdcdcdaaaabqclclcocncocRdScXdGerererfZerergaerergberererdGcRemcXcocncoclclbtboaaaacdcdcdcdcdcdcdcdcdcdaabYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaTaaaaaaaaaaaaaTaaaaaabqclclcneecnefeVcIdGdGdGdGdGdGdGdGdGdGdGdGdGdGdGefemcIcneecnclclbqaaaaaaaaaTaaaaaaaaaaaaaTaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabYbYbYbYbYbYbYbYbYbYaaaabqclclcocncocReVgdgedkdkgfgggcgighglgjgmgfdkdkgngoemcXcocncoclclbqaaaaaabYbYbYbYbYbYbYbYbYbYaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
diff --git a/vorestation.dme b/vorestation.dme
index 904f78b64b..f80e79a8a8 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -133,6 +133,8 @@
#include "code\controllers\subsystems.dm"
#include "code\controllers\verbs.dm"
#include "code\controllers\voting.dm"
+#include "code\controllers\observer_listener\atom\observer.dm"
+#include "code\controllers\observer_listener\datum\observer.dm"
#include "code\controllers\Processes\air.dm"
#include "code\controllers\Processes\alarm.dm"
#include "code\controllers\Processes\chemistry.dm"
@@ -419,6 +421,7 @@
#include "code\game\machinery\nuclear_bomb.dm"
#include "code\game\machinery\OpTable.dm"
#include "code\game\machinery\overview.dm"
+#include "code\game\machinery\pda_multicaster.dm"
#include "code\game\machinery\portable_turret.dm"
#include "code\game\machinery\recharger.dm"
#include "code\game\machinery\rechargestation.dm"
@@ -624,6 +627,7 @@
#include "code\game\objects\items\devices\flash.dm"
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
+#include "code\game\objects\items\devices\hacktool.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\locker_painter.dm"
#include "code\game\objects\items\devices\megaphone.dm"
@@ -1016,6 +1020,7 @@
#include "code\modules\client\preference_setup\global\02_settings.dm"
#include "code\modules\client\preference_setup\global\03_pai.dm"
#include "code\modules\client\preference_setup\global\04_communicators.dm"
+#include "code\modules\client\preference_setup\global\05_ooc.dm"
#include "code\modules\client\preference_setup\global\setting_datums.dm"
#include "code\modules\client\preference_setup\loadout\gear_tweaks.dm"
#include "code\modules\client\preference_setup\loadout\loadout.dm"