diff --git a/baystation12.dme b/baystation12.dme
index 0695839aea3..ec5a6267ce1 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -16,7 +16,6 @@
#include "code\setup.dm"
#include "code\stylesheet.dm"
#include "code\world.dm"
-#include "code\__HELPERS\bygex.dm"
#include "code\__HELPERS\files.dm"
#include "code\__HELPERS\game.dm"
#include "code\__HELPERS\global_lists.dm"
@@ -178,9 +177,14 @@
#include "code\game\area\ai_monitored.dm"
#include "code\game\area\areas.dm"
#include "code\game\area\Space Station 13 areas.dm"
-#include "code\game\dna\dna.dm"
-#include "code\game\dna\dna_misc.dm"
+#include "code\game\dna\dna2.dm"
+#include "code\game\dna\dna2_domutcheck.dm"
+#include "code\game\dna\dna2_helpers.dm"
#include "code\game\dna\dna_modifier.dm"
+#include "code\game\dna\genes\disabilities.dm"
+#include "code\game\dna\genes\gene.dm"
+#include "code\game\dna\genes\monkey.dm"
+#include "code\game\dna\genes\powers.dm"
#include "code\game\gamemodes\events.dm"
#include "code\game\gamemodes\factions.dm"
#include "code\game\gamemodes\game_mode.dm"
@@ -267,6 +271,7 @@
#include "code\game\machinery\cloning.dm"
#include "code\game\machinery\constructable_frame.dm"
#include "code\game\machinery\cryo.dm"
+#include "code\game\machinery\cryopod.dm"
#include "code\game\machinery\deployable.dm"
#include "code\game\machinery\door_control.dm"
#include "code\game\machinery\doppler_array.dm"
@@ -781,6 +786,7 @@
#include "code\modules\economy\TradeDestinations.dm"
#include "code\modules\events\alien_infestation.dm"
#include "code\modules\events\blob.dm"
+#include "code\modules\events\borers.dm"
#include "code\modules\events\brand_intelligence.dm"
#include "code\modules\events\carp_migration.dm"
#include "code\modules\events\comms_blackout.dm"
@@ -834,6 +840,7 @@
#include "code\modules\mining\money_bag.dm"
#include "code\modules\mining\ores_coins.dm"
#include "code\modules\mining\satchel_ore_boxdm.dm"
+#include "code\modules\mob\abilities.dm"
#include "code\modules\mob\death.dm"
#include "code\modules\mob\emote.dm"
#include "code\modules\mob\inventory.dm"
@@ -1299,6 +1306,7 @@
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\LaserComputer.dm"
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\ZeroPointLaser.dm"
#include "code\WorkInProgress\Chinsky\ashtray.dm"
+#include "code\WorkInProgress\Chinsky\guestpass.dm"
#include "code\WorkInProgress\Cib\MedicalSideEffects.dm"
#include "code\WorkInProgress\kilakk\fax.dm"
#include "code\WorkInProgress\Mini\atmos_control.dm"
diff --git a/bygex.dll b/bygex.dll
deleted file mode 100644
index e7bdd9f9a78..00000000000
Binary files a/bygex.dll and /dev/null differ
diff --git a/code/WorkInProgress/Chinsky/ashtray.dm b/code/WorkInProgress/Chinsky/ashtray.dm
index ab3a6362515..5ec88ac8bdf 100644
--- a/code/WorkInProgress/Chinsky/ashtray.dm
+++ b/code/WorkInProgress/Chinsky/ashtray.dm
@@ -17,35 +17,34 @@
/obj/item/ashtray/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (health < 1)
return
- if (istype(W,/obj/item/clothing/mask/cigarette) || istype(W, /obj/item/weapon/match))
- if(user)
- if (contents.len >= max_butts)
- user << "This ashtray is full."
- return
- user.u_equip(W)
- W.loc = src
- if ((user.client && user.s_active != src))
- user.client.screen -= W
+ if (istype(W,/obj/item/weapon/cigbutt) || istype(W,/obj/item/clothing/mask/cigarette) || istype(W, /obj/item/weapon/match))
+ if (contents.len >= max_butts)
+ user << "This ashtray is full."
+ return
+ user.u_equip(W)
+ W.loc = src
+
+ if (istype(W,/obj/item/clothing/mask/cigarette))
var/obj/item/clothing/mask/cigarette/cig = W
if (cig.lit == 1)
src.visible_message("[user] crushes [cig] in [src], putting it out.")
- cig.smoketime = 0
+ processing_objects.Remove(cig)
+ var/obj/item/butt = new cig.type_butt(src)
+ cig.transfer_fingerprints_to(butt)
+ del(cig)
else if (cig.lit == 0)
- if(istype(cig, /obj/item/weapon/match))
- user << "You place [cig] in [src] without even lighting it. Why would you do that?"
- else
- user << "You place [cig] in [src] without even smoking it. Why would you do that?"
- else if (cig.lit == -1)
- src.visible_message("[user] places [cig] in [src].")
- user.update_inv_l_hand()
- user.update_inv_r_hand()
- add_fingerprint(user)
- if (contents.len == max_butts)
- icon_state = icon_full
- desc = empty_desc + " It's stuffed full."
- else if (contents.len > max_butts/2)
- icon_state = icon_half
- desc = empty_desc + " It's half-filled."
+ user << "You place [cig] in [src] without even smoking it. Why would you do that?"
+
+ src.visible_message("[user] places [W] in [src].")
+ user.update_inv_l_hand()
+ user.update_inv_r_hand()
+ add_fingerprint(user)
+ if (contents.len == max_butts)
+ icon_state = icon_full
+ desc = empty_desc + " It's stuffed full."
+ else if (contents.len > max_butts/2)
+ icon_state = icon_half
+ desc = empty_desc + " It's half-filled."
else
health = max(0,health - W.force)
user << "You hit [src] with [W]."
@@ -62,7 +61,6 @@
if (contents.len)
src.visible_message("\red [src] slams into [hit_atom] spilling its contents!")
for (var/obj/item/clothing/mask/cigarette/O in contents)
- contents -= O
O.loc = src.loc
icon_state = icon_empty
return ..()
@@ -70,7 +68,6 @@
/obj/item/ashtray/proc/die()
src.visible_message("\red [src] shatters spilling its contents!")
for (var/obj/item/clothing/mask/cigarette/O in contents)
- contents -= O
O.loc = src.loc
icon_state = icon_broken
diff --git a/code/WorkInProgress/Chinsky/guestpass.dm b/code/WorkInProgress/Chinsky/guestpass.dm
new file mode 100644
index 00000000000..8a959c5b76a
--- /dev/null
+++ b/code/WorkInProgress/Chinsky/guestpass.dm
@@ -0,0 +1,186 @@
+/////////////////////////////////////////////
+//Guest pass ////////////////////////////////
+/////////////////////////////////////////////
+/obj/item/weapon/card/id/guest
+ name = "guest pass"
+ desc = "Allows temporary access to station areas."
+ icon_state = "guest"
+
+ var/temp_access = list() //to prevent agent cards stealing access as permanent
+ var/expiration_time = 0
+ var/reason = "NOT SPECIFIED"
+
+/obj/item/weapon/card/id/guest/GetAccess()
+ if (world.time > expiration_time)
+ return access
+ else
+ return temp_access
+
+/obj/item/weapon/card/id/guest/examine()
+ ..()
+ if (world.time < expiration_time)
+ usr << "\blue This pass expires at [worldtime2text(expiration_time)]."
+ else
+ usr << "\red It expired at [worldtime2text(expiration_time)]."
+
+/obj/item/weapon/card/id/guest/read()
+ if (world.time > expiration_time)
+ usr << "This pass expired at [worldtime2text(expiration_time)]."
+ else
+ usr << "This pass expires at [worldtime2text(expiration_time)]."
+
+ usr << "It grants access to following areas:"
+ for (var/A in temp_access)
+ usr << "[get_access_desc(A)]."
+ usr << "Issuing reason: [reason]."
+ return
+
+/////////////////////////////////////////////
+//Guest pass terminal////////////////////////
+/////////////////////////////////////////////
+
+/obj/machinery/computer/guestpass
+ name = "guest pass terminal"
+ icon_state = "guest"
+ density = 0
+
+
+ var/obj/item/weapon/card/id/giver
+ var/list/accesses = list()
+ var/giv_name = "NOT SPECIFIED"
+ var/reason = "NOT SPECIFIED"
+ var/duration = 0
+
+ var/list/internal_log = list()
+ var/mode = 0 // 0 - making pass, 1 - viewing logs
+
+/obj/machinery/computer/guestpass/New()
+ ..()
+ uid = "[rand(100,999)]-G[rand(10,99)]"
+
+/obj/machinery/computer/guestpass/attackby(obj/O, mob/user)
+ if(istype(O, /obj/item/weapon/card/id))
+ user.drop_item()
+ O.loc = src
+ giver = O
+ updateUsrDialog()
+
+/obj/machinery/computer/guestpass/attack_ai(var/mob/user as mob)
+ return attack_hand(user)
+
+/obj/machinery/computer/guestpass/attack_paw(var/mob/user as mob)
+ return attack_hand(user)
+
+/obj/machinery/computer/guestpass/attack_hand(var/mob/user as mob)
+ if(..())
+ return
+
+ user.set_machine(src)
+ var/dat
+
+ if (mode == 1) //Logs
+ dat += "
Activity log
"
+ for (var/entry in internal_log)
+ dat += "[entry]
"
+ dat += "Print
"
+ dat += "Back
"
+ else
+ dat += "Guest pass terminal #[uid]
"
+ dat += "View activity log
"
+ dat += "Issuing ID: [giver]
"
+ dat += "Issued to: [giv_name]
"
+ dat += "Reason: [reason]
"
+ dat += "Duration (minutes): [duration] m
"
+ dat += "Access to areas:
"
+ if (giver && giver.access)
+ for (var/A in giver.access)
+ var/area = get_access_desc(A)
+ if (A in accesses)
+ area = "[area]"
+ dat += "[area]
"
+ dat += "
Issue pass
"
+
+ user << browse(dat, "window=guestpass;size=400x520")
+ onclose(user, "guestpass")
+
+
+/obj/machinery/computer/guestpass/Topic(href, href_list)
+ if(..())
+ return
+ usr.set_machine(src)
+ if (href_list["mode"])
+ mode = text2num(href_list["mode"])
+
+ if (href_list["choice"])
+ switch(href_list["choice"])
+ if ("giv_name")
+ var/nam = input("Person pass is issued to", "Name", name)
+ if (nam)
+ giv_name = nam
+ if ("reason")
+ var/reas = input("Reason why pass is issued", "Reason", reason)
+ reason = reas
+ if ("duration")
+ var/dur = input("Duration (in minutes) during which pass is valid.", "Duration") as num
+ if (dur > 0 && dur < 30)
+ duration = dur
+ else
+ usr << "\red Invalid duration."
+ if ("access")
+ var/A = text2num(href_list["access"])
+ if (A in accesses)
+ accesses.Remove(A)
+ else
+ accesses.Add(A)
+ if (href_list["action"])
+ switch(href_list["action"])
+ if ("id")
+ if (giver)
+ if(ishuman(usr))
+ giver.loc = usr.loc
+ if(!usr.get_active_hand())
+ usr.put_in_hands(giver)
+ giver = null
+ else
+ giver.loc = src.loc
+ giver = null
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if (istype(I, /obj/item/weapon/card/id))
+ usr.drop_item()
+ I.loc = src
+ giver = I
+ updateUsrDialog()
+
+ if ("print")
+ var/dat = "Activity log of guest pass terminal #[uid]
"
+ for (var/entry in internal_log)
+ dat += "[entry]
"
+ //usr << "Printing the log, standby..."
+ //sleep(50)
+ var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc )
+ P.name = "activity log"
+ P.info = dat
+
+ if ("issue")
+ if (giver)
+ var/number = add_zero("[rand(0,9999)]", 4)
+ var/entry = "\[[worldtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: "
+ for (var/i=1 to accesses.len)
+ var/A = accesses[i]
+ if (A)
+ var/area = get_access_desc(A)
+ entry += "[i > 1 ? ", [area]" : "[area]"]"
+ entry += ". Expires at [worldtime2text(world.time + duration*10*60)]."
+ internal_log.Add(entry)
+
+ var/obj/item/weapon/card/id/guest/pass = new(src.loc)
+ pass.temp_access = accesses.Copy()
+ pass.registered_name = giv_name
+ pass.expiration_time = world.time + duration*10*60
+ pass.reason = reason
+ pass.name = "guest pass #[number]"
+ else
+ usr << "\red Cannot issue pass without issuing ID."
+ updateUsrDialog()
+ return
\ No newline at end of file
diff --git a/code/WorkInProgress/Yinadele/Supermatter.dm b/code/WorkInProgress/Yinadele/Supermatter.dm
index 39759ff4946..aba28a7d5b2 100644
--- a/code/WorkInProgress/Yinadele/Supermatter.dm
+++ b/code/WorkInProgress/Yinadele/Supermatter.dm
@@ -202,6 +202,9 @@
/obj/machinery/power/supermatter/attack_robot(mob/user as mob)
return attack_hand(user)
+/obj/machinery/power/supermatter/attack_ai(mob/user as mob)
+ user << "You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update."
+
/obj/machinery/power/supermatter/attack_hand(mob/user as mob)
user.visible_message("\The [user] reaches out and touches \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.",\
diff --git a/code/WorkInProgress/carn/master_controller_semi-seq.dm b/code/WorkInProgress/carn/master_controller_semi-seq.dm
index 96e7eacda6e..0f9b4f666d9 100644
--- a/code/WorkInProgress/carn/master_controller_semi-seq.dm
+++ b/code/WorkInProgress/carn/master_controller_semi-seq.dm
@@ -50,7 +50,7 @@ datum/controller/game_controller/New()
if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
if(!ticker) ticker = new /datum/controller/gameticker()
if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()
-
+ if(artifact_spawn) artifact_spawning_turfs = artifact_spawn
datum/controller/game_controller/proc/setup()
world.tick_lag = config.Ticklag
diff --git a/code/WorkInProgress/kilakk/fax.dm b/code/WorkInProgress/kilakk/fax.dm
index 76bcc0baa40..0d8f4cdde1f 100644
--- a/code/WorkInProgress/kilakk/fax.dm
+++ b/code/WorkInProgress/kilakk/fax.dm
@@ -109,10 +109,13 @@ var/list/alldepartments = list("Central Command")
if(href_list["remove"])
if(tofax)
- tofax.loc = usr.loc
- usr.put_in_hands(tofax)
- usr << "You take the paper out of \the [src]."
- tofax = null
+ if(!ishuman(usr))
+ usr << "You can't do it."
+ else
+ tofax.loc = usr.loc
+ usr.put_in_hands(tofax)
+ usr << "You take the paper out of \the [src]."
+ tofax = null
if(href_list["scan"])
if (scan)
diff --git a/code/__HELPERS/bygex.dm b/code/__HELPERS/bygex.dm
deleted file mode 100644
index 0955b107508..00000000000
--- a/code/__HELPERS/bygex.dm
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef LIBREGEX_LIBRARY
- #define LIBREGEX_LIBRARY "bygex"
-#endif
-
-proc
- regEx_compare(str, exp)
- return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_compare")(str, exp))
-
- regex_compare(str, exp)
- return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_compare")(str, exp))
-
- regEx_find(str, exp)
- return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_find")(str, exp))
-
- regex_find(str, exp)
- return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_find")(str, exp))
-
- regEx_replaceall(str, exp, fmt)
- return call(LIBREGEX_LIBRARY, "regEx_replaceall")(str, exp, fmt)
-
- regex_replaceall(str, exp, fmt)
- return call(LIBREGEX_LIBRARY, "regex_replaceall")(str, exp, fmt)
-
- replacetextEx(str, exp, fmt)
- return call(LIBREGEX_LIBRARY, "regEx_replaceallliteral")(str, exp, fmt)
-
- replacetext(str, exp, fmt)
- return call(LIBREGEX_LIBRARY, "regex_replaceallliteral")(str, exp, fmt)
-
- regEx_replace(str, exp, fmt)
- return call(LIBREGEX_LIBRARY, "regEx_replace")(str, exp, fmt)
-
- regex_replace(str, exp, fmt)
- return call(LIBREGEX_LIBRARY, "regex_replace")(str, exp, fmt)
-
- regEx_findall(str, exp)
- return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regEx_findall")(str, exp))
-
- regex_findall(str, exp)
- return new /datum/regex(str, exp, call(LIBREGEX_LIBRARY, "regex_findall")(str, exp))
-
-
-//upon calling a regex match or search, a /datum/regex object is created with str(haystack) and exp(needle) variables set
-//it also contains a list(matches) of /datum/match objects, each of which holds the position and length of the match
-//matched strings are not returned from the dll, in order to save on memory allocation for large numbers of strings
-//instead, you can use regex.str(matchnum) to fetch this string as needed.
-//likewise you can also use regex.pos(matchnum) and regex.len(matchnum) as shorthands
-/datum/regex
- var/str
- var/exp
- var/error
- var/anchors = 0
- var/list/matches = list()
-
- New(str, exp, results)
- src.str = str
- src.exp = exp
-
- if(findtext(results, "Err", 1, 4)) //error message
- src.error = results
- else
- var/list/L = params2list(results)
- var/list/M
- var{i;j}
- for(i in L)
- M = L[i]
- for(j=2, j<=M.len, j+=2)
- matches += new /datum/match(text2num(M[j-1]),text2num(M[j]))
- anchors = (j-2)/2
- return matches
-
- proc
- str(i)
- if(!i) return str
- var/datum/match/M = matches[i]
- return copytext(str, M.pos, M.pos+M.len)
-
- pos(i)
- if(!i) return 1
- var/datum/match/M = matches[i]
- return M.pos
-
- len(i)
- if(!i) return length(str)
- var/datum/match/M = matches[i]
- return M.len
-
- end(i)
- if(!i) return length(str)
- var/datum/match/M = matches[i]
- return M.pos + M.len
-
- report() //debug tool
- . = ":: RESULTS ::\n:: str :: [html_encode(str)]\n:: exp :: [html_encode(exp)]\n:: anchors :: [anchors]"
- if(error)
- . += "\n[error]"
- return
- for(var/i=1, i<=matches.len, ++i)
- . += "\nMatch[i]\n\t[html_encode(str(i))]\n\tpos=[pos(i)] len=[len(i)]"
-
-/datum/match
- var/pos
- var/len
-
- New(pos, len)
- src.pos = pos
- src.len = len
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index d33f976fe76..a493aa9d080 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -194,7 +194,35 @@ proc/checkhtml(var/t)
/*
* Text modification
*/
- //Adds 'u' number of zeros ahead of the text 't'
+/proc/replacetext(text, find, replacement)
+ var/find_len = length(find)
+ if(find_len < 1) return text
+ . = ""
+ var/last_found = 1
+ while(1)
+ var/found = findtext(text, find, last_found, 0)
+ . += copytext(text, last_found, found)
+ if(found)
+ . += replacement
+ last_found = found + find_len
+ continue
+ return .
+
+/proc/replacetextEx(text, find, replacement)
+ var/find_len = length(find)
+ if(find_len < 1) return text
+ . = ""
+ var/last_found = 1
+ while(1)
+ var/found = findtextEx(text, find, last_found, 0)
+ . += copytext(text, last_found, found)
+ if(found)
+ . += replacement
+ last_found = found + find_len
+ continue
+ return .
+
+//Adds 'u' number of zeros ahead of the text 't'
/proc/add_zero(t, u)
while (length(t) < u)
t = "0[t]"
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index e180f2092d6..20eb15d6af0 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -261,4 +261,5 @@ proc/tg_list2text(list/list, glue=",")
switch(ui_style)
if("old") return 'icons/mob/screen1_old.dmi'
if("Orange") return 'icons/mob/screen1_Orange.dmi'
- else return 'icons/mob/screen1_Midnight.dmi'
+ if("Midnight") return 'icons/mob/screen1_Midnight.dmi'
+ else return 'icons/mob/screen1_White.dmi'
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 5ce15be96e7..fd0b658aa0b 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -291,7 +291,7 @@
// Simple helper to face what you clicked on, in case it should be needed in more than one place
/mob/proc/face_atom(var/atom/A)
- if( buckled || !A || !x || !y || !A.x || !A.y ) return
+ if( stat || buckled || !A || !x || !y || !A.x || !A.y ) return
var/dx = A.x - x
var/dy = A.y - y
if(!dx && !dy) return
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 618858d5438..88ac1b70e2c 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -166,9 +166,11 @@ datum/hud/New(mob/owner)
if(!ismob(mymob)) return 0
if(!mymob.client) return 0
var/ui_style = ui_style2icon(mymob.client.prefs.UI_style)
+ var/ui_color = mymob.client.prefs.UI_style_color
+ var/ui_alpha = mymob.client.prefs.UI_style_alpha
if(ishuman(mymob))
- human_hud(ui_style) // Pass the player the UI style chosen in preferences
+ human_hud(ui_style, ui_color, ui_alpha) // Pass the player the UI style chosen in preferences
else if(ismonkey(mymob))
monkey_hud(ui_style)
else if(isbrain(mymob))
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 3d97018352a..ca053f86e6b 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -1,4 +1,4 @@
-/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_old.dmi')
+/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_White.dmi', var/ui_color = "#ffffff", var/ui_alpha = 255)
src.adding = list()
src.other = list()
@@ -73,6 +73,8 @@
using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
using.screen_loc = ui_movi
using.layer = 20
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
move_intent = using
@@ -82,6 +84,8 @@
using.icon_state = "act_drop"
using.screen_loc = ui_drop_throw
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.hotkeybuttons += using
inv_box = new /obj/screen/inventory()
@@ -92,6 +96,8 @@
inv_box.icon_state = "center"
inv_box.screen_loc = ui_iclothing
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -102,6 +108,8 @@
inv_box.icon_state = "equip"
inv_box.screen_loc = ui_oclothing
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -114,6 +122,9 @@
inv_box.screen_loc = ui_rhand
inv_box.slot_id = slot_r_hand
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
+
src.r_hand_hud_object = inv_box
src.adding += inv_box
@@ -127,6 +138,8 @@
inv_box.screen_loc = ui_lhand
inv_box.slot_id = slot_l_hand
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.l_hand_hud_object = inv_box
src.adding += inv_box
@@ -137,6 +150,8 @@
using.icon_state = "hand1"
using.screen_loc = ui_swaphand1
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
using = new /obj/screen/inventory()
@@ -146,6 +161,8 @@
using.icon_state = "hand2"
using.screen_loc = ui_swaphand2
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
inv_box = new /obj/screen/inventory()
@@ -156,6 +173,8 @@
inv_box.screen_loc = ui_id
inv_box.slot_id = slot_wear_id
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -166,6 +185,8 @@
inv_box.screen_loc = ui_mask
inv_box.slot_id = slot_wear_mask
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -176,6 +197,8 @@
inv_box.screen_loc = ui_back
inv_box.slot_id = slot_back
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -185,6 +208,8 @@
inv_box.screen_loc = ui_storage1
inv_box.slot_id = slot_l_store
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -194,6 +219,8 @@
inv_box.screen_loc = ui_storage2
inv_box.slot_id = slot_r_store
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
inv_box = new /obj/screen/inventory()
@@ -204,6 +231,8 @@
inv_box.screen_loc = ui_sstore1
inv_box.slot_id = slot_s_store
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
using = new /obj/screen()
@@ -212,6 +241,8 @@
using.icon_state = "act_resist"
using.screen_loc = ui_pull_resist
using.layer = 19
+ using.color = ui_color
+ using.alpha = ui_alpha
src.hotkeybuttons += using
using = new /obj/screen()
@@ -220,6 +251,8 @@
using.icon_state = "other"
using.screen_loc = ui_inventory
using.layer = 20
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
using = new /obj/screen()
@@ -228,6 +261,8 @@
using.icon_state = "act_equip"
using.screen_loc = ui_equip
using.layer = 20
+ using.color = ui_color
+ using.alpha = ui_alpha
src.adding += using
inv_box = new /obj/screen/inventory()
@@ -237,6 +272,8 @@
inv_box.screen_loc = ui_gloves
inv_box.slot_id = slot_gloves
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -246,6 +283,8 @@
inv_box.screen_loc = ui_glasses
inv_box.slot_id = slot_glasses
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -255,6 +294,8 @@
inv_box.screen_loc = ui_l_ear
inv_box.slot_id = slot_l_ear
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -264,6 +305,8 @@
inv_box.screen_loc = ui_r_ear
inv_box.slot_id = slot_r_ear
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -273,6 +316,8 @@
inv_box.screen_loc = ui_head
inv_box.slot_id = slot_head
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -282,6 +327,8 @@
inv_box.screen_loc = ui_shoes
inv_box.slot_id = slot_shoes
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.other += inv_box
inv_box = new /obj/screen/inventory()
@@ -291,6 +338,8 @@
inv_box.screen_loc = ui_belt
inv_box.slot_id = slot_belt
inv_box.layer = 19
+ inv_box.color = ui_color
+ inv_box.alpha = ui_alpha
src.adding += inv_box
mymob.throw_icon = new /obj/screen()
@@ -298,6 +347,8 @@
mymob.throw_icon.icon_state = "act_throw_off"
mymob.throw_icon.name = "throw"
mymob.throw_icon.screen_loc = ui_drop_throw
+ mymob.throw_icon.color = ui_color
+ mymob.throw_icon.alpha = ui_alpha
src.hotkeybuttons += mymob.throw_icon
mymob.oxygen = new /obj/screen()
@@ -382,6 +433,8 @@
mymob.zone_sel = new /obj/screen/zone_sel( null )
mymob.zone_sel.icon = ui_style
+ mymob.zone_sel.color = ui_color
+ mymob.zone_sel.alpha = ui_alpha
mymob.zone_sel.overlays.Cut()
mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 4ca8f9f5d75..ed054ae6c8a 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -276,37 +276,79 @@
C << "You are not wearing a mask."
return 1
else
- if(istype(C.l_hand, /obj/item/weapon/tank))
- C << "You are now running on internals from the [C.l_hand] on your left hand."
- C.internal = C.l_hand
- else if(istype(C.r_hand, /obj/item/weapon/tank))
- C << "You are now running on internals from the [C.r_hand] on your right hand."
- C.internal = C.r_hand
- else if(ishuman(C))
+ var/list/nicename = null
+ var/list/tankcheck = null
+ var/breathes = "oxygen" //default, we'll check later
+ var/list/contents = list()
+
+ if(ishuman(C))
var/mob/living/carbon/human/H = C
- if(istype(H.s_store, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.s_store] on your [H.wear_suit]."
- H.internal = H.s_store
- else if(istype(H.belt, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.belt] on your belt."
- H.internal = H.belt
- else if(istype(H.l_store, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.l_store] in your left pocket."
- H.internal = H.l_store
- else if(istype(H.r_store, /obj/item/weapon/tank))
- H << "You are now running on internals from the [H.r_store] in your right pocket."
- H.internal = H.r_store
+ breathes = H.species.breath_type
+ nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket")
+ tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store)
- //Seperate so CO2 jetpacks are a little less cumbersome.
- if(!C.internal && istype(C.back, /obj/item/weapon/tank))
- C << "You are now running on internals from the [C.back] on your back."
- C.internal = C.back
+ else
+ nicename = list("Right Hand", "Left Hand", "Back")
+ tankcheck = list(C.r_hand, C.l_hand, C.back)
+
+ for(var/i=1, i bestcontents)
+ best = i
+ bestcontents = contents[i]
+
+
+ //We've determined the best container now we set it as our internals
+
+ if(best)
+ C << "You are now running on internals from [tankcheck[best]] on your [nicename[best]]."
+ C.internal = tankcheck[best]
+
+
if(C.internal)
if(C.internals)
C.internals.icon_state = "internal1"
else
- C << "You don't have an oxygen tank."
+ C << "You don't have a[breathes=="oxygen" ? "n oxygen" : addtext(" ",breathes)] tank."
if("act_intent")
usr.a_intent_change("right")
if("help")
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index f2b5f01ce36..b5b6cf74233 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -62,6 +62,9 @@
var/automute_on = 0 //enables automuting/spam prevention
var/jobs_have_minimal_access = 0 //determines whether jobs use minimal access or expanded access.
+ var/disable_player_mice = 0
+ var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
+
var/usealienwhitelist = 0
var/limitalienplayers = 0
var/alien_to_human_ratio = 0.5
@@ -425,6 +428,12 @@
if("ghost_interaction")
config.ghost_interaction = 1
+ if("disable_player_mice")
+ config.disable_player_mice = 1
+
+ if("uneducated_mice")
+ config.uneducated_mice = 1
+
if("comms_password")
config.comms_password = value
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 2be4c6e82a1..d4e92584229 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -107,13 +107,13 @@
var/datum/data/record/L = new()
L.fields["id"] = md5("[H.real_name][H.mind.assigned_role]")
L.fields["name"] = H.real_name
- L.fields["rank"] = H.mind.assigned_role
+ L.fields["rank"] = H.mind.assigned_role
L.fields["age"] = H.age
L.fields["sex"] = H.gender
L.fields["b_type"] = H.b_type
L.fields["b_dna"] = H.dna.unique_enzymes
- L.fields["enzymes"] = H.dna.struc_enzymes
- L.fields["identity"] = H.dna.uni_identity
+ L.fields["enzymes"] = H.dna.SE // Used in respawning
+ L.fields["identity"] = H.dna.UI // "
L.fields["image"] = getFlatIcon(H,0) //This is god-awful
locked += L
return
diff --git a/code/datums/diseases/appendicitis.dm b/code/datums/diseases/appendicitis.dm
index 16b4008fef0..502ce1e7346 100644
--- a/code/datums/diseases/appendicitis.dm
+++ b/code/datums/diseases/appendicitis.dm
@@ -45,7 +45,7 @@
H.op_stage.appendix = 2.0
var/datum/organ/external/groin = H.get_organ("groin")
- var/datum/wound/W = new /datum/wound/internal_bleeding(25)
+ var/datum/wound/W = new /datum/wound/internal_bleeding(20)
H.adjustToxLoss(25)
groin.wounds += W
src.cure()
diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm
index c7c5f812122..69a8eb6500f 100644
--- a/code/datums/diseases/dna_spread.dm
+++ b/code/datums/diseases/dna_spread.dm
@@ -39,13 +39,13 @@
//Save original dna for when the disease is cured.
src.original_dna["name"] = affected_mob.real_name
- src.original_dna["UI"] = affected_mob.dna.uni_identity
- src.original_dna["SE"] = affected_mob.dna.struc_enzymes
+ src.original_dna["UI"] = affected_mob.dna.UI
+ src.original_dna["SE"] = affected_mob.dna.SE
affected_mob << "\red You don't feel like yourself.."
- affected_mob.dna.uni_identity = strain_data["UI"]
- updateappearance(affected_mob, affected_mob.dna.uni_identity)
- affected_mob.dna.struc_enzymes = strain_data["SE"]
+ affected_mob.UpdateAppearance(strain_data["UI"])
+ affected_mob.dna.SE = strain_data["SE"]
+ affected_mob.dna.UpdateSE()
affected_mob.real_name = strain_data["name"]
domutcheck(affected_mob)
@@ -56,9 +56,9 @@
/datum/disease/dnaspread/Del()
if ((original_dna["name"]) && (original_dna["UI"]) && (original_dna["SE"]))
- affected_mob.dna.uni_identity = original_dna["UI"]
- updateappearance(affected_mob, affected_mob.dna.uni_identity)
- affected_mob.dna.struc_enzymes = original_dna["SE"]
+ affected_mob.UpdateAppearance(original_dna["UI"])
+ affected_mob.dna.SE = original_dna["SE"]
+ affected_mob.dna.UpdateSE()
affected_mob.real_name = original_dna["name"]
affected_mob << "\blue You feel more like yourself."
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 511731195e4..7cebf4f6bac 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -726,7 +726,7 @@ datum/mind
else
current.dna = changeling.absorbed_dna[1]
current.real_name = current.dna.real_name
- updateappearance(current, current.dna.uni_identity)
+ current.UpdateAppearance()
domutcheck(current, null)
else if (href_list["nuclear"])
diff --git a/code/defines/obj.dm b/code/defines/obj.dm
index 6c6269d301e..3e066989043 100644
--- a/code/defines/obj.dm
+++ b/code/defines/obj.dm
@@ -51,122 +51,194 @@
//This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character().
var/locked[] = list()
- proc/get_manifest(monochrome, OOC)
- var/list/heads = new()
- var/list/sec = new()
- var/list/eng = new()
- var/list/med = new()
- var/list/sci = new()
- var/list/civ = new()
- var/list/bot = new()
- var/list/misc = new()
- var/list/isactive = new()
- var/dat = {"
-
-
- | Name | Rank | Activity |
- "}
- var/even = 0
-
- // sort mobs
- for(var/datum/data/record/t in data_core.general)
- var/name = t.fields["name"]
- var/rank = t.fields["rank"]
- var/real_rank = t.fields["real_rank"]
- if(OOC)
- var/active = 0
- for(var/mob/M in player_list)
- if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10)
- active = 1
- break
- isactive[name] = active ? "Active" : "Inactive"
- else
- isactive[name] = t.fields["p_stat"]
-
+/obj/effect/datacore/proc/get_manifest(monochrome, OOC)
+ var/list/heads = new()
+ var/list/sec = new()
+ var/list/eng = new()
+ var/list/med = new()
+ var/list/sci = new()
+ var/list/civ = new()
+ var/list/bot = new()
+ var/list/misc = new()
+ var/list/isactive = new()
+ var/dat = {"
+
+
+ | Name | Rank | Activity |
+ "}
+ var/even = 0
+ // sort mobs
+ for(var/datum/data/record/t in data_core.general)
+ var/name = t.fields["name"]
+ var/rank = t.fields["rank"]
+ var/real_rank = t.fields["real_rank"]
+ if(OOC)
+ var/active = 0
+ for(var/mob/M in player_list)
+ if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10)
+ active = 1
+ break
+ isactive[name] = active ? "Active" : "Inactive"
+ else
+ isactive[name] = t.fields["p_stat"]
//world << "[name]: [rank]"
-
//cael - to prevent multiple appearances of a player/job combination, add a continue after each line
- var/department = 0
- if(real_rank in command_positions)
- heads[name] = rank
- department = 1
- if(real_rank in security_positions)
- sec[name] = rank
- department = 1
- if(real_rank in engineering_positions)
- eng[name] = rank
- department = 1
- if(real_rank in medical_positions)
- med[name] = rank
- department = 1
- if(real_rank in science_positions)
- sci[name] = rank
- department = 1
- if(real_rank in civilian_positions)
- civ[name] = rank
- department = 1
- if(real_rank in nonhuman_positions)
- bot[name] = rank
- department = 1
+ var/department = 0
+ if(real_rank in command_positions)
+ heads[name] = rank
+ department = 1
+ if(real_rank in security_positions)
+ sec[name] = rank
+ department = 1
+ if(real_rank in engineering_positions)
+ eng[name] = rank
+ department = 1
+ if(real_rank in medical_positions)
+ med[name] = rank
+ department = 1
+ if(real_rank in science_positions)
+ sci[name] = rank
+ department = 1
+ if(real_rank in civilian_positions)
+ civ[name] = rank
+ department = 1
+ if(real_rank in nonhuman_positions)
+ bot[name] = rank
+ department = 1
+ if(!department && !(name in heads))
+ misc[name] = rank
+ if(heads.len > 0)
+ dat += "| Heads |
"
+ for(name in heads)
+ dat += "| [name] | [heads[name]] | [isactive[name]] |
"
+ even = !even
+ if(sec.len > 0)
+ dat += "| Security |
"
+ for(name in sec)
+ dat += "| [name] | [sec[name]] | [isactive[name]] |
"
+ even = !even
+ if(eng.len > 0)
+ dat += "| Engineering |
"
+ for(name in eng)
+ dat += "| [name] | [eng[name]] | [isactive[name]] |
"
+ even = !even
+ if(med.len > 0)
+ dat += "| Medical |
"
+ for(name in med)
+ dat += "| [name] | [med[name]] | [isactive[name]] |
"
+ even = !even
+ if(sci.len > 0)
+ dat += "| Science |
"
+ for(name in sci)
+ dat += "| [name] | [sci[name]] | [isactive[name]] |
"
+ even = !even
+ if(civ.len > 0)
+ dat += "| Civilian |
"
+ for(name in civ)
+ dat += "| [name] | [civ[name]] | [isactive[name]] |
"
+ even = !even
+ // in case somebody is insane and added them to the manifest, why not
+ if(bot.len > 0)
+ dat += "| Silicon |
"
+ for(name in bot)
+ dat += "| [name] | [bot[name]] | [isactive[name]] |
"
+ even = !even
+ // misc guys
+ if(misc.len > 0)
+ dat += "| Miscellaneous |
"
+ for(name in misc)
+ dat += "| [name] | [misc[name]] | [isactive[name]] |
"
+ even = !even
- if(!department && !(name in heads))
- misc[name] = rank
-
- if(heads.len > 0)
- dat += "| Heads |
"
- for(name in heads)
- dat += "| [name] | [heads[name]] | [isactive[name]] |
"
- even = !even
- if(sec.len > 0)
- dat += "| Security |
"
- for(name in sec)
- dat += "| [name] | [sec[name]] | [isactive[name]] |
"
- even = !even
- if(eng.len > 0)
- dat += "| Engineering |
"
- for(name in eng)
- dat += "| [name] | [eng[name]] | [isactive[name]] |
"
- even = !even
- if(med.len > 0)
- dat += "| Medical |
"
- for(name in med)
- dat += "| [name] | [med[name]] | [isactive[name]] |
"
- even = !even
- if(sci.len > 0)
- dat += "| Science |
"
- for(name in sci)
- dat += "| [name] | [sci[name]] | [isactive[name]] |
"
- even = !even
- if(civ.len > 0)
- dat += "| Civilian |
"
- for(name in civ)
- dat += "| [name] | [civ[name]] | [isactive[name]] |
"
- even = !even
- // in case somebody is insane and added them to the manifest, why not
- if(bot.len > 0)
- dat += "| Silicon |
"
- for(name in bot)
- dat += "| [name] | [bot[name]] | [isactive[name]] |
"
- even = !even
- // misc guys
- if(misc.len > 0)
- dat += "| Miscellaneous |
"
- for(name in misc)
- dat += "| [name] | [misc[name]] | [isactive[name]] |
"
- even = !even
+ dat += "
"
+ dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly
+ dat = replacetext(dat, "\t", "")
+ return dat
+
+
+/*
+We can't just insert in HTML into the nanoUI so we need the raw data to play with.
+*/
+
+/obj/effect/datacore/proc/get_manifest_json()
+ var/heads[0]
+ var/sec[0]
+ var/eng[0]
+ var/med[0]
+ var/sci[0]
+ var/civ[0]
+ var/bot[0]
+ var/misc[0]
+ for(var/datum/data/record/t in data_core.general)
+ var/name = t.fields["name"]
+ var/rank = t.fields["rank"]
+ var/real_rank = t.fields["real_rank"]
+ var/isactive = t.fields["p_stat"]
+ var/department = 0
+ var/depthead = 0 // Department Heads will be placed at the top of their lists.
+ if(real_rank in command_positions)
+ heads[++heads.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ depthead = 1
+ if(rank=="Captain" && heads.len != 1)
+ heads.Swap(1,heads.len)
+
+ if(real_rank in security_positions)
+ sec[++sec.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && sec.len != 1)
+ sec.Swap(1,sec.len)
+
+ if(real_rank in engineering_positions)
+ eng[++eng.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && eng.len != 1)
+ eng.Swap(1,eng.len)
+
+ if(real_rank in medical_positions)
+ med[++med.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && med.len != 1)
+ med.Swap(1,med.len)
+
+ if(real_rank in science_positions)
+ sci[++sci.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && sci.len != 1)
+ sci.Swap(1,sci.len)
+
+ if(real_rank in civilian_positions)
+ civ[++civ.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+ if(depthead && civ.len != 1)
+ civ.Swap(1,civ.len)
+
+ if(real_rank in nonhuman_positions)
+ bot[++bot.len] = list("name" = name, "rank" = rank, "active" = isactive)
+ department = 1
+
+ if(!department && !(name in heads))
+ misc[++misc.len] = list("name" = name, "rank" = rank, "active" = isactive)
+
+ return list(\
+ "heads" = heads,\
+ "sec" = sec,\
+ "eng" = eng,\
+ "med" = med,\
+ "sci" = sci,\
+ "civ" = civ,\
+ "bot" = bot,\
+ "misc" = misc\
+ )
- dat += "
"
- dat = replacetext(dat, "\n", "") // so it can be placed on paper correctly
- dat = replacetext(dat, "\t", "")
- return dat
/obj/effect/laser
name = "laser"
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index b84388f5838..d48e2e10c6f 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -325,6 +325,13 @@
icon = 'icons/obj/wizard.dmi'
icon_state = "broom"
+/obj/item/weapon/staff/gentcane
+ name = "Gentlemans Cane"
+ desc = "An ebony can with an ivory tip."
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "cane"
+ item_state = "stick"
+
/obj/item/weapon/staff/stick
name = "stick"
desc = "A great tool to drag someone else's drinks across the bar."
diff --git a/code/game/communications.dm b/code/game/communications.dm
index 3bc3ee70092..4f13277a31d 100644
--- a/code/game/communications.dm
+++ b/code/game/communications.dm
@@ -103,16 +103,16 @@ var/list/radiochannels = list(
"Medical" = 1355,
"Engineering" = 1357,
"Security" = 1359,
- "Response Team" = 1443,
- "Deathsquad" = 1441,
+ "Response Team" = 1345,
+ "Deathsquad" = 1341,
"Syndicate" = 1213,
"Supply" = 1347,
)
//depenging helpers
-var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1443, 1441, 1347)
+var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1345, 1341, 1347)
// central command channels, i.e deathsquid & response teams
-var/list/CENT_FREQS = list(1441, 1443)
+var/list/CENT_FREQS = list(1345, 1341)
var/const/COMM_FREQ = 1353 //command, colored gold in chat window
var/const/SYND_FREQ = 1213
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
new file mode 100644
index 00000000000..6b06dc57f68
--- /dev/null
+++ b/code/game/dna/dna2.dm
@@ -0,0 +1,356 @@
+/**
+* DNA 2: The Spaghetti Strikes Back
+*
+* @author N3X15
+*/
+
+// What each index means:
+#define DNA_OFF_LOWERBOUND 0
+#define DNA_OFF_UPPERBOUND 1
+#define DNA_ON_LOWERBOUND 2
+#define DNA_ON_UPPERBOUND 3
+
+// Define block bounds (off-low,off-high,on-low,on-high)
+// Used in setupgame.dm
+#define DNA_DEFAULT_BOUNDS list(1,2049,2050,4095)
+#define DNA_HARDER_BOUNDS list(1,3049,3050,4095)
+#define DNA_HARD_BOUNDS list(1,3490,3500,4095)
+
+// Defines which values mean "on" or "off".
+// This is to make some of the more OP superpowers a larger PITA to activate,
+// and to tell our new DNA datum which values to set in order to turn something
+// on or off.
+var/global/list/dna_activity_bounds[STRUCDNASIZE]
+
+// Used to determine what each block means (admin hax and species stuff on /vg/, mostly)
+var/global/list/assigned_blocks[STRUCDNASIZE]
+
+var/global/list/datum/dna/gene/dna_genes[0]
+
+// UI Indices (can change to mutblock style, if desired)
+#define DNA_UI_HAIR_R 1
+#define DNA_UI_HAIR_G 2
+#define DNA_UI_HAIR_B 3
+#define DNA_UI_BEARD_R 4
+#define DNA_UI_BEARD_G 5
+#define DNA_UI_BEARD_B 6
+#define DNA_UI_SKIN_TONE 7
+#define DNA_UI_EYES_R 8
+#define DNA_UI_EYES_G 9
+#define DNA_UI_EYES_B 10
+#define DNA_UI_GENDER 11
+#define DNA_UI_BEARD_STYLE 12
+#define DNA_UI_HAIR_STYLE 13
+#define DNA_UI_LENGTH 13 // Update this when you add something, or you WILL break shit.
+
+/////////////////
+// GENE DEFINES
+/////////////////
+
+// Skip checking if it's already active.
+// Used for genes that check for value rather than a binary on/off.
+#define GENE_ALWAYS_ACTIVATE 1
+
+/* Note RE: unassigned blocks
+
+ Many genes in baycode are currently sitting unused
+ (compare setupgame.dm to the number of *BLOCK variables).
+
+ This datum will return 0 (or equivalent) if asked about
+ a block 0 (which means the gene was unassigned). Setters
+ will silently return without performing any action.
+
+ I have code to assign these genes in a streamlined manner,
+ but in order to avoid breaking things, I've left the
+ existing setupgame.dm intact. Please let me know if you
+ need this behavior changed.
+ */
+
+/datum/dna
+ // READ-ONLY, GETS OVERWRITTEN
+ // DO NOT FUCK WITH THESE OR BYOND WILL EAT YOUR FACE
+ var/uni_identity="" // Encoded UI
+ var/struc_enzymes="" // Encoded SE
+ var/unique_enzymes="" // MD5 of player name
+
+ // Internal dirtiness checks
+ var/dirtyUI=0
+ var/dirtySE=0
+
+ // Okay to read, but you're an idiot if you do.
+ // BLOCK = VALUE
+ var/list/SE[STRUCDNASIZE]
+ var/list/UI[DNA_UI_LENGTH]
+
+ // From old dna.
+ var/b_type = "A+" // Should probably change to an integer => string map but I'm lazy.
+ var/mutantrace = null // The type of mutant race the player is, if applicable (i.e. potato-man)
+ var/real_name // Stores the real name of the person who originally got this dna datum. Used primarily for changelings,
+
+ // New stuff
+ var/species = "Human"
+
+///////////////////////////////////////
+// UNIQUE IDENTITY
+///////////////////////////////////////
+
+// Create random UI.
+/datum/dna/proc/ResetUI(var/defer=0)
+ for(var/i=1,i<=DNA_UI_LENGTH,i++)
+ switch(i)
+ if(DNA_UI_SKIN_TONE)
+ SetUIValueRange(DNA_UI_SKIN_TONE,rand(1,220),220,1) // Otherwise, it gets fucked
+ else
+ UI[i]=rand(0,4095)
+ if(!defer)
+ UpdateUI()
+
+/datum/dna/proc/ResetUIFrom(var/mob/living/carbon/human/character)
+ // INITIALIZE!
+ ResetUI(1)
+ // Hair
+ // FIXME: Species-specific defaults pls
+ if(!character.h_style)
+ character.h_style = "Skinhead"
+ var/hair = hair_styles_list.Find(character.h_style)
+
+ // Facial Hair
+ if(!character.f_style)
+ character.f_style = "Shaved"
+ var/beard = facial_hair_styles_list.Find(character.f_style)
+
+ SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1)
+ SetUIValueRange(DNA_UI_HAIR_G, character.g_hair, 255, 1)
+ SetUIValueRange(DNA_UI_HAIR_B, character.b_hair, 255, 1)
+
+ SetUIValueRange(DNA_UI_BEARD_R, character.r_facial, 255, 1)
+ SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1)
+ SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1)
+
+ SetUIValueRange(DNA_UI_BEARD_R, character.r_eyes, 255, 1)
+ SetUIValueRange(DNA_UI_BEARD_G, character.g_eyes, 255, 1)
+ SetUIValueRange(DNA_UI_BEARD_B, character.b_eyes, 255, 1)
+
+ SetUIValueRange(DNA_UI_SKIN_TONE, 35-character.s_tone, 220, 1) // Value can be negative.
+
+ SetUIState(DNA_UI_GENDER, character.gender!=MALE, 1)
+
+ SetUIValueRange(DNA_UI_HAIR_STYLE, hair, hair_styles_list.len, 1)
+ SetUIValueRange(DNA_UI_BEARD_STYLE, beard, facial_hair_styles_list.len,1)
+
+ UpdateUI()
+
+// Set a DNA UI block's raw value.
+/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0)
+ if (block<=0) return
+ ASSERT(value>=0)
+ ASSERT(value<=4095)
+ UI[block]=value
+ dirtyUI=1
+ if(!defer)
+ UpdateUI()
+
+// Get a DNA UI block's raw value.
+/datum/dna/proc/GetUIValue(var/block)
+ if (block<=0) return 0
+ return UI[block]
+
+// Set a DNA UI block's value, given a value and a max possible value.
+// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list)
+/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue)
+ if (block<=0) return
+ ASSERT(maxvalue<=4095)
+ var/range = round(4095 / maxvalue)
+ if(value)
+ SetUIValue(block,value * range - rand(1,range-1))
+
+// Getter version of above.
+/datum/dna/proc/GetUIValueRange(var/block,var/maxvalue)
+ if (block<=0) return 0
+ var/value = GetUIValue(block)
+ return round(1 +(value / 4096)*maxvalue)
+
+// Is the UI gene "on" or "off"?
+// For UI, this is simply a check of if the value is > 2050.
+/datum/dna/proc/GetUIState(var/block)
+ if (block<=0) return
+ return UI[block] > 2050
+
+
+// Set UI gene "on" (1) or "off" (0)
+/datum/dna/proc/SetUIState(var/block,var/on,var/defer=0)
+ if (block<=0) return
+ var/val
+ if(on)
+ val=rand(2050,4095)
+ else
+ val=rand(1,2049)
+ SetUIValue(block,val,defer)
+
+// Get a hex-encoded UI block.
+/datum/dna/proc/GetUIBlock(var/block)
+ return EncodeDNABlock(GetUIValue(block))
+
+// Do not use this unless you absolutely have to.
+// Set a block from a hex string. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetUIBlock(var/block,var/value,var/defer=0)
+ if (block<=0) return
+ return SetUIValue(block,hex2num(value),defer)
+
+// Get a sub-block from a block.
+/datum/dna/proc/GetUISubBlock(var/block,var/subBlock)
+ return copytext(GetUIBlock(block),subBlock,subBlock+1)
+
+// Do not use this unless you absolutely have to.
+// Set a block from a hex string. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetUISubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0)
+ if (block<=0) return
+ var/oldBlock=GetUIBlock(block)
+ var/newBlock=""
+ for(var/i=1, i<=length(oldBlock), i++)
+ if(i==subBlock)
+ newBlock+=newSubBlock
+ else
+ newBlock+=copytext(oldBlock,i,i+1)
+ SetUIBlock(block,newBlock,defer)
+
+///////////////////////////////////////
+// STRUCTURAL ENZYMES
+///////////////////////////////////////
+
+// "Zeroes out" all of the blocks.
+/datum/dna/proc/ResetSE()
+ for(var/i = 1, i <= STRUCDNASIZE, i++)
+ SetSEValue(i,rand(1,1024),1)
+ UpdateSE()
+
+// Set a DNA SE block's raw value.
+/datum/dna/proc/SetSEValue(var/block,var/value,var/defer=0)
+ //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]")
+ if (block<=0) return
+ ASSERT(value>=0)
+ ASSERT(value<=4095)
+ SE[block]=value
+ dirtySE=1
+ if(!defer)
+ UpdateSE()
+
+// Get a DNA SE block's raw value.
+/datum/dna/proc/GetSEValue(var/block)
+ if (block<=0) return 0
+ return SE[block]
+
+// Set a DNA SE block's value, given a value and a max possible value.
+// Might be used for species?
+/datum/dna/proc/SetSEValueRange(var/block,var/value,var/maxvalue)
+ if (block<=0) return
+ ASSERT(maxvalue<=4095)
+ var/range = round(4095 / maxvalue)
+ if(value)
+ SetSEValue(block, value * range - rand(1,range-1))
+
+// Getter version of above.
+/datum/dna/proc/GetSEValueRange(var/block,var/maxvalue)
+ if (block<=0) return 0
+ var/value = GetSEValue(block)
+ return round(1 +(value / 4096)*maxvalue)
+
+// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.)
+/datum/dna/proc/GetSEState(var/block)
+ if (block<=0) return 0
+ var/list/BOUNDS=GetDNABounds(block)
+ var/value=GetSEValue(block)
+ return (value > BOUNDS[DNA_ON_LOWERBOUND])
+
+// Set a block "on" or "off".
+/datum/dna/proc/SetSEState(var/block,var/on,var/defer=0)
+ if (block<=0) return
+ var/list/BOUNDS=GetDNABounds(block)
+ var/val
+ if(on)
+ val=rand(BOUNDS[DNA_ON_LOWERBOUND],BOUNDS[DNA_ON_UPPERBOUND])
+ else
+ val=rand(BOUNDS[DNA_OFF_LOWERBOUND],BOUNDS[DNA_OFF_UPPERBOUND])
+ SetSEValue(block,val,defer)
+
+// Get hex-encoded SE block.
+/datum/dna/proc/GetSEBlock(var/block)
+ return EncodeDNABlock(GetSEValue(block))
+
+// Do not use this unless you absolutely have to.
+// Set a block from a hex string. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetSEBlock(var/block,var/value,var/defer=0)
+ if (block<=0) return
+ var/nval=hex2num(value)
+ //testing("SetSEBlock([block],[value],[defer]): [value] -> [nval]")
+ return SetSEValue(block,nval,defer)
+
+/datum/dna/proc/GetSESubBlock(var/block,var/subBlock)
+ return copytext(GetSEBlock(block),subBlock,subBlock+1)
+
+// Do not use this unless you absolutely have to.
+// Set a sub-block from a hex character. This is inefficient. If you can, use SetUIValue().
+// Used in DNA modifiers.
+/datum/dna/proc/SetSESubBlock(var/block,var/subBlock, var/newSubBlock, var/defer=0)
+ if (block<=0) return
+ var/oldBlock=GetSEBlock(block)
+ var/newBlock=""
+ for(var/i=1, i<=length(oldBlock), i++)
+ if(i==subBlock)
+ newBlock+=newSubBlock
+ else
+ newBlock+=copytext(oldBlock,i,i+1)
+ //testing("SetSESubBlock([block],[subBlock],[newSubBlock],[defer]): [oldBlock] -> [newBlock]")
+ SetSEBlock(block,newBlock,defer)
+
+
+/proc/EncodeDNABlock(var/value)
+ return add_zero2(num2hex(value,1), 3)
+
+/datum/dna/proc/UpdateUI()
+ src.uni_identity=""
+ for(var/block in UI)
+ uni_identity += EncodeDNABlock(block)
+ //testing("New UI: [uni_identity]")
+ dirtyUI=0
+
+/datum/dna/proc/UpdateSE()
+ //var/oldse=struc_enzymes
+ struc_enzymes=""
+ for(var/block in SE)
+ struc_enzymes += EncodeDNABlock(block)
+ //testing("Old SE: [oldse]")
+ //testing("New SE: [struc_enzymes]")
+ dirtySE=0
+
+// BACK-COMPAT!
+// Just checks our character has all the crap it needs.
+/datum/dna/proc/check_integrity(var/mob/living/carbon/human/character)
+ if(character)
+ if(UI.len != DNA_UI_LENGTH)
+ ResetUIFrom(character)
+
+ if(length(struc_enzymes)!= 3*STRUCDNASIZE)
+ ResetSE()
+
+ if(length(unique_enzymes) != 32)
+ unique_enzymes = md5(character.real_name)
+ else
+ if(length(uni_identity) != 3*DNA_UI_LENGTH)
+ uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4"
+ if(length(struc_enzymes)!= 3*STRUCDNASIZE)
+ struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6"
+
+// BACK-COMPAT!
+// Initial DNA setup. I'm kind of wondering why the hell this doesn't just call the above.
+/datum/dna/proc/ready_dna(mob/living/carbon/human/character)
+ ResetUIFrom(character)
+
+ ResetSE()
+
+ unique_enzymes = md5(character.real_name)
+ reg_dna[unique_enzymes] = character.real_name
+
diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm
new file mode 100644
index 00000000000..c9b75118de2
--- /dev/null
+++ b/code/game/dna/dna2_domutcheck.dm
@@ -0,0 +1,355 @@
+// (Re-)Apply mutations.
+// TODO: Turn into a /mob proc, change inj to a bitflag for various forms of differing behavior.
+// M: Mob to mess with
+// connected: Machine we're in, type unchecked so I doubt it's used beyond monkeying
+// flags: See below, bitfield.
+#define MUTCHK_FORCED 1
+/proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0)
+ for(var/datum/dna/gene/gene in dna_genes)
+ if(!M)
+ return
+ if(!gene.block)
+ continue
+
+ // Sanity checks, don't skip.
+ if(!gene.can_activate(M,flags))
+ //testing("[M] - Failed to activate [gene.name] (can_activate fail).")
+ continue
+
+ // Current state
+ var/gene_active = (gene.flags & GENE_ALWAYS_ACTIVATE)
+ if(!gene_active)
+ gene_active = M.dna.GetSEState(gene.block)
+
+ // Prior state
+ var/gene_prior_status = (gene.type in M.active_genes)
+
+ if((gene_active && !gene_prior_status) || (gene.flags & GENE_ALWAYS_ACTIVATE))
+ //testing("[gene.name] activated!")
+ gene.activate(M,connected,flags)
+ if(M)
+ if(!(gene.flags & GENE_ALWAYS_ACTIVATE))
+ M.active_genes |= gene.type
+ M.update_icon=1
+ else if(!gene_active && gene_prior_status)
+ //testing("[gene.name] deactivated!")
+ gene.deactivate(M,connected,flags)
+ if(M)
+ M.active_genes -= gene.type
+ M.update_icon = 1
+ //else
+ // testing("[M] - Failed to activate [gene.name] - [gene_active?"+":"-"]active, [gene_prior_status?"+":"-"]prior")
+
+/* Old, inflexibile
+/proc/domutcheck(var/mob/living/M, var/connected, var/flags)
+ if (!M) return
+
+ M.dna.check_integrity()
+
+ M.disabilities = 0
+ M.sdisabilities = 0
+ var/old_mutations = M.mutations
+ M.mutations = list()
+ M.pass_flags = 0
+// M.see_in_dark = 2
+// M.see_invisible = 0
+
+ if(PLANT in old_mutations)
+ M.mutations.Add(PLANT)
+ if(SKELETON in old_mutations)
+ M.mutations.Add(SKELETON)
+ if(FAT in old_mutations)
+ M.mutations.Add(FAT)
+ if(HUSK in old_mutations)
+ M.mutations.Add(HUSK)
+
+ var/inj = (flags & MUTCHK_FROM_INJECTOR) == MUTCHK_FROM_INJECTOR
+ var/forced = (flags & MUTCHK_FORCED) == MUTCHK_FORCED
+
+ if(M.dna.GetSEState(NOBREATHBLOCK))
+ if(forced || probinj(45,inj) || (mNobreath in old_mutations))
+ M << "\blue You feel no need to breathe."
+ M.mutations.Add(mNobreath)
+ if(M.dna.GetSEState(REMOTEVIEWBLOCK))
+ if(forced || probinj(45,inj) || (mRemote in old_mutations))
+ M << "\blue Your mind expands"
+ M.mutations.Add(mRemote)
+ M.verbs += /mob/living/carbon/human/proc/remoteobserve
+ if(M.dna.GetSEState(REGENERATEBLOCK))
+ if(forced || probinj(45,inj) || (mRegen in old_mutations))
+ M << "\blue You feel better"
+ M.mutations.Add(mRegen)
+ if(M.dna.GetSEState(INCREASERUNBLOCK))
+ if(forced || probinj(45,inj) || (mRun in old_mutations))
+ M << "\blue Your leg muscles pulsate."
+ M.mutations.Add(mRun)
+ if(M.dna.GetSEState(REMOTETALKBLOCK))
+ if(forced || probinj(45,inj) || (mRemotetalk in old_mutations))
+ M << "\blue You expand your mind outwards"
+ M.mutations.Add(mRemotetalk)
+ M.verbs += /mob/living/carbon/human/proc/remotesay
+ if(M.dna.GetSEState(MORPHBLOCK))
+ if(forced || probinj(45,inj) || (mMorph in old_mutations))
+ M.mutations.Add(mMorph)
+ M << "\blue Your skin feels strange"
+ M.verbs += /mob/living/carbon/human/proc/morph
+ if(M.dna.GetSEState(COLDBLOCK))
+ if(!(COLD_RESISTANCE in old_mutations))
+ if(forced || probinj(15,inj) || (mHeatres in old_mutations))
+ M.mutations.Add(mHeatres)
+ M << "\blue Your skin is icy to the touch"
+ else
+ if(forced || probinj(5,inj) || (mHeatres in old_mutations))
+ M.mutations.Add(mHeatres)
+ M << "\blue Your skin is icy to the touch"
+ if(M.dna.GetSEState(HALLUCINATIONBLOCK))
+ if(forced || probinj(45,inj) || (mHallucination in old_mutations))
+ M.mutations.Add(mHallucination)
+ M << "\red Your mind says 'Hello'"
+ if(M.dna.GetSEState(NOPRINTSBLOCK))
+ if(forced || probinj(45,inj) || (mFingerprints in old_mutations))
+ M.mutations.Add(mFingerprints)
+ M << "\blue Your fingers feel numb"
+ if(M.dna.GetSEState(SHOCKIMMUNITYBLOCK))
+ if(forced || probinj(45,inj) || (mShock in old_mutations))
+ M.mutations.Add(mShock)
+ M << "\blue Your skin feels strange"
+ if(M.dna.GetSEState(SMALLSIZEBLOCK))
+ if(forced || probinj(45,inj) || (mSmallsize in old_mutations))
+ M << "\blue Your skin feels rubbery"
+ M.mutations.Add(mSmallsize)
+ M.pass_flags |= 1
+
+
+
+ if (M.dna.GetSEState(HULKBLOCK))
+ if(forced || probinj(5,inj) || (HULK in old_mutations))
+ M << "\blue Your muscles hurt."
+ M.mutations.Add(HULK)
+ if (M.dna.GetSEState(HEADACHEBLOCK))
+ M.disabilities |= EPILEPSY
+ M << "\red You get a headache."
+ if (M.dna.GetSEState(FAKEBLOCK))
+ M << "\red You feel strange."
+ if (prob(95))
+ if(prob(50))
+ randmutb(M)
+ else
+ randmuti(M)
+ else
+ randmutg(M)
+ if (M.dna.GetSEState(COUGHBLOCK))
+ M.disabilities |= COUGHING
+ M << "\red You start coughing."
+ if (M.dna.GetSEState(CLUMSYBLOCK))
+ M << "\red You feel lightheaded."
+ M.mutations.Add(CLUMSY)
+ if (M.dna.GetSEState(TWITCHBLOCK))
+ M.disabilities |= TOURETTES
+ M << "\red You twitch."
+ if (M.dna.GetSEState(XRAYBLOCK))
+ if(forced || probinj(30,inj) || (XRAY in old_mutations))
+ M << "\blue The walls suddenly disappear."
+// M.sight |= (SEE_MOBS|SEE_OBJS|SEE_TURFS)
+// M.see_in_dark = 8
+// M.see_invisible = 2
+ M.mutations.Add(XRAY)
+ if (M.dna.GetSEState(NERVOUSBLOCK))
+ M.disabilities |= NERVOUS
+ M << "\red You feel nervous."
+ if (M.dna.GetSEState(FIREBLOCK))
+ if(!(mHeatres in old_mutations))
+ if(forced || probinj(30,inj) || (COLD_RESISTANCE in old_mutations))
+ M << "\blue Your body feels warm."
+ M.mutations.Add(COLD_RESISTANCE)
+ else
+ if(forced || probinj(5,inj) || (COLD_RESISTANCE in old_mutations))
+ M << "\blue Your body feels warm."
+ M.mutations.Add(COLD_RESISTANCE)
+ if (M.dna.GetSEState(BLINDBLOCK))
+ M.sdisabilities |= BLIND
+ M << "\red You can't seem to see anything."
+ if (M.dna.GetSEState(TELEBLOCK))
+ if(forced || probinj(15,inj) || (TK in old_mutations))
+ M << "\blue You feel smarter."
+ M.mutations.Add(TK)
+ if (M.dna.GetSEState(DEAFBLOCK))
+ M.sdisabilities |= DEAF
+ M.ear_deaf = 1
+ M << "\red Its kinda quiet.."
+ if (M.dna.GetSEState(GLASSESBLOCK))
+ M.disabilities |= NEARSIGHTED
+ M << "Your eyes feel weird..."
+
+ /* If you want the new mutations to work, UNCOMMENT THIS.
+ if(istype(M, /mob/living/carbon))
+ for (var/datum/mutations/mut in global_mutations)
+ mut.check_mutation(M)
+ */
+
+//////////////////////////////////////////////////////////// Monkey Block
+ if (M.dna.GetSEState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human))
+ // human > monkey
+ var/mob/living/carbon/human/H = M
+ H.monkeyizing = 1
+ var/list/implants = list() //Try to preserve implants.
+ for(var/obj/item/weapon/implant/W in H)
+ implants += W
+ W.loc = null
+
+ if(!connected)
+ for(var/obj/item/W in (H.contents-implants))
+ if (W==H.w_uniform) // will be teared
+ continue
+ H.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("h2monkey", animation)
+ sleep(48)
+ del(animation)
+
+
+ var/mob/living/carbon/monkey/O = null
+ if(H.species.primitive)
+ O = new H.species.primitive(src)
+ else
+ H.gib() //Trying to change the species of a creature with no primitive var set is messy.
+ return
+
+ if(M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+
+ for(var/obj/T in (M.contents-implants))
+ del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the cute little monkey
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+ O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6))
+ O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss() + 20)
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ O.a_intent = "hurt"
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
+
+ if (!M.dna.GetSEState(MONKEYBLOCK) && !istype(M, /mob/living/carbon/human))
+ // monkey > human,
+ var/mob/living/carbon/monkey/Mo = M
+ Mo.monkeyizing = 1
+ var/list/implants = list() //Still preserving implants
+ for(var/obj/item/weapon/implant/W in Mo)
+ implants += W
+ W.loc = null
+ if(!connected)
+ for(var/obj/item/W in (Mo.contents-implants))
+ Mo.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("monkey2h", animation)
+ sleep(48)
+ del(animation)
+
+ var/mob/living/carbon/human/O = new( src )
+ if(Mo.greaterform)
+ O.set_species(Mo.greaterform)
+
+ if (M.dna.GetUIState(DNA_UI_GENDER))
+ O.gender = FEMALE
+ else
+ O.gender = MALE
+
+ if (M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+ //for(var/obj/T in M)
+ // del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the human
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+
+ var/i
+ while (!i)
+ var/randomname
+ if (O.gender == MALE)
+ randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names)))
+ else
+ randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names)))
+ if (findname(randomname))
+ continue
+ else
+ O.real_name = randomname
+ i++
+ O.UpdateAppearance()
+ O.take_overall_damage(M.getBruteLoss(), M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss())
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
+//////////////////////////////////////////////////////////// Monkey Block
+ if(M)
+ M.update_icon = 1 //queue a full icon update at next life() call
+ return null
+/////////////////////////// DNA MISC-PROCS
+*/
\ No newline at end of file
diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm
new file mode 100644
index 00000000000..6f180993fb8
--- /dev/null
+++ b/code/game/dna/dna2_helpers.dm
@@ -0,0 +1,172 @@
+/////////////////////////////
+// Helpers for DNA2
+/////////////////////////////
+
+// Pads 0s to t until length == u
+/proc/add_zero2(t, u)
+ var/temp1
+ while (length(t) < u)
+ t = "0[t]"
+ temp1 = t
+ if (length(t) > u)
+ temp1 = copytext(t,2,u+1)
+ return temp1
+
+// DNA Gene activation boundaries, see dna2.dm.
+// Returns a list object with 4 numbers.
+/proc/GetDNABounds(var/block)
+ var/list/BOUNDS=dna_activity_bounds[block]
+ if(!istype(BOUNDS))
+ return DNA_DEFAULT_BOUNDS
+ return BOUNDS
+
+// Give Random Bad Mutation to M
+/proc/randmutb(var/mob/living/M)
+ if(!M) return
+ M.dna.check_integrity()
+ var/block = pick(GLASSESBLOCK,COUGHBLOCK,FAKEBLOCK,NERVOUSBLOCK,CLUMSYBLOCK,TWITCHBLOCK,HEADACHEBLOCK,BLINDBLOCK,DEAFBLOCK,HALLUCINATIONBLOCK)
+ M.dna.SetSEState(block, 1)
+
+// Give Random Good Mutation to M
+/proc/randmutg(var/mob/living/M)
+ if(!M) return
+ M.dna.check_integrity()
+ var/block = pick(HULKBLOCK,XRAYBLOCK,FIREBLOCK,TELEBLOCK,NOBREATHBLOCK,REMOTEVIEWBLOCK,REGENERATEBLOCK,INCREASERUNBLOCK,REMOTETALKBLOCK,MORPHBLOCK,BLENDBLOCK,NOPRINTSBLOCK,SHOCKIMMUNITYBLOCK,SMALLSIZEBLOCK)
+ M.dna.SetSEState(block, 1)
+
+// Random Appearance Mutation
+/proc/randmuti(var/mob/living/M)
+ if(!M) return
+ M.dna.check_integrity()
+ M.dna.SetUIValue(rand(1,UNIDNASIZE),rand(1,4095))
+
+// Scramble UI or SE.
+/proc/scramble(var/UI, var/mob/M, var/prob)
+ if(!M) return
+ M.dna.check_integrity()
+ if(UI)
+ for(var/i = 1, i <= DNA_UI_LENGTH-1, i++)
+ if(prob(prob))
+ M.dna.SetUIValue(i,rand(1,4095),1)
+ M.dna.UpdateUI()
+ M.UpdateAppearance()
+
+ else
+ for(var/i = 1, i <= STRUCDNASIZE-1, i++)
+ if(prob(prob))
+ M.dna.SetSEValue(i,rand(1,4095),1)
+ M.dna.UpdateSE()
+ domutcheck(M, null)
+ return
+
+// I haven't yet figured out what the fuck this is supposed to do.
+/proc/miniscramble(input,rs,rd)
+ var/output
+ output = null
+ if (input == "C" || input == "D" || input == "E" || input == "F")
+ output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"6",prob((rs*10));"7",prob((rs*5)+(rd));"0",prob((rs*5)+(rd));"1",prob((rs*10)-(rd));"2",prob((rs*10)-(rd));"3")
+ if (input == "8" || input == "9" || input == "A" || input == "B")
+ output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3")
+ if (input == "4" || input == "5" || input == "6" || input == "7")
+ output = pick(prob((rs*10));"4",prob((rs*10));"5",prob((rs*10));"A",prob((rs*10));"B",prob((rs*5)+(rd));"C",prob((rs*5)+(rd));"D",prob((rs*5)+(rd));"2",prob((rs*5)+(rd));"3")
+ if (input == "0" || input == "1" || input == "2" || input == "3")
+ output = pick(prob((rs*10));"8",prob((rs*10));"9",prob((rs*10));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C",prob((rs*10)-(rd));"D",prob((rs*5)+(rd));"E",prob((rs*5)+(rd));"F")
+ if (!output) output = "5"
+ return output
+
+// HELLO I MAKE BELL CURVES AROUND YOUR DESIRED TARGET
+// So a shitty way of replacing gaussian noise.
+// input: YOUR TARGET
+// rs: RAD STRENGTH
+// rd: DURATION
+/proc/miniscrambletarget(input,rs,rd)
+ var/output = null
+ switch(input)
+ if("0")
+ output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10));"2",prob((rs*10)-(rd));"3")
+ if("1")
+ output = pick(prob((rs*10)+(rd));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10));"3",prob((rs*10)-(rd));"4")
+ if("2")
+ output = pick(prob((rs*10));"0",prob((rs*10)+(rd));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10));"4",prob((rs*10)-(rd));"5")
+ if("3")
+ output = pick(prob((rs*10)-(rd));"0",prob((rs*10));"1",prob((rs*10)+(rd));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10));"5",prob((rs*10)-(rd));"6")
+ if("4")
+ output = pick(prob((rs*10)-(rd));"1",prob((rs*10));"2",prob((rs*10)+(rd));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10));"6",prob((rs*10)-(rd));"7")
+ if("5")
+ output = pick(prob((rs*10)-(rd));"2",prob((rs*10));"3",prob((rs*10)+(rd));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10));"7",prob((rs*10)-(rd));"8")
+ if("6")
+ output = pick(prob((rs*10)-(rd));"3",prob((rs*10));"4",prob((rs*10)+(rd));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10));"8",prob((rs*10)-(rd));"9")
+ if("7")
+ output = pick(prob((rs*10)-(rd));"4",prob((rs*10));"5",prob((rs*10)+(rd));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10));"9",prob((rs*10)-(rd));"A")
+ if("8")
+ output = pick(prob((rs*10)-(rd));"5",prob((rs*10));"6",prob((rs*10)+(rd));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10));"A",prob((rs*10)-(rd));"B")
+ if("9")
+ output = pick(prob((rs*10)-(rd));"6",prob((rs*10));"7",prob((rs*10)+(rd));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10));"B",prob((rs*10)-(rd));"C")
+ if("10")//A
+ output = pick(prob((rs*10)-(rd));"7",prob((rs*10));"8",prob((rs*10)+(rd));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10));"C",prob((rs*10)-(rd));"D")
+ if("11")//B
+ output = pick(prob((rs*10)-(rd));"8",prob((rs*10));"9",prob((rs*10)+(rd));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10));"D",prob((rs*10)-(rd));"E")
+ if("12")//C
+ output = pick(prob((rs*10)-(rd));"9",prob((rs*10));"A",prob((rs*10)+(rd));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10));"E",prob((rs*10)-(rd));"F")
+ if("13")//D
+ output = pick(prob((rs*10)-(rd));"A",prob((rs*10));"B",prob((rs*10)+(rd));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10));"F")
+ if("14")//E
+ output = pick(prob((rs*10)-(rd));"B",prob((rs*10));"C",prob((rs*10)+(rd));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F")
+ if("15")//F
+ output = pick(prob((rs*10)-(rd));"C",prob((rs*10));"D",prob((rs*10)+(rd));"E",prob((rs*10)+(rd));"F")
+
+ if(!input || !output) //How did this happen?
+ output = "8"
+
+ return output
+
+// /proc/updateappearance has changed behavior, so it's been removed
+// Use mob.UpdateAppearance() instead.
+
+// Simpler. Don't specify UI in order for the mob to use its own.
+/mob/proc/UpdateAppearance(var/list/UI=null)
+ if(istype(src, /mob/living/carbon/human))
+ if(UI!=null)
+ src.dna.UI=UI
+ src.dna.UpdateUI()
+ dna.check_integrity()
+ var/mob/living/carbon/human/H = src
+ H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255)
+ H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255)
+ H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255)
+
+ H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255)
+ H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255)
+ H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255)
+
+ H.r_eyes = dna.GetUIValueRange(DNA_UI_EYES_R, 255)
+ H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255)
+ H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255)
+
+ H.s_tone = 35 - dna.GetUIValueRange(DNA_UI_SKIN_TONE, 220) // Value can be negative.
+
+ if (dna.GetUIState(DNA_UI_GENDER))
+ H.gender = FEMALE
+ else
+ H.gender = MALE
+
+ //Hair
+ var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len)
+ if((0 < hair) && (hair <= hair_styles_list.len))
+ H.h_style = hair_styles_list[hair]
+
+ //Facial Hair
+ var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len)
+ if((0 < beard) && (beard <= facial_hair_styles_list.len))
+ H.f_style = facial_hair_styles_list[beard]
+
+ H.update_body(0)
+ H.update_hair()
+
+ return 1
+ else
+ return 0
+
+// Used below, simple injection modifier.
+/proc/probinj(var/pr, var/inj)
+ return prob(pr+inj*pr)
diff --git a/code/game/dna/dna_modifier.dm b/code/game/dna/dna_modifier.dm
index 28598b175bb..6be58f811d7 100644
--- a/code/game/dna/dna_modifier.dm
+++ b/code/game/dna/dna_modifier.dm
@@ -1,5 +1,37 @@
#define DNA_BLOCK_SIZE 3
+// Buffer datatype flags.
+#define DNA2_BUF_UI 1
+#define DNA2_BUF_UE 2
+#define DNA2_BUF_SE 4
+
+//list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
+/datum/dna2/record
+ var/datum/dna/dna = null
+ var/types=0
+ var/name="Empty"
+
+ // Stuff for cloners
+ var/id=null
+ var/implant=null
+ var/ckey=null
+ var/mind=null
+
+/datum/dna2/record/proc/GetData()
+ var/list/ser=list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0)
+ ser["ue"] = (types & DNA2_BUF_UE) == DNA2_BUF_UE
+ if(types & DNA2_BUF_SE)
+ ser["data"] = dna.SE
+ else
+ ser["data"] = dna.UI
+ ser["owner"] = src.dna.real_name
+ ser["label"] = name
+ if(types & DNA2_BUF_UI)
+ ser["type"] = "ui"
+ else
+ ser["type"] = "se"
+ return ser
+
/////////////////////////// DNA MACHINES
/obj/machinery/dna_scannernew
name = "\improper DNA modifier"
@@ -14,6 +46,7 @@
var/locked = 0
var/mob/living/carbon/occupant = null
var/obj/item/weapon/reagent_containers/glass/beaker = null
+ var/opened = 0
/obj/machinery/dna_scannernew/New()
..()
@@ -80,12 +113,6 @@
usr.loc = src
src.occupant = usr
src.icon_state = "scanner_1"
- /*
- for(var/obj/O in src) // THIS IS P. STUPID -- LOVE, DOOHL
- //O = null
- del(O)
- //Foreach goto(124)
- */
src.add_fingerprint(usr)
return
@@ -111,7 +138,12 @@
if (G.affecting.abiotic())
user << "\blue Subject cannot have abiotic items on."
return
- var/mob/M = G.affecting
+ put_in(G.affecting)
+ src.add_fingerprint(user)
+ del(G)
+ return
+
+/obj/machinery/dna_scannernew/proc/put_in(var/mob/M)
if(M.client)
M.client.perspective = EYE_PERSPECTIVE
M.client.eye = src
@@ -119,8 +151,6 @@
src.occupant = M
src.icon_state = "scanner_1"
- src.add_fingerprint(user)
-
// search for ghosts, if the corpse is empty and the scanner is connected to a cloner
if(locate(/obj/machinery/computer/cloning, get_step(src, NORTH)) \
|| locate(/obj/machinery/computer/cloning, get_step(src, SOUTH)) \
@@ -132,19 +162,11 @@
if(ghost.mind == M.mind)
ghost << "Your corpse has been placed into a cloning scanner. Return to your body if you want to be resurrected/cloned! (Verbs -> Ghost -> Re-enter corpse)"
break
- del(G)
return
/obj/machinery/dna_scannernew/proc/go_out()
if ((!( src.occupant ) || src.locked))
return
-/*
-// it's like this was -just- here to break constructed dna scanners -Pete
-// if that's not the case, slap my shit and uncomment this.
-// for(var/obj/O in src)
-// O.loc = src.loc
-*/
- //Foreach goto(30)
if (src.occupant.client)
src.occupant.client.eye = src.occupant.client.mob
src.occupant.client.perspective = MOB_PERSPECTIVE
@@ -205,11 +227,7 @@
var/selected_ui_target_hex = 1
var/radiation_duration = 2.0
var/radiation_intensity = 1.0
- var/list/buffers = list(
- list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
- list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0),
- list("data" = null, "owner" = null, "label" = null, "type" = null, "ue" = 0)
- )
+ var/list/datum/dna2/record/buffers[3]
var/irradiating = 0
var/injector_ready = 0 //Quick fix for issue 286 (screwdriver the screen twice to restore injector) -Pete
var/obj/machinery/dna_scannernew/connected = null
@@ -219,6 +237,7 @@
use_power = 1
idle_power_usage = 10
active_power_usage = 400
+ var/waiting_for_user_input=0 // Fix for #274 (Mash create block injector without answering dialog to make unlimited injectors) - N3X
/obj/machinery/computer/scan_consolenew/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/weapon/screwdriver))
@@ -302,19 +321,19 @@
return
return
-/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/buffer)
+/obj/machinery/computer/scan_consolenew/proc/all_dna_blocks(var/list/buffer)
var/list/arr = list()
- for(var/i = 1, i <= length(buffer)/3, i++)
- arr += "[i]:[copytext(buffer,i*3-2,i*3+1)]"
+ for(var/i = 1, i <= buffer.len, i++)
+ arr += "[i]:[EncodeDNABlock(buffer[i])]"
return arr
-/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/buffer)
+/obj/machinery/computer/scan_consolenew/proc/setInjectorBlock(var/obj/item/weapon/dnainjector/I, var/blk, var/datum/dna2/record/buffer)
var/pos = findtext(blk,":")
if(!pos) return 0
var/id = text2num(copytext(blk,1,pos))
if(!id) return 0
I.block = id
- I.dna = copytext(buffer,id*3-2,id*3+1)
+ I.buf = buffer
return 1
/obj/machinery/computer/scan_consolenew/attackby(obj/item/W as obj, mob/user as mob)
@@ -336,6 +355,7 @@
ui_interact(user)
/obj/machinery/computer/scan_consolenew/attack_ai(user as mob)
+ src.add_hiddenprint(user)
ui_interact(user)
/obj/machinery/computer/scan_consolenew/attack_hand(user as mob)
@@ -363,27 +383,26 @@
data["selectedMenuKey"] = selected_menu_key
data["locked"] = src.connected.locked
data["hasOccupant"] = connected.occupant ? 1 : 0
-
+
data["isInjectorReady"] = injector_ready
data["hasDisk"] = disk ? 1 : 0
var/diskData[0]
- if (!disk)
+ if (!disk || !disk.buf)
diskData["data"] = null
diskData["owner"] = null
diskData["label"] = null
diskData["type"] = null
diskData["ue"] = null
else
- diskData["data"] = disk.data
- diskData["owner"] = disk.owner
- diskData["label"] = disk.name
- diskData["type"] = disk.data_type
- diskData["ue"] = disk.ue
+ diskData = disk.buf.GetData()
data["disk"] = diskData
- data["buffers"] = buffers
+ var/list/new_buffers = list()
+ for(var/datum/dna2/record/buf in buffers)
+ new_buffers.Add(buf.GetData())
+ data["buffers"]=new_buffers
data["radiationIntensity"] = radiation_intensity
data["radiationDuration"] = radiation_duration
@@ -571,10 +590,7 @@
return 1 // return 1 forces an update to all Nano uis attached to src
if (href_list["pulseUIRadiation"])
- var/block
- var/newblock
- var/tstructure2
- block = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),src.selected_ui_subblock,1)
+ var/block = src.connected.occupant.dna.GetUISubBlock(src.selected_ui_block,src.selected_ui_subblock)
irradiating = src.radiation_duration
var/lock_state = src.connected.locked
@@ -590,13 +606,8 @@
if (prob((80 + (src.radiation_duration / 2))))
block = miniscrambletarget(num2text(selected_ui_target), src.radiation_intensity, src.radiation_duration)
- newblock = null
- if (src.selected_ui_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_ui_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_ui_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.uni_identity,src.selected_ui_block,DNA_BLOCK_SIZE),2,1) + block
- tstructure2 = setblock(src.connected.occupant.dna.uni_identity, src.selected_ui_block, newblock,DNA_BLOCK_SIZE)
- src.connected.occupant.dna.uni_identity = tstructure2
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
+ src.connected.occupant.dna.SetUISubBlock(src.selected_ui_block,src.selected_ui_subblock,block)
+ src.connected.occupant.UpdateAppearance()
src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
else
if (prob(20+src.radiation_intensity))
@@ -604,7 +615,7 @@
domutcheck(src.connected.occupant,src.connected)
else
randmuti(src.connected.occupant)
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
+ src.connected.occupant.UpdateAppearance()
src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration)
src.connected.locked = lock_state
return 1 // return 1 forces an update to all Nano uis attached to src
@@ -632,15 +643,13 @@
src.selected_se_block = select_block
if ((select_subblock <= DNA_BLOCK_SIZE) && (select_subblock >= 1))
src.selected_se_subblock = select_subblock
+ //testing("User selected block [selected_se_block] (sent [select_block]), subblock [selected_se_subblock] (sent [select_block]).")
return 1 // return 1 forces an update to all Nano uis attached to src
if (href_list["pulseSERadiation"])
- var/block
- var/newblock
- var/tstructure2
- var/oldblock
-
- block = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),src.selected_se_subblock,1)
+ var/block = src.connected.occupant.dna.GetSESubBlock(src.selected_se_block,src.selected_se_subblock)
+ //var/original_block=block
+ //testing("Irradiating SE block [src.selected_se_block]:[src.selected_se_subblock] ([block])...")
irradiating = src.radiation_duration
var/lock_state = src.connected.locked
@@ -653,47 +662,37 @@
if(src.connected.occupant)
if (prob((80 + (src.radiation_duration / 2))))
- if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20))
- oldblock = src.selected_se_block
- block = miniscramble(block, src.radiation_intensity, src.radiation_duration)
- newblock = null
+ // FIXME: Find out what these corresponded to and change them to the WHATEVERBLOCK they need to be.
+ //if ((src.selected_se_block != 2 || src.selected_se_block != 12 || src.selected_se_block != 8 || src.selected_se_block || 10) && prob (20))
+ var/real_SE_block=selected_se_block
+ block = miniscramble(block, src.radiation_intensity, src.radiation_duration)
+ if(prob(20))
if (src.selected_se_block > 1 && src.selected_se_block < STRUCDNASIZE/2)
- src.selected_se_block++
+ real_SE_block++
else if (src.selected_se_block > STRUCDNASIZE/2 && src.selected_se_block < STRUCDNASIZE)
- src.selected_se_block--
- if (src.selected_se_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + block
- tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.selected_se_block, newblock,DNA_BLOCK_SIZE)
- src.connected.occupant.dna.struc_enzymes = tstructure2
- domutcheck(src.connected.occupant,src.connected)
- src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
- src.selected_se_block = oldblock
- else
- //
- block = miniscramble(block, src.radiation_intensity, src.radiation_duration)
- newblock = null
- if (src.selected_se_subblock == 1) newblock = block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 2) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + block + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),3,1)
- if (src.selected_se_subblock == 3) newblock = getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),1,1) + getblock(getblock(src.connected.occupant.dna.struc_enzymes,src.selected_se_block,DNA_BLOCK_SIZE),2,1) + block
- tstructure2 = setblock(src.connected.occupant.dna.struc_enzymes, src.selected_se_block, newblock,DNA_BLOCK_SIZE)
- src.connected.occupant.dna.struc_enzymes = tstructure2
- domutcheck(src.connected.occupant,src.connected)
- src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
+ real_SE_block--
+
+ //testing("Irradiated SE block [real_SE_block]:[src.selected_se_subblock] ([original_block] now [block]) [(real_SE_block!=selected_se_block) ? "(SHIFTED)":""]!")
+ connected.occupant.dna.SetSESubBlock(real_SE_block,selected_se_subblock,block)
+ src.connected.occupant.radiation += (src.radiation_intensity+src.radiation_duration)
+ domutcheck(src.connected.occupant,src.connected)
else
+ src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration)
if (prob(80-src.radiation_duration))
+ //testing("Random bad mut!")
randmutb(src.connected.occupant)
domutcheck(src.connected.occupant,src.connected)
else
randmuti(src.connected.occupant)
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
- src.connected.occupant.radiation += ((src.radiation_intensity*2)+src.radiation_duration)
+ //testing("Random identity mut!")
+ src.connected.occupant.UpdateAppearance()
src.connected.locked = lock_state
return 1 // return 1 forces an update to all Nano uis attached to src
if(href_list["ejectBeaker"])
if(connected.beaker)
- connected.beaker.loc = connected.loc
+ var/obj/item/weapon/reagent_containers/glass/B = connected.beaker
+ B.loc = connected.loc
connected.beaker = null
return 1
@@ -704,18 +703,14 @@
// Transfer Buffer Management
if(href_list["bufferOption"])
var/bufferOption = href_list["bufferOption"]
-
+
// These bufferOptions do not require a bufferId
if (bufferOption == "wipeDisk")
if ((isnull(src.disk)) || (src.disk.read_only))
//src.temphtml = "Invalid disk. Please try again."
return 0
- src.disk.data = null
- src.disk.data_type = null
- src.disk.ue = null
- src.disk.owner = null
- src.disk.name = null
+ src.disk.buf=null
//src.temphtml = "Data saved."
return 1
@@ -724,12 +719,12 @@
return
src.disk.loc = get_turf(src)
src.disk = null
- return 1
-
+ return 1
+
// All bufferOptions from here on require a bufferId
if (!href_list["bufferId"])
return 0
-
+
var/bufferId = text2num(href_list["bufferId"])
if (bufferId < 1 || bufferId > 3)
@@ -737,56 +732,46 @@
if (bufferOption == "saveUI")
if(src.connected.occupant && src.connected.occupant.dna)
- src.buffers[bufferId]["ue"] = 0
- src.buffers[bufferId]["data"] = src.connected.occupant.dna.uni_identity
- if (!istype(src.connected.occupant,/mob/living/carbon/human))
- src.buffers[bufferId]["owner"] = src.connected.occupant.name
- else
- src.buffers[bufferId]["owner"] = src.connected.occupant.real_name
- src.buffers[bufferId]["label"] = "Unique Identifier"
- src.buffers[bufferId]["type"] = "ui"
+ var/datum/dna2/record/databuf=new
+ databuf.types = DNA2_BUF_UE
+ databuf.dna = src.connected.occupant.dna
+ databuf.name = "Unique Identifier"
+ src.buffers[bufferId] = databuf
return 1
if (bufferOption == "saveUIAndUE")
if(src.connected.occupant && src.connected.occupant.dna)
- src.buffers[bufferId]["data"] = src.connected.occupant.dna.uni_identity
- if (!istype(src.connected.occupant,/mob/living/carbon/human))
- src.buffers[bufferId]["owner"] = src.connected.occupant.name
- else
- src.buffers[bufferId]["owner"] = src.connected.occupant.real_name
- src.buffers[bufferId]["label"] = "Unique Identifier + Unique Enzymes"
- src.buffers[bufferId]["type"] = "ui"
- src.buffers[bufferId]["ue"] = 1
+ var/datum/dna2/record/databuf=new
+ databuf.types = DNA2_BUF_UI|DNA2_BUF_UE
+ databuf.dna = src.connected.occupant.dna
+ databuf.name = "Unique Identifier + Unique Enzymes"
+ src.buffers[bufferId] = databuf
return 1
if (bufferOption == "saveSE")
if(src.connected.occupant && src.connected.occupant.dna)
- src.buffers[bufferId]["ue"] = 0
- src.buffers[bufferId]["data"] = src.connected.occupant.dna.struc_enzymes
- if (!istype(src.connected.occupant,/mob/living/carbon/human))
- src.buffers[bufferId]["owner"] = src.connected.occupant.name
- else
- src.buffers[bufferId]["owner"] = src.connected.occupant.real_name
- src.buffers[bufferId]["label"] = "Structural Enzymes"
- src.buffers[bufferId]["type"] = "se"
+ var/datum/dna2/record/databuf=new
+ databuf.types = DNA2_BUF_SE
+ databuf.dna = src.connected.occupant.dna
+ databuf.name = "Structural Enzymes"
+ src.buffers[bufferId] = databuf
return 1
if (bufferOption == "clear")
- src.buffers[bufferId]["data"] = null
- src.buffers[bufferId]["owner"] = null
- src.buffers[bufferId]["label"] = null
- src.buffers[bufferId]["ue"] = null
+ src.buffers[bufferId]=null
return 1
if (bufferOption == "changeLabel")
- var/label = src.buffers[bufferId]["label"] ? src.buffers[bufferId]["label"] : "New Label"
- src.buffers[bufferId]["label"] = sanitize(input("New Label:", "Edit Label", label))
+ var/datum/dna2/record/buf = src.buffers[bufferId]
+ buf.name = buf.name ? src.buffers[bufferId]["label"] : "New Label"
+ buf.name = sanitize(input("New Label:", "Edit Label", buf.name))
+ src.buffers[bufferId] = buf
return 1
if (bufferOption == "transfer")
if (!src.connected.occupant || (NOCLONE in src.connected.occupant.mutations) || !src.connected.occupant.dna)
return
-
+
irradiating = 2
var/lock_state = src.connected.locked
src.connected.locked = 1//lock it
@@ -796,33 +781,37 @@
irradiating = 0
src.connected.locked = lock_state
-
- if (src.buffers[bufferId]["type"] == "ui")
- if (src.buffers[bufferId]["ue"])
- src.connected.occupant.real_name = src.buffers[bufferId]["owner"]
- src.connected.occupant.name = src.buffers[bufferId]["owner"]
- src.connected.occupant.dna.uni_identity = src.buffers[bufferId]["data"]
- updateappearance(src.connected.occupant,src.connected.occupant.dna.uni_identity)
- else if (src.buffers[bufferId]["type"] == "se")
- src.connected.occupant.dna.struc_enzymes = src.buffers[bufferId]["data"]
+
+ var/datum/dna2/record/buf = src.buffers[bufferId]
+
+ if ((buf.types & DNA2_BUF_UI))
+ if ((buf.types & DNA2_BUF_UE))
+ src.connected.occupant.real_name = buf.dna.real_name
+ src.connected.occupant.name = buf.dna.real_name
+ src.connected.occupant.UpdateAppearance(buf.dna.UI)
+ else if (buf.types & DNA2_BUF_SE)
+ src.connected.occupant.dna.SE = buf.dna.SE
+ src.connected.occupant.dna.UpdateSE()
domutcheck(src.connected.occupant,src.connected)
src.connected.occupant.radiation += rand(20,50)
return 1
if (bufferOption == "createInjector")
- if (src.injector_ready)
+ if (src.injector_ready || waiting_for_user_input)
+
var/success = 1
var/obj/item/weapon/dnainjector/I = new /obj/item/weapon/dnainjector
- I.dnatype = src.buffers[bufferId]["type"]
+ var/datum/dna2/record/buf = src.buffers[bufferId]
if(href_list["createBlockInjector"])
- var/blk = input(usr,"Select Block","Block") in all_dna_blocks(src.buffers[bufferId]["data"])
- success = setInjectorBlock(I,blk,src.buffers[bufferId]["data"])
+ waiting_for_user_input=1
+ var/blk = input(usr,"Select Block","Block") in all_dna_blocks(buf.GetData())
+ success = setInjectorBlock(I,blk,buf)
else
- I.dna = src.buffers[bufferId]["data"]
+ I.buf = buf
+ waiting_for_user_input=0
if(success)
I.loc = src.loc
- I.name += " ([src.buffers[bufferId]["label"]])"
- if (src.buffers[bufferId]["ue"]) I.ue = src.buffers[bufferId]["owner"] //lazy haw haw
+ I.name += " ([buf.name])"
//src.temphtml = "Injector created."
src.injector_ready = 0
spawn(300)
@@ -834,14 +823,11 @@
return 1
if (bufferOption == "loadDisk")
- if ((isnull(src.disk)) || (!src.disk.data) || (src.disk.data == ""))
+ if ((isnull(src.disk)) || (!src.disk.buf))
//src.temphtml = "Invalid disk. Please try again."
return 0
- src.buffers[bufferId]["data"] = src.disk.data
- src.buffers[bufferId]["type"] = src.disk.data_type
- src.buffers[bufferId]["ue"] = src.disk.ue
- src.buffers[bufferId]["owner"] = src.disk.owner
+ src.buffers[bufferId]=src.disk.buf
//src.temphtml = "Data loaded."
return 1
@@ -850,13 +836,12 @@
//src.temphtml = "Invalid disk. Please try again."
return 0
- src.disk.data = buffers[bufferId]["data"]
- src.disk.data_type = src.buffers[bufferId]["type"]
- src.disk.ue = src.buffers[bufferId]["ue"]
- src.disk.owner = src.buffers[bufferId]["owner"]
- src.disk.name = "data disk - '[src.buffers[bufferId]["owner"]]'"
+ var/datum/dna2/record/buf = src.buffers[bufferId]
+
+ src.disk.buf = buf
+ src.disk.name = "data disk - '[buf.dna.real_name]'"
//src.temphtml = "Data saved."
- return 1
+ return 1
/////////////////////////// DNA MACHINES
diff --git a/code/game/dna/genes/disabilities.dm b/code/game/dna/genes/disabilities.dm
new file mode 100644
index 00000000000..e312111f6f3
--- /dev/null
+++ b/code/game/dna/genes/disabilities.dm
@@ -0,0 +1,125 @@
+/////////////////////
+// DISABILITY GENES
+//
+// These activate either a mutation, disability, or sdisability.
+//
+// Gene is always activated.
+/////////////////////
+
+/datum/dna/gene/disability
+ name="DISABILITY"
+
+ // Mutation to give (or 0)
+ var/mutation=0
+
+ // Disability to give (or 0)
+ var/disability=0
+
+ // SDisability to give (or 0)
+ var/sdisability=0
+
+ // Activation message
+ var/activation_message=""
+
+ // Yay, you're no longer growing 3 arms
+ var/deactivation_message=""
+
+/datum/dna/gene/disability/can_activate(var/mob/M,var/flags)
+ return 1 // Always set!
+
+/datum/dna/gene/disability/activate(var/mob/M, var/connected, var/flags)
+ if(mutation && !(mutation in M.mutations))
+ M.mutations.Add(mutation)
+ if(disability)
+ M.disabilities|=disability
+ if(sdisability)
+ M.sdisabilities|=sdisability
+ if(activation_message)
+ M << "\red [activation_message]"
+
+/datum/dna/gene/disability/deactivate(var/mob/M, var/connected, var/flags)
+ if(mutation && (mutation in M.mutations))
+ M.mutations.Remove(mutation)
+ if(disability)
+ M.disabilities &= ~disability
+ if(sdisability)
+ M.sdisabilities &= ~sdisability
+ if(deactivation_message)
+ M << "\red [deactivation_message]"
+
+// Note: Doesn't seem to do squat, at the moment.
+/datum/dna/gene/disability/hallucinate
+ name="Hallucinate"
+ activation_message="Your mind says 'Hello'."
+ mutation=mHallucination
+
+ New()
+ block=HALLUCINATIONBLOCK
+
+/datum/dna/gene/disability/epilepsy
+ name="Epilepsy"
+ activation_message="You get a headache."
+ disability=EPILEPSY
+
+ New()
+ block=HEADACHEBLOCK
+
+/datum/dna/gene/disability/cough
+ name="Coughing"
+ activation_message="You start coughing."
+ disability=COUGHING
+
+ New()
+ block=COUGHBLOCK
+
+/datum/dna/gene/disability/clumsy
+ name="Clumsiness"
+ activation_message="You feel lightheaded."
+ mutation=CLUMSY
+
+ New()
+ block=CLUMSYBLOCK
+
+/datum/dna/gene/disability/tourettes
+ name="Tourettes"
+ activation_message="You twitch."
+ disability=TOURETTES
+
+ New()
+ block=TWITCHBLOCK
+
+/datum/dna/gene/disability/nervousness
+ name="Nervousness"
+ activation_message="You feel nervous."
+ disability=NERVOUS
+
+ New()
+ block=NERVOUSBLOCK
+
+/datum/dna/gene/disability/blindness
+ name="Blindness"
+ activation_message="You can't seem to see anything."
+ sdisability=BLIND
+
+ New()
+ block=BLINDBLOCK
+
+/datum/dna/gene/disability/deaf
+ name="Deafness"
+ activation_message="It's kinda quiet."
+ sdisability=DEAF
+
+ New()
+ block=DEAFBLOCK
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.ear_deaf = 1
+
+/datum/dna/gene/disability/nearsighted
+ name="Nearsightedness"
+ activation_message="Your eyes feel weird..."
+ disability=NEARSIGHTED
+
+ New()
+ block=GLASSESBLOCK
\ No newline at end of file
diff --git a/code/game/dna/genes/gene.dm b/code/game/dna/genes/gene.dm
new file mode 100644
index 00000000000..3bf5b5e5f75
--- /dev/null
+++ b/code/game/dna/genes/gene.dm
@@ -0,0 +1,88 @@
+/**
+* Gene Datum
+*
+* domutcheck was getting pretty hairy. This is the solution.
+*
+* All genes are stored in a global variable to cut down on memory
+* usage.
+*
+* @author N3X15
+*/
+
+/datum/dna/gene
+ // Display name
+ var/name="BASE GENE"
+
+ // Probably won't get used but why the fuck not
+ var/desc="Oh god who knows what this does."
+
+ // Set in initialize()!
+ // What gene activates this?
+ var/block=0
+
+ // Any of a number of GENE_ flags.
+ var/flags=0
+
+// Return 1 if we can activate.
+// HANDLE MUTCHK_FORCED HERE!
+/datum/dna/gene/proc/can_activate(var/mob/M, var/flags)
+ return 0
+
+// Called when the gene activates. Do your magic here.
+/datum/dna/gene/proc/activate(var/mob/M, var/connected, var/flags)
+ return
+
+// Called when the gene deactivates. Undo your magic here.
+// Only called when the block is deactivated.
+/datum/dna/gene/proc/deactivate(var/mob/M, var/connected, var/flags)
+ return
+
+
+/////////////////////
+// BASIC GENES
+//
+// These just chuck in a mutation and display a message.
+//
+// Gene is activated:
+// 1. If mutation already exists in mob
+// 2. If the probability roll succeeds
+// 3. Activation is forced (done in domutcheck)
+/////////////////////
+
+
+/datum/dna/gene/basic
+ name="BASIC GENE"
+
+ // Mutation to give
+ var/mutation=0
+
+ // Activation probability
+ var/activation_prob=45
+
+ // Possible activation messages
+ var/list/activation_messages=list()
+
+ // Possible deactivation messages
+ var/list/deactivation_messages=list()
+
+/datum/dna/gene/basic/can_activate(var/mob/M,var/flags)
+ if(mutation==0)
+ return 0
+
+ // Probability check
+ if(flags & MUTCHK_FORCED || probinj(activation_prob,(flags&MUTCHK_FORCED)))
+ return 1
+
+ return 0
+
+/datum/dna/gene/basic/activate(var/mob/M)
+ M.mutations.Add(mutation)
+ if(activation_messages.len)
+ var/msg = pick(activation_messages)
+ M << "\blue [msg]"
+
+/datum/dna/gene/basic/deactivate(var/mob/M)
+ M.mutations.Remove(mutation)
+ if(deactivation_messages.len)
+ var/msg = pick(deactivation_messages)
+ M << "\red [msg]"
\ No newline at end of file
diff --git a/code/game/dna/genes/monkey.dm b/code/game/dna/genes/monkey.dm
new file mode 100644
index 00000000000..952f7df0f48
--- /dev/null
+++ b/code/game/dna/genes/monkey.dm
@@ -0,0 +1,170 @@
+/datum/dna/gene/monkey
+ name="Monkey"
+
+/datum/dna/gene/monkey/New()
+ block=MONKEYBLOCK
+
+/datum/dna/gene/monkey/can_activate(var/mob/M,var/flags)
+ return istype(M, /mob/living/carbon/human) || istype(M,/mob/living/carbon/monkey)
+
+/datum/dna/gene/monkey/activate(var/mob/living/M, var/connected, var/flags)
+ if(!istype(M,/mob/living/carbon/human))
+ return
+ var/mob/living/carbon/human/H = M
+ H.monkeyizing = 1
+ var/list/implants = list() //Try to preserve implants.
+ for(var/obj/item/weapon/implant/W in H)
+ implants += W
+ W.loc = null
+
+ if(!connected)
+ for(var/obj/item/W in (H.contents-implants))
+ if (W==H.w_uniform) // will be teared
+ continue
+ H.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("h2monkey", animation)
+ sleep(48)
+ del(animation)
+
+
+ var/mob/living/carbon/monkey/O = null
+ if(H.species.primitive)
+ O = new H.species.primitive(src)
+ else
+ H.gib() //Trying to change the species of a creature with no primitive var set is messy.
+ return
+
+ if(M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+
+ for(var/obj/T in (M.contents-implants))
+ del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the cute little monkey
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+ O.real_name = text("monkey ([])",copytext(md5(M.real_name), 2, 6))
+ O.take_overall_damage(M.getBruteLoss() + 40, M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss() + 20)
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ O.a_intent = "hurt"
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
+
+/datum/dna/gene/monkey/deactivate(var/mob/living/M, var/connected, var/flags)
+ if(!istype(M,/mob/living/carbon/monkey))
+ return
+ var/mob/living/carbon/monkey/Mo = M
+ Mo.monkeyizing = 1
+ var/list/implants = list() //Still preserving implants
+ for(var/obj/item/weapon/implant/W in Mo)
+ implants += W
+ W.loc = null
+ if(!connected)
+ for(var/obj/item/W in (Mo.contents-implants))
+ Mo.drop_from_inventory(W)
+ M.monkeyizing = 1
+ M.canmove = 0
+ M.icon = null
+ M.invisibility = 101
+ var/atom/movable/overlay/animation = new( M.loc )
+ animation.icon_state = "blank"
+ animation.icon = 'icons/mob/mob.dmi'
+ animation.master = src
+ flick("monkey2h", animation)
+ sleep(48)
+ del(animation)
+
+ var/mob/living/carbon/human/O = new( src )
+ if(Mo.greaterform)
+ O.set_species(Mo.greaterform)
+
+ if (M.dna.GetUIState(DNA_UI_GENDER))
+ O.gender = FEMALE
+ else
+ O.gender = MALE
+
+ if (M)
+ if (M.dna)
+ O.dna = M.dna
+ M.dna = null
+
+ if (M.suiciding)
+ O.suiciding = M.suiciding
+ M.suiciding = null
+
+ for(var/datum/disease/D in M.viruses)
+ O.viruses += D
+ D.affected_mob = O
+ M.viruses -= D
+
+ //for(var/obj/T in M)
+ // del(T)
+
+ O.loc = M.loc
+
+ if(M.mind)
+ M.mind.transfer_to(O) //transfer our mind to the human
+
+ if (connected) //inside dna thing
+ var/obj/machinery/dna_scannernew/C = connected
+ O.loc = C
+ C.occupant = O
+ connected = null
+
+ var/i
+ while (!i)
+ var/randomname
+ if (O.gender == MALE)
+ randomname = capitalize(pick(first_names_male) + " " + capitalize(pick(last_names)))
+ else
+ randomname = capitalize(pick(first_names_female) + " " + capitalize(pick(last_names)))
+ if (findname(randomname))
+ continue
+ else
+ O.real_name = randomname
+ i++
+ O.UpdateAppearance()
+ O.take_overall_damage(M.getBruteLoss(), M.getFireLoss())
+ O.adjustToxLoss(M.getToxLoss())
+ O.adjustOxyLoss(M.getOxyLoss())
+ O.stat = M.stat
+ for (var/obj/item/weapon/implant/I in implants)
+ I.loc = O
+ I.implanted = O
+// O.update_icon = 1 //queue a full icon update at next life() call
+ del(M)
+ return
\ No newline at end of file
diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm
new file mode 100644
index 00000000000..a8a9eefee7d
--- /dev/null
+++ b/code/game/dna/genes/powers.dm
@@ -0,0 +1,167 @@
+///////////////////////////////////
+// POWERS
+///////////////////////////////////
+
+/datum/dna/gene/basic/nobreath
+ name="No Breathing"
+ activation_messages=list("You feel no need to breathe.")
+ mutation=mNobreath
+
+ New()
+ block=NOBREATHBLOCK
+
+/datum/dna/gene/basic/remoteview
+ name="Remote Viewing"
+ activation_messages=list("Your mind expands.")
+ mutation=mRemote
+
+ New()
+ block=REMOTEVIEWBLOCK
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.verbs += /mob/living/carbon/human/proc/remoteobserve
+
+/datum/dna/gene/basic/regenerate
+ name="Regenerate"
+ activation_messages=list("You feel better.")
+ mutation=mRegen
+
+ New()
+ block=REGENERATEBLOCK
+
+/datum/dna/gene/basic/increaserun
+ name="Super Speed"
+ activation_messages=list("Your leg muscles pulsate.")
+ mutation=mRun
+
+ New()
+ block=INCREASERUNBLOCK
+
+/datum/dna/gene/basic/remotetalk
+ name="Telepathy"
+ activation_messages=list("You expand your mind outwards.")
+ mutation=mRemotetalk
+
+ New()
+ block=REMOTETALKBLOCK
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.verbs += /mob/living/carbon/human/proc/remotesay
+
+/datum/dna/gene/basic/morph
+ name="Morph"
+ activation_messages=list("Your skin feels strange.")
+ mutation=mMorph
+
+ New()
+ block=MORPHBLOCK
+
+ activate(var/mob/M)
+ ..(M)
+ M.verbs += /mob/living/carbon/human/proc/morph
+
+/* Not used on bay
+/datum/dna/gene/basic/heat_resist
+ name="Heat Resistance"
+ activation_messages=list("Your skin is icy to the touch.")
+ mutation=mHeatres
+
+ New()
+ block=COLDBLOCK
+
+ can_activate(var/mob/M,var/flags)
+ // Probability check
+ var/_prob = 15
+ if(COLD_RESISTANCE in M.mutations)
+ _prob=5
+ if(probinj(_prob,(flags&MUTCHK_FORCED)))
+ return 1
+*/
+
+/datum/dna/gene/basic/cold_resist
+ name="Cold Resistance"
+ activation_messages=list("Your body is filled with warmth.")
+ mutation=COLD_RESISTANCE
+
+ New()
+ block=FIREBLOCK
+
+ can_activate(var/mob/M,var/flags)
+
+ // Probability check
+ var/_prob=30
+ //if(mHeatres in M.mutations)
+ // _prob=5
+ if(probinj(_prob,(flags&MUTCHK_FORCED)))
+ return 1
+
+/datum/dna/gene/basic/noprints
+ name="No Prints"
+ activation_messages=list("Your fingers feel numb.")
+ mutation=mFingerprints
+
+ New()
+ block=NOPRINTSBLOCK
+
+/datum/dna/gene/basic/noshock
+ name="Shock Immunity"
+ activation_messages=list("Your skin feels strange.")
+ mutation=mShock
+
+ New()
+ block=SHOCKIMMUNITYBLOCK
+
+/datum/dna/gene/basic/midget
+ name="Midget"
+ activation_messages=list("Your skin feels rubbery.")
+ mutation=mSmallsize
+
+ New()
+ block=SMALLSIZEBLOCK
+
+ can_activate(var/mob/M,var/flags)
+ // Can't be big and small.
+ if(HULK in M.mutations)
+ return 0
+ return ..(M,flags)
+
+ activate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.pass_flags |= 1
+
+ deactivate(var/mob/M, var/connected, var/flags)
+ ..(M,connected,flags)
+ M.pass_flags &= ~1 //This may cause issues down the track, but offhand I can't think of any other way for humans to get passtable short of varediting so it should be fine. ~Z
+
+/datum/dna/gene/basic/hulk
+ name="Hulk"
+ activation_messages=list("Your muscles hurt.")
+ mutation=HULK
+
+ New()
+ block=HULKBLOCK
+
+ can_activate(var/mob/M,var/flags)
+ // Can't be big and small.
+ if(mSmallsize in M.mutations)
+ return 0
+ return ..(M,flags)
+
+/datum/dna/gene/basic/xray
+ name="X-Ray Vision"
+ activation_messages=list("The walls suddenly disappear.")
+ mutation=XRAY
+
+ New()
+ block=XRAYBLOCK
+
+/datum/dna/gene/basic/tk
+ name="Telekenesis"
+ activation_messages=list("You feel smarter.")
+ mutation=TK
+ activation_prob=15
+
+ New()
+ block=TELEBLOCK
\ 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 e66aed88b87..a552ac1cd74 100644
--- a/code/game/gamemodes/changeling/changeling_powers.dm
+++ b/code/game/gamemodes/changeling/changeling_powers.dm
@@ -187,7 +187,7 @@
src.dna = chosen_dna
src.real_name = chosen_dna.real_name
src.flavor_text = ""
- updateappearance(src, src.dna.uni_identity)
+ src.UpdateAppearance()
domutcheck(src, null)
src.verbs -= /mob/proc/changeling_transform
@@ -205,6 +205,10 @@
var/datum/changeling/changeling = changeling_power(1,0,0)
if(!changeling) return
+ if(src.has_brain_worms())
+ src << "We cannot perform this ability at the present time!"
+ return
+
var/mob/living/carbon/C = src
changeling.chem_charges--
C.remove_changeling_powers()
@@ -314,7 +318,7 @@
W.layer = initial(W.layer)
var/mob/living/carbon/human/O = new /mob/living/carbon/human( src )
- if (isblockon(getblock(C.dna.uni_identity, 11,3),11))
+ if (C.dna.GetUIState(DNA_UI_GENDER))
O.gender = FEMALE
else
O.gender = MALE
@@ -327,7 +331,7 @@
O.loc = C.loc
- updateappearance(O,O.dna.uni_identity)
+ O.UpdateAppearance()
domutcheck(O, null)
O.setToxLoss(C.getToxLoss())
O.adjustBruteLoss(C.getBruteLoss())
@@ -370,24 +374,24 @@
if(changeling_power(20,1,100,DEAD))
// charge the changeling chemical cost for stasis
changeling.chem_charges -= 20
-
+
// restore us to health
C.rejuvenate()
-
+
// remove our fake death flag
C.status_flags &= ~(FAKEDEATH)
-
+
// let us move again
C.update_canmove()
-
+
// re-add out changeling powers
- C.make_changeling()
-
+ C.make_changeling()
+
// sending display messages
C << "We have regenerated."
C.visible_message("[src] appears to wake from the dead, having healed all wounds.")
-
-
+
+
feedback_add_details("changeling_powers","FD")
return 1
@@ -719,7 +723,7 @@ var/list/datum/dna/hivemind_bank = list()
T.visible_message("[T] transforms!")
T.dna = chosen_dna
T.real_name = chosen_dna.real_name
- updateappearance(T, T.dna.uni_identity)
+ T.UpdateAppearance()
domutcheck(T, null)
feedback_add_details("changeling_powers","TS")
return 1
diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm
index b9f68fb143c..5b1b1494b59 100644
--- a/code/game/gamemodes/events.dm
+++ b/code/game/gamemodes/events.dm
@@ -163,8 +163,8 @@
continue
var/datum/disease/dnaspread/D = new
D.strain_data["name"] = H.real_name
- D.strain_data["UI"] = H.dna.uni_identity
- D.strain_data["SE"] = H.dna.struc_enzymes
+ D.strain_data["UI"] = H.dna.UI
+ D.strain_data["SE"] = H.dna.SE
D.carrier = 1
D.holder = H
D.affected_mob = H
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index be688554147..f9a237b083d 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -209,9 +209,7 @@
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(synd_mob), slot_w_uniform)
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(synd_mob), slot_shoes)
- synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(synd_mob), slot_wear_suit)
synd_mob.equip_to_slot_or_del(new /obj/item/clothing/gloves/swat(synd_mob), slot_gloves)
- synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/swat(synd_mob), slot_head)
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/card/id/syndicate(synd_mob), slot_wear_id)
if(synd_mob.backbag == 2) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(synd_mob), slot_back)
if(synd_mob.backbag == 3) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(synd_mob), slot_back)
@@ -221,6 +219,26 @@
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/pill/cyanide(synd_mob), slot_in_backpack)
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/c20r(synd_mob), slot_belt)
synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(synd_mob.back), slot_in_backpack)
+
+ if(synd_mob.species)
+ var/race = synd_mob.species.name
+
+ if(race == "Unathi")
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/unathi(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/unathi(synd_mob), slot_head)
+ else if(race == "Tajaran")
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/tajara(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/tajara(synd_mob), slot_head)
+ else if(race == "Skrell")
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/skrell(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/skrell(synd_mob), slot_head)
+ else
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/human(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/human(synd_mob), slot_head)
+ else
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/syndi/human(synd_mob), slot_wear_suit)
+ synd_mob.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/syndi/human(synd_mob), slot_head)
+
var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(synd_mob)
E.imp_in = synd_mob
E.implanted = 1
diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm
index 53d90a7e98c..813bbbabf2c 100644
--- a/code/game/gamemodes/setupgame.dm
+++ b/code/game/gamemodes/setupgame.dm
@@ -1,10 +1,27 @@
+/////////////////////////
+// (mostly) DNA2 SETUP
+/////////////////////////
+
+// Randomize block, assign a reference name, and optionally define difficulty (by making activation zone smaller or bigger)
+// The name is used on /vg/ for species with predefined genetic traits,
+// and for the DNA panel in the player panel.
+/proc/getAssignedBlock(var/name,var/list/blocksLeft, var/activity_bounds=DNA_DEFAULT_BOUNDS)
+ var/assigned = pick(blocksLeft)
+ blocksLeft.Remove(assigned)
+ assigned_blocks[assigned]=name
+ dna_activity_bounds[assigned]=activity_bounds
+ //testing("[name] assigned to block #[assigned].")
+ return assigned
+
/proc/setupgenetics()
if (prob(50))
+ // Currently unused. Will revisit. - N3X
BLOCKADD = rand(-300,300)
if (prob(75))
DIFFMUT = rand(0,20)
+ /* Old, for reference (so I don't accidentally activate something) - N3X
var/list/avnums = new/list()
var/tempnum
@@ -41,11 +58,62 @@
tempnum = pick(avnums)
avnums.Remove(tempnum)
BLINDBLOCK = tempnum
+ */
+ var/list/numsToAssign=new()
+ for(var/i=1;iThis being is corrupted by an alien intelligence and cannot be soul trapped."
+ return..()
+
M.attack_log += text("\[[time_stamp()]\] Has had their soul captured with [src.name] by [user.name] ([user.ckey])")
user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to capture the soul of [M.name] ([M.ckey])")
msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to capture the soul of [M.name] ([M.ckey]) (JMP)")
diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm
index 1303976b131..4f2f6596633 100644
--- a/code/game/jobs/job/medical.dm
+++ b/code/game/jobs/job/medical.dm
@@ -15,7 +15,7 @@
minimal_access = list(access_medical, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
access_keycard_auth, access_sec_doors, access_psychiatrist)
- minimal_player_age = 7
+ minimal_player_age = 10
equip(var/mob/living/carbon/human/H)
if(!H) return 0
diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm
index 4d0488f1229..69e9babb0ac 100644
--- a/code/game/jobs/job/security.dm
+++ b/code/game/jobs/job/security.dm
@@ -60,7 +60,7 @@
selection_color = "#ffeeee"
access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels, access_morgue)
minimal_access = list(access_security, access_sec_doors, access_brig, access_armory, access_court, access_maint_tunnels)
- minimal_player_age = 7
+ minimal_player_age = 5
equip(var/mob/living/carbon/human/H)
if(!H) return 0
@@ -100,7 +100,7 @@
access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
minimal_access = list(access_security, access_sec_doors, access_forensics_lockers, access_morgue, access_maint_tunnels, access_court)
alt_titles = list("Forensic Technician")
- minimal_player_age = 7
+ minimal_player_age = 3
equip(var/mob/living/carbon/human/H)
if(!H) return 0
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear)
@@ -146,7 +146,7 @@
selection_color = "#ffeeee"
access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels, access_morgue)
minimal_access = list(access_security, access_sec_doors, access_brig, access_court, access_maint_tunnels)
- minimal_player_age = 7
+ minimal_player_age = 3
equip(var/mob/living/carbon/human/H)
if(!H) return 0
H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sec(H), slot_l_ear)
diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm
index f1a0fd2e260..5e067d85560 100644
--- a/code/game/jobs/job/silicon.dm
+++ b/code/game/jobs/job/silicon.dm
@@ -8,7 +8,7 @@
selection_color = "#ccffcc"
supervisors = "your laws"
req_admin_notify = 1
- minimal_player_age = 30
+ minimal_player_age = 7
equip(var/mob/living/carbon/human/H)
if(!H) return 0
@@ -25,7 +25,7 @@
spawn_positions = 2
supervisors = "your laws and the AI" //Nodrak
selection_color = "#ddffdd"
- minimal_player_age = 21
+ minimal_player_age = 1
alt_titles = list("Android", "Robot")
equip(var/mob/living/carbon/human/H)
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index 4b2fb50c54e..bd44ba4e7d2 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -250,6 +250,9 @@
dat += text("Paralysis Summary %: [] ([] seconds left!)
", occupant.paralysis, round(occupant.paralysis / 4))
dat += text("Body Temperature: [occupant.bodytemperature-T0C]°C ([occupant.bodytemperature*1.8-459.67]°F)
")
+ if(occupant.has_brain_worms())
+ dat += "Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended.
"
+
if(occupant.vessel)
var/blood_volume = round(occupant.vessel.get_reagent_amount("blood"))
var/blood_percent = blood_volume / 560
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 1d5f210dd33..d8b85211501 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -255,6 +255,8 @@ Release Pressure: - Consciousness slowly creeps over you as your body regenerates.
So this is what cloning feels like?"
// -- Mode/mind specific stuff goes here
@@ -180,24 +198,24 @@
// -- End mode specific stuff
- if(!H.dna)
+ if(!R.dna)
H.dna = new /datum/dna()
H.dna.real_name = H.real_name
- if(ui)
- H.dna.uni_identity = ui
- updateappearance(H, ui)
- if(se)
- H.dna.struc_enzymes = se
- randmutb(H) //Sometimes the clones come out wrong.
+ else
+ H.dna=R.dna
+ H.UpdateAppearance()
+ randmutb(H) //Sometimes the clones come out wrong.
+ H.dna.UpdateSE()
+ H.dna.UpdateUI()
H.f_style = "Shaved"
- if(mrace.name == "Human") //no more xenos losing ears/tentacles
+ if(R.dna.species == "Human") //no more xenos losing ears/tentacles
H.h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3")
- H.species = mrace
- for(var/datum/language/L in languages)
- H.add_language(L.name)
- H.update_mutantrace()
+ H.set_species(R.dna.species)
+
+ //for(var/datum/language/L in languages)
+ // H.add_language(L.name)
H.suiciding = 0
src.attempting = 0
return 1
diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm
index f9d765de6a5..bdd313853f3 100644
--- a/code/game/machinery/computer/HolodeckControl.dm
+++ b/code/game/machinery/computer/HolodeckControl.dm
@@ -532,6 +532,12 @@
w_class = 2
playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
user << "\blue [src] can now be concealed."
+
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
add_fingerprint(user)
return
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 184cc8e8670..293046b0768 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -10,7 +10,7 @@
var/scantemp = "Scanner unoccupied"
var/menu = 1 //Which menu screen to display
var/list/records = list()
- var/datum/data/record/active_record = null
+ var/datum/dna2/record/active_record = null
var/obj/item/weapon/disk/data/diskette = null //Mostly so the geneticist can steal everything.
var/loading = 0 // Nice loading text
@@ -136,8 +136,8 @@
if(2)
dat += "Current records
"
dat += "Back
"
- for(var/datum/data/record/R in src.records)
- dat += "[R.fields["id"]]-[R.fields["name"]]
"
+ for(var/datum/dna2/record/R in src.records)
+ dat += "[R.dna.real_name]"
if(3)
dat += "Selected Record
"
@@ -146,10 +146,11 @@
if (!src.active_record)
dat += "ERROR: Record not found."
else
- dat += "
Delete Record
"
- dat += "Name: [src.active_record.fields["name"]]
"
-
- var/obj/item/weapon/implant/health/H = locate(src.active_record.fields["imp"])
+ dat += {"
Delete Record
+ Name: [src.active_record.dna.real_name]
"}
+ var/obj/item/weapon/implant/health/H = null
+ if(src.active_record.implant)
+ H=locate(src.active_record.implant)
if ((H) && (istype(H)))
dat += "Health: [H.sensehealth()] | OXY-BURN-TOX-BRUTE
"
@@ -166,13 +167,13 @@
else
dat += "
" //Keeping a line empty for appearances I guess.
- dat += {"UI: [src.active_record.fields["UI"]]
- SE: [src.active_record.fields["SE"]]
"}
+ dat += {"UI: [src.active_record.dna.uni_identity]
+ SE: [src.active_record.dna.struc_enzymes]
"}
if(pod1 && pod1.biomass >= CLONE_BIOMASS)
dat += {"Clone
"}
else
- dat += {"Unsufficient biomass
"}
+ dat += {"Insufficient biomass
"}
if(4)
if (!src.active_record)
@@ -217,8 +218,8 @@
else if (href_list["view_rec"])
src.active_record = locate(href_list["view_rec"])
- if(istype(src.active_record,/datum/data/record))
- if ((isnull(src.active_record.fields["ckey"])) || (src.active_record.fields["ckey"] == ""))
+ if(istype(src.active_record,/datum/dna2/record))
+ if ((isnull(src.active_record.ckey)))
del(src.active_record)
src.temp = "ERROR: Record Corrupt"
else
@@ -248,7 +249,7 @@
else if (href_list["disk"]) //Load or eject.
switch(href_list["disk"])
if("load")
- if ((isnull(src.diskette)) || (src.diskette.data == ""))
+ if ((isnull(src.diskette)) || isnull(src.diskette.buf))
src.temp = "Load error."
src.updateUsrDialog()
return
@@ -258,12 +259,7 @@
src.updateUsrDialog()
return
- if (src.diskette.data_type == "ui")
- src.active_record.fields["UI"] = src.diskette.data
- if (src.diskette.ue)
- src.active_record.fields["name"] = src.diskette.owner
- else if (src.diskette.data_type == "se")
- src.active_record.fields["SE"] = src.diskette.data
+ src.active_record = src.diskette.buf
src.temp = "Load successful."
if("eject")
@@ -277,28 +273,24 @@
src.updateUsrDialog()
return
+ // DNA2 makes things a little simpler.
+ src.diskette.buf=src.active_record
+ src.diskette.buf.types=0
switch(href_list["save_disk"]) //Save as Ui/Ui+Ue/Se
if("ui")
- src.diskette.data = src.active_record.fields["UI"]
- src.diskette.ue = 0
- src.diskette.data_type = "ui"
+ src.diskette.buf.types=DNA2_BUF_UI
if("ue")
- src.diskette.data = src.active_record.fields["UI"]
- src.diskette.ue = 1
- src.diskette.data_type = "ui"
+ src.diskette.buf.types=DNA2_BUF_UI|DNA2_BUF_UE
if("se")
- src.diskette.data = src.active_record.fields["SE"]
- src.diskette.ue = 0
- src.diskette.data_type = "se"
- src.diskette.owner = src.active_record.fields["name"]
- src.diskette.name = "data disk - '[src.diskette.owner]'"
+ src.diskette.buf.types=DNA2_BUF_SE
+ src.diskette.name = "data disk - '[src.active_record.dna.real_name]'"
src.temp = "Save \[[href_list["save_disk"]]\] successful."
else if (href_list["refresh"])
src.updateUsrDialog()
else if (href_list["clone"])
- var/datum/data/record/C = locate(href_list["clone"])
+ var/datum/dna2/record/C = locate(href_list["clone"])
//Look for that player! They better be dead!
if(istype(C))
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
@@ -313,17 +305,17 @@
else if(!config.revival_cloning)
temp = "Error: Unable to initiate cloning cycle."
- else if(pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["languages"]))
+ else if(pod1.growclone(C))
temp = "Initiating cloning cycle..."
records.Remove(C)
del(C)
menu = 1
else
- var/mob/selected = find_dead_player("[C.fields["ckey"]]")
+ var/mob/selected = find_dead_player("[C.ckey]")
selected << 'sound/machines/chime.ogg' //probably not the best sound but I think it's reasonable
var/answer = alert(selected,"Do you want to return to life?","Cloning","Yes","No")
- if(answer != "No" && pod1.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["mrace"], C.fields["languages"], C.fields["interface"]))
+ if(answer != "No" && pod1.growclone(C))
temp = "Initiating cloning cycle..."
records.Remove(C)
del(C)
@@ -363,27 +355,25 @@
subject.dna.check_integrity()
- var/datum/data/record/R = new /datum/data/record( )
- R.fields["mrace"] = subject.species
- R.fields["ckey"] = subject.ckey
- R.fields["name"] = subject.real_name
- R.fields["id"] = copytext(md5(subject.real_name), 2, 6)
- R.fields["UI"] = subject.dna.uni_identity
- R.fields["SE"] = subject.dna.struc_enzymes
- R.fields["languages"] = subject.languages
+ var/datum/dna2/record/R = new /datum/dna2/record()
+ R.dna=subject.dna
+ R.ckey = subject.ckey
+ R.id= copytext(md5(subject.real_name), 2, 6)
+ R.name=R.dna.real_name
+ R.types=DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
//Add an implant if needed
var/obj/item/weapon/implant/health/imp = locate(/obj/item/weapon/implant/health, subject)
if (isnull(imp))
imp = new /obj/item/weapon/implant/health(subject)
imp.implanted = subject
- R.fields["imp"] = "\ref[imp]"
+ R.implant = "\ref[imp]"
//Update it if needed
else
- R.fields["imp"] = "\ref[imp]"
+ R.implant = "\ref[imp]"
if (!isnull(subject.mind)) //Save that mind so traitors can continue traitoring after cloning.
- R.fields["mind"] = "\ref[subject.mind]"
+ R.mind = "\ref[subject.mind]"
src.records += R
scantemp = "Subject successfully scanned."
@@ -391,8 +381,8 @@
//Find a specific record by key.
/obj/machinery/computer/cloning/proc/find_record(var/find_key)
var/selected_record = null
- for(var/datum/data/record/R in src.records)
- if (R.fields["ckey"] == find_key)
+ for(var/datum/dna2/record/R in src.records)
+ if (R.ckey == find_key)
selected_record = R
break
return selected_record
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index ed164896369..71a545cd556 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -443,7 +443,6 @@
//Sender isn't faking as someone who exists
if(isnull(PDARec))
src.linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]")
- customrecepient.tnote += "← From [customsender] ([customjob]):
[custommessage]
"
if (!customrecepient.silent)
playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, customrecepient.loc))
@@ -456,8 +455,13 @@
customrecepient.overlays += image('icons/obj/pda.dmi', "pda-r")
//Sender is faking as someone who exists
else
+
src.linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]")
- customrecepient.tnote += "← From [PDARec.owner] ([customjob]):
[custommessage]
"
+ customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]")))
+
+ if(!customrecepient.conversations.Find("\ref[PDARec]"))
+ customrecepient.conversations.Add("\ref[PDARec]")
+
if (!customrecepient.silent)
playsound(customrecepient.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, customrecepient.loc))
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 073c1b8fe40..6c6fc53f61a 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -5,7 +5,7 @@
density = 1
anchored = 1.0
layer = 2.8
-
+
var/on = 0
var/temperature_archived
var/mob/living/carbon/occupant = null
@@ -68,7 +68,7 @@
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
- * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
+ * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
*
* @return nothing
@@ -79,7 +79,7 @@
return
// this is the data which will be sent to the ui
- var/data[0]
+ var/data[0]
data["isOperating"] = on
data["hasOccupant"] = occupant ? 1 : 0
@@ -115,7 +115,7 @@
else if(air_contents.temperature > 225)
data["cellTemperatureStatus"] = "average"
- data["isBeakerLoaded"] = beaker ? 1 : 0
+ data["isBeakerLoaded"] = beaker ? 1 : 0
/* // Removing beaker contents list from front-end, replacing with a total remaining volume
var beakerContents[0]
if(beaker && beaker.reagents && beaker.reagents.reagent_list.len)
@@ -130,12 +130,12 @@
if (beaker.reagents && beaker.reagents.reagent_list.len)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
data["beakerVolume"] += R.volume
-
+
if (!ui) // no ui has been passed, so we'll search for one
{
ui = nanomanager.get_open_ui(user, src, ui_key)
- }
- if (!ui)
+ }
+ if (!ui)
// the ui does not exist, so we'll create a new one
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 410)
// When the UI is first opened this is the data it will use
@@ -159,7 +159,7 @@
if(href_list["switchOn"])
on = 1
update_icon()
-
+
if(href_list["switchOff"])
on = 0
update_icon()
@@ -168,12 +168,12 @@
if(beaker)
beaker.loc = get_step(loc, SOUTH)
beaker = null
-
+
if(href_list["ejectOccupant"])
if(!occupant || isslime(usr) || ispAI(usr))
return 0 // don't update UIs attached to this object
go_out()
-
+
add_fingerprint(usr)
return 1 // update UIs attached to this object
@@ -268,15 +268,15 @@
occupant.client.eye = occupant.client.mob
occupant.client.perspective = MOB_PERSPECTIVE
occupant.loc = get_step(loc, SOUTH) //this doesn't account for walls or anything, but i don't forsee that being a problem.
- if (occupant.bodytemperature < 261 && occupant.bodytemperature > 140) //Patch by Aranclanos to stop people from taking burn damage after being ejected
- occupant.bodytemperature = 261
+ if (occupant.bodytemperature < 261 && occupant.bodytemperature >= 70) //Patch by Aranclanos to stop people from taking burn damage after being ejected
+ occupant.bodytemperature = 261 // Changed to 70 from 140 by Zuhayr due to reoccurance of bug.
// occupant.metabslow = 0
occupant = null
update_icon()
return
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob)
if (!istype(M))
- usr << "\red The cryo cell cannot handle such liveform!"
+ usr << "\red The cryo cell cannot handle such a lifeform!"
return
if (occupant)
usr << "\red The cryo cell is already occupied!"
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
new file mode 100644
index 00000000000..605b575bd98
--- /dev/null
+++ b/code/game/machinery/cryopod.dm
@@ -0,0 +1,388 @@
+/*
+ * Cryogenic refrigeration unit. Basically a despawner.
+ * Stealing a lot of concepts/code from sleepers due to massive laziness.
+ * The despawn tick will only fire if it's been more than time_till_despawned ticks
+ * since time_entered, which is world.time when the occupant moves in.
+ * ~ Zuhayr
+ */
+
+//Used for logging people entering cryosleep and important items they are carrying.
+var/global/list/frozen_crew = list()
+var/global/list/frozen_items = list()
+
+//Main cryopod console.
+
+/obj/machinery/computer/cryopod
+ name = "cryogenic oversight console"
+ desc = "An interface between crew and the cryogenic storage oversight systems."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "cellconsole"
+ circuit = "/obj/item/weapon/circuitboard/cryopodcontrol"
+ var/mode = null
+
+/obj/machinery/computer/cryopod/attack_paw()
+ src.attack_hand()
+
+/obj/machinery/computer/cryopod/attack_ai()
+ src.attack_hand()
+
+obj/machinery/computer/cryopod/attack_hand(mob/user = usr)
+ if(stat & (NOPOWER|BROKEN))
+ return
+
+ user.set_machine(src)
+ src.add_fingerprint(usr)
+
+ var/dat
+
+ if (!( ticker ))
+ return
+
+ dat += "
Cryogenic Oversight Control
"
+ dat += "Welcome, [user.real_name].
"
+ dat += "View storage log.
"
+ dat += "Recover object.
"
+ dat += "Recover all objects.
"
+ dat += "Revive crew.
"
+
+ user << browse(dat, "window=cryopod_console")
+ onclose(user, "cryopod_console")
+
+obj/machinery/computer/cryopod/Topic(href, href_list)
+
+ if(..())
+ return
+
+ var/mob/user = usr
+
+ src.add_fingerprint(user)
+
+ if(href_list["log"])
+
+ var/dat = "Recently stored crewmembers
"
+ for(var/person in frozen_crew)
+ dat += "[person]
"
+ dat += "
"
+
+ user << browse(dat, "window=cryolog")
+
+ else if(href_list["item"])
+
+ if(frozen_items.len == 0)
+ user << "\blue There is nothing to recover from storage."
+ return
+
+ var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as obj in frozen_items
+
+ if(!I || frozen_items.len == 0)
+ user << "\blue There is nothing to recover from storage."
+ return
+
+ visible_message("\blue The console beeps happily as it disgorges \the [I].", 3)
+
+ I.loc = get_turf(src)
+ frozen_items -= I
+
+ else if(href_list["allitems"])
+
+ if(frozen_items.len == 0)
+ user << "\blue There is nothing to recover from storage."
+ return
+
+ visible_message("\blue The console beeps happily as it disgorges the desired objects.", 3)
+
+ for(var/obj/item/I in frozen_items)
+ I.loc = get_turf(src)
+ frozen_items -= I
+
+ else if(href_list["crew"])
+
+ user << "\red Functionality unavailable at this time."
+
+ src.updateUsrDialog()
+ return
+
+/obj/item/weapon/circuitboard/cryopodcontrol
+ name = "Circuit board (Cryogenic Oversight Console)"
+ build_path = "/obj/machinery/computer/cryopod"
+ origin_tech = "programming=3"
+
+//Decorative structures to go alongside cryopods.
+/obj/structure/cryofeed
+
+ name = "\improper cryogenic feed"
+ desc = "A bewildering tangle of machinery and pipes."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "cryo_rear"
+ anchored = 1
+
+ var/orient_right = null //Flips the sprite.
+
+/obj/structure/cryofeed/right
+ orient_right = 1
+ icon_state = "cryo_rear-r"
+
+/obj/structure/cryofeed/New()
+
+ if(orient_right)
+ icon_state = "cryo_rear-r"
+ else
+ icon_state = "cryo_rear"
+ ..()
+
+//Cryopods themselves.
+/obj/machinery/cryopod
+ name = "\improper cryogenic freezer"
+ desc = "A man-sized pod for entering suspended animation."
+ icon = 'icons/obj/Cryogenic2.dmi'
+ icon_state = "body_scanner_0"
+ density = 1
+ anchored = 1
+
+ var/mob/occupant = null // Person waiting to be despawned.
+ var/orient_right = null // Flips the sprite.
+ var/time_till_despawn = 9000 // 15 minutes-ish safe period before being despawned.
+ var/time_entered = 0 // Used to keep track of the safe period.
+ var/obj/item/device/radio/intercom/announce //
+
+ // These items are preserved when the process() despawn proc occurs.
+ var/list/preserve_items = list(
+ /obj/item/weapon/hand_tele,
+ /obj/item/weapon/card/id/captains_spare,
+ /obj/item/device/aicard,
+ /obj/item/device/mmi,
+ /obj/item/device/paicard,
+ /obj/item/weapon/gun,
+ /obj/item/weapon/pinpointer,
+ /obj/item/clothing/suit,
+ /obj/item/clothing/shoes/magboots,
+ /obj/item/blueprints,
+ /obj/item/clothing/head/helmet/space/
+ )
+
+/obj/machinery/cryopod/right
+ orient_right = 1
+ icon_state = "body_scanner_0-r"
+
+/obj/machinery/cryopod/New()
+
+ announce = new /obj/item/device/radio/intercom(src)
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+ ..()
+
+//Lifted from Unity stasis.dm and refactored. ~Zuhayr
+/obj/machinery/cryopod/process()
+ if(occupant)
+
+ //Allow a ten minute gap between entering the pod and actually despawning.
+ if(world.time - time_entered < time_till_despawn)
+ return
+
+ if(!occupant.client && occupant.stat<2) //Occupant is living and has no client.
+
+ //Delete all items not on the preservation list and drop all others into the pod.
+ for(var/obj/item/W in occupant)
+ occupant.drop_from_inventory(W)
+ W.loc = src
+
+ var/preserve = null
+ for(var/T in preserve_items)
+ if(istype(W,T))
+ preserve = 1
+ break
+
+ if(!preserve)
+ del(W)
+ else
+ frozen_items += W
+
+ var/job = occupant.mind.assigned_role
+ var/role = occupant.mind.special_role
+
+ job_master.FreeRole(job)
+
+ if(role == "traitor" || role == "MODE")
+ del(occupant.mind.objectives)
+ occupant.mind.special_role = null
+ else
+ if(ticker.mode.name == "AutoTraitor")
+ var/datum/game_mode/traitor/autotraitor/current_mode = ticker.mode
+ current_mode.possible_traitors.Remove(occupant)
+
+ // Delete them from datacore.
+ for(var/datum/data/record/R in data_core.medical)
+ if ((R.fields["name"] == occupant.real_name))
+ del(R)
+ for(var/datum/data/record/T in data_core.security)
+ if ((T.fields["name"] == occupant.real_name))
+ del(T)
+ for(var/datum/data/record/G in data_core.general)
+ if ((G.fields["name"] == occupant.real_name))
+ del(G)
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+
+ //TODO: Check objectives/mode, update new targets if this mob is the target, spawn new antags?
+
+ //This should guarantee that ghosts don't spawn.
+ occupant.ckey = null
+
+ //Make an announcement and log the person entering storage.
+ frozen_crew += "[occupant.real_name]"
+
+ announce.autosay("[occupant.real_name] has entered long-term storage.", "Cryogenic Oversight")
+ visible_message("\blue The crypod hums and hisses as it moves [occupant.real_name] into storage.", 3)
+
+ // Delete the mob.
+ del(occupant)
+ occupant = null
+
+
+ return
+
+
+/obj/machinery/cryopod/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob)
+
+ if(istype(G, /obj/item/weapon/grab))
+
+ if(occupant)
+ user << "\blue The cryo pod is in use."
+ return
+
+ if(!ismob(G:affecting))
+ return
+
+ var/willing = null //We don't want to allow people to be forced into despawning.
+ var/mob/M = G:affecting
+
+ if(M.client)
+ if(alert(M,"Would you like to enter cryosleep?",,"Yes","No") == "Yes")
+ if(!M || !G || !G:affecting) return
+ willing = 1
+ else
+ willing = 1
+
+ if(willing)
+
+ visible_message("[user] starts putting [G:affecting:name] into the cryo pod.", 3)
+
+ if(do_after(user, 20))
+ if(!M || !G || !G:affecting) return
+
+ M.loc = src
+
+ if(M.client)
+ M.client.perspective = EYE_PERSPECTIVE
+ M.client.eye = src
+
+ if(orient_right)
+ icon_state = "body_scanner_1-r"
+ else
+ icon_state = "body_scanner_1"
+
+ M << "\blue You feel cool air surround you. You go numb as your senses turn inward."
+ M << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round."
+ occupant = M
+ time_entered = world.time
+
+ // Book keeping!
+ log_admin("[key_name_admin(M)] has entered a stasis pod.")
+ message_admins("\blue [key_name_admin(M)] has entered a stasis pod.")
+
+ //Despawning occurs when process() is called with an occupant without a client.
+ src.add_fingerprint(M)
+
+/obj/machinery/cryopod/verb/eject()
+ set name = "Eject Pod"
+ set category = "Object"
+ set src in oview(1)
+ if(usr.stat != 0)
+ return
+
+ if(orient_right)
+ icon_state = "body_scanner0-r"
+ else
+ icon_state = "body_scanner0"
+
+ src.go_out()
+ add_fingerprint(usr)
+ return
+
+/obj/machinery/cryopod/verb/move_inside()
+ set name = "Enter Pod"
+ set category = "Object"
+ set src in oview(1)
+
+ if(usr.stat != 0 || !(ishuman(usr) || ismonkey(usr)))
+ return
+
+ if(src.occupant)
+ usr << "\blue The cryo pod is in use."
+ return
+
+ for(var/mob/living/carbon/slime/M in range(1,usr))
+ if(M.Victim == usr)
+ usr << "You're too busy getting your life sucked out of you."
+ return
+
+ visible_message("[usr] starts climbing into the cryo pod.", 3)
+
+ if(do_after(usr, 20))
+
+ if(!usr || !usr.client)
+ return
+
+ if(src.occupant)
+ usr << "\blue The cryo pod is in use."
+ return
+
+ usr.stop_pulling()
+ usr.client.perspective = EYE_PERSPECTIVE
+ usr.client.eye = src
+ usr.loc = src
+ src.occupant = usr
+
+ if(orient_right)
+ icon_state = "body_scanner_1-r"
+ else
+ icon_state = "body_scanner_1"
+
+ usr << "\blue You feel cool air surround you. You go numb as your senses turn inward."
+ usr << "\blue If you ghost, log out or close your client now, your character will shortly be permanently removed from the round."
+ occupant = usr
+ time_entered = world.time
+
+ src.add_fingerprint(usr)
+
+ return
+
+/obj/machinery/cryopod/proc/go_out()
+
+ if(!occupant)
+ return
+
+ if(occupant.client)
+ occupant.client.eye = src.occupant.client.mob
+ occupant.client.perspective = MOB_PERSPECTIVE
+
+ occupant.loc = get_turf(src)
+ occupant = null
+
+ if(orient_right)
+ icon_state = "body_scanner_0-r"
+ else
+ icon_state = "body_scanner_0"
+
+ return
+
+
+//Attacks/effects.
+/obj/machinery/cryopod/blob_act()
+ return //Sorta gamey, but we don't really want these to be destroyed.
\ No newline at end of file
diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm
index d90986a5dda..155f6c64815 100644
--- a/code/game/machinery/telecomms/broadcaster.dm
+++ b/code/game/machinery/telecomms/broadcaster.dm
@@ -333,19 +333,19 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept
freq_text = "#unkn"
if(COMM_FREQ)
freq_text = "Command"
- if(1351)
+ if(SCI_FREQ)
freq_text = "Science"
- if(1355)
+ if(MED_FREQ)
freq_text = "Medical"
- if(1357)
+ if(ENG_FREQ)
freq_text = "Engineering"
- if(1359)
+ if(SEC_FREQ)
freq_text = "Security"
- if(1347)
+ if(SUP_FREQ)
freq_text = "Supply"
- if(1441)
+ if(1341)
freq_text = "Special Ops"
- if(1443)
+ if(1345)
freq_text = "Response Team"
//There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO
diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm
index 914bd8c9016..83f3a532b7f 100644
--- a/code/game/machinery/telecomms/presets.dm
+++ b/code/game/machinery/telecomms/presets.dm
@@ -43,6 +43,13 @@
"supply", "common", "command", "engineering", "security",
"receiverA", "receiverB", "broadcasterA", "broadcasterB")
+/obj/machinery/telecomms/hub/preset_cent
+ id = "CentComm Hub"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("hub_cent", "c_relay", "s_relay", "m_relay", "r_relay",
+ "centcomm", "receiverCent", "broadcasterCent")
+
//Receivers
//--PRESET LEFT--//
@@ -68,6 +75,13 @@
freq_listening |= i
..()
+/obj/machinery/telecomms/receiver/preset_cent
+ id = "CentComm Receiver"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("receiverCent")
+ freq_listening = list(1345, 1341)
+
//Buses
@@ -100,6 +114,13 @@
freq_listening |= i
..()
+/obj/machinery/telecomms/bus/preset_cent
+ id = "CentComm Bus"
+ network = "tcommsat"
+ freq_listening = list(1345, 1341)
+ heatgen = 0
+ autolinkers = list("processorCent", "centcomm")
+
//Processors
/obj/machinery/telecomms/processor/preset_one
@@ -122,6 +143,12 @@
network = "tcommsat"
autolinkers = list("processor4")
+/obj/machinery/telecomms/processor/preset_cent
+ id = "CentComm Processor"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("processorCent")
+
//Servers
/obj/machinery/telecomms/server/presets
@@ -170,6 +197,12 @@
freq_listening = list(1359)
autolinkers = list("security")
+/obj/machinery/telecomms/server/presets/centcomm
+ id = "CentComm Server"
+ freq_listening = list(1345, 1341)
+ heatgen = 0
+ autolinkers = list("centcomm")
+
//Broadcasters
@@ -186,3 +219,9 @@
id = "Broadcaster B"
network = "tcommsat"
autolinkers = list("broadcasterB")
+
+/obj/machinery/telecomms/broadcaster/preset_cent
+ id = "CentComm Broadcaster"
+ network = "tcommsat"
+ heatgen = 0
+ autolinkers = list("broadcasterCent")
\ No newline at end of file
diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm
index 008b5d819ab..5c188802e3e 100644
--- a/code/game/mecha/medical/odysseus.dm
+++ b/code/game/mecha/medical/odysseus.dm
@@ -108,6 +108,13 @@
holder.icon_state = "hudxeno"
else if(foundVirus)
holder.icon_state = "hudill"
+ else if(patient.has_brain_worms())
+ var/mob/living/simple_animal/borer/B = patient.has_brain_worms()
+ if(B.controlling)
+ holder.icon_state = "hudbrainworm"
+ else
+ holder.icon_state = "hudhealthy"
else
holder.icon_state = "hudhealthy"
+
C.images += holder
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index 4f472f864ff..d5f8dd59aca 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -64,6 +64,22 @@
icon = I
amount = 0
+/obj/effect/decal/cleanable/blood/attack_hand(mob/living/carbon/human/user)
+ ..()
+ if (amount && istype(user))
+ add_fingerprint(user)
+ if (user.gloves)
+ return
+ var/taken = rand(1,amount)
+ amount -= taken
+ user << "You get some blood on your hands."
+ if (!user.blood_DNA)
+ user.blood_DNA = list()
+ user.blood_DNA |= blood_DNA.Copy()
+ user.bloody_hands += taken
+ user.update_inv_gloves(1)
+ user.verbs += /mob/living/carbon/human/proc/bloody_doodle
+
/obj/effect/decal/cleanable/blood/splatter
random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
amount = 2
@@ -91,6 +107,24 @@
icon_state = "1"
amount = 0
+/obj/effect/decal/cleanable/blood/writing
+ icon_state = "tracks"
+ desc = "It looks like a writing in blood."
+ gender = NEUTER
+ random_icon_states = list("writing1","writing2","writing3","writing4","writing5")
+ amount = 0
+ var/message
+
+/obj/effect/decal/cleanable/blood/writing/New()
+ ..()
+ for(var/obj/effect/decal/cleanable/blood/writing/W in loc)
+ random_icon_states.Remove(W.icon_state)
+ icon_state = pick(random_icon_states)
+
+/obj/effect/decal/cleanable/blood/writing/examine()
+ ..()
+ usr << "It reads: \"[message]\""
+
/obj/effect/decal/cleanable/blood/gibs
name = "gibs"
desc = "They look bloody and gruesome."
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 16e5ef3a9ab..7fac6fb7e3a 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -589,4 +589,17 @@
//not sure if this is worth it. It attaches the blood_overlay to every item of the same type if they don't have one already made.
for(var/obj/item/A in world)
if(A.type == type && !A.blood_overlay)
- A.blood_overlay = I
\ No newline at end of file
+ A.blood_overlay = I
+
+/obj/item/proc/showoff(mob/user)
+ for (var/mob/M in view(user))
+ M.show_message("[user] holds up [src]. Take a closer look.",1)
+
+/mob/living/carbon/verb/showoff()
+ set name = "Show Held Item"
+ set category = "Object"
+
+ var/obj/item/I = get_active_hand()
+ if(I && !I.abstract)
+ I.showoff(src)
+
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 9123617f2a7..4631577172e 100755
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -26,7 +26,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
var/f_lum = 2 //Luminosity for the flashlight function
var/silent = 0 //To beep or not to beep, that is the question
var/toff = 0 //If 1, messenger disabled
- var/tnote = null //Current Texts
+ var/tnote[0] //Current Texts
var/last_text //No text spamming
var/last_honk //Also no honk spamming that's bad too
var/ttone = "beep" //The ringtone!
@@ -38,7 +38,10 @@ var/global/list/obj/item/device/pda/PDAs = list()
var/cart = "" //A place to stick cartridge menu information
var/detonate = 1 // Can the PDA be blown up?
var/hidden = 0 // Is the PDA hidden from the PDA list?
-
+ var/active_conversation = null // New variable that allows us to only view a single conversation.
+ var/list/conversations = list() // For keeping up with who we have PDA messsages from.
+ var/newmessage = 0 //To remove hackish overlay check
+
var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both.
var/ownjob = null //related to above
@@ -243,7 +246,13 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(usr.stat == 2)
usr << "You can't do that because you are dead!"
return
- var/HTML = "AI PDA Message Log[tnote]"
+ var/HTML = "AI PDA Message Log"
+ for(var/index in tnote)
+ if(index["sent"])
+ HTML += addtext("→ To ", index["owner"],":
", index["message"], "
")
+ else
+ HTML += addtext("← From ", index["owner"],":
", index["message"], "
")
+ HTML +=""
usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0")
@@ -310,6 +319,172 @@ var/global/list/obj/item/device/pda/PDAs = list()
return attack_self(M)
return
+
+
+
+/* Notes for those wanting to modify this code or even understand it.
+ There are two modes: New UI and a UI already existing.
+ If the UI is new, you define your variables, if the ui already exists if it didn't have variables in data for what you want to add
+ then it won't add it even if you make a data["blahblah"] for it. That's the reason for the = null all over the place, so that.
+ ui.push_data(data) proc has to have the var structure already setup otherwise it can't push the update.
+
+ The exception to the "YOU HAVE TO DEFINE IT" rule is cartridges, we later force
+ the ui to close if a cartridge is inserted so that never will be a problem.
+ So there will never be a time a UI creation causes that to be a problem.
+*/
+
+/obj/item/device/pda/ui_interact(mob/user, ui_key = "main")
+ var/title = "Personal Data Assistant"
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+
+ var/data[0] // This is the data that will be sent to the PDA
+
+
+ data["owner"] = owner // Who is your daddy...
+ data["ownjob"] = ownjob // ...and what does he do?
+
+ data["mode"] = mode // The current view
+ data["scanmode"] = scanmode // Scanners
+ data["fon"] = fon // Flashlight on?
+ data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted?
+ data["note"] = note // current pda notes
+ data["silent"] = silent // does the pda make noise when it receives a message?
+ data["toff"] = toff // is the messenger function turned off?
+ data["active_conversation"] = active_conversation // Which conversation are we following right now?
+
+
+ data["idInserted"] = (id ? 1 : 0)
+ data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------")
+
+
+ if(cartridge)
+ var/cartdata[0]
+
+
+ data["records"] = cartridge.create_NanoUI_values()
+
+
+ cartdata["name"] = cartridge.name
+ cartdata["access"] = list(\
+ "access_security" = cartridge.access_security,\
+ "access_engine" = cartridge.access_engine,\
+ "access_atmos" = cartridge.access_atmos,\
+ "access_medical" = cartridge.access_medical,\
+ "access_clown" = cartridge.access_clown,\
+ "access_mime" = cartridge.access_mime,\
+ "access_janitor" = cartridge.access_janitor,\
+ "access_quartermaster" = cartridge.access_quartermaster,\
+ "access_hydroponics" = cartridge.access_hydroponics,\
+ "access_reagent_scanner" = cartridge.access_reagent_scanner,\
+ "access_remote_door" = cartridge.access_remote_door,\
+ "access_status_display" = cartridge.access_status_display\
+ )
+ if(isnull(cartridge.radio))
+ cartdata["radio"] = 0
+ else
+ if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky))
+ cartdata["radio"] = 1
+ if(istype(cartridge.radio, /obj/item/radio/integrated/signal))
+ cartdata["radio"] = 2
+ if(istype(cartridge.radio, /obj/item/radio/integrated/mule))
+ cartdata["radio"] = 3
+
+ cartdata["type"] = cartridge.type
+ cartdata["charges"] = cartridge.charges ? cartridge.charges : 0
+ data["cartridge"] = cartdata
+
+
+
+
+
+ data["stationTime"] = worldtime2text()
+ data["newMessage"] = newmessage
+
+
+
+ var/convopdas[0]
+ var/pdas[0]
+ var/count = 0
+ for (var/obj/item/device/pda/P in sortAtom(PDAs))
+ if (!P.owner||P.toff||P == src||P.hidden) continue
+ if(conversations.Find("\ref[P]"))
+ convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1")))
+ else
+ pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0")))
+ count++
+ data["convopdas"] = convopdas
+ data["pdas"] = pdas
+ data["pda_count"] = count
+ data["messagescount"] = tnote.len
+ data["messages"] = tnote
+ var/found = 0
+ if(active_conversation)
+ for(var/c in tnote)
+ if(c["target"] == active_conversation)
+ data["convo_name"] = c["owner"]
+ data["convo_job"] = c["job"]
+ found = 1
+ break
+ if(!found)
+ data["convo_name"] = null
+ data["convo_job"] = null
+
+ if(!ui || mode==41)
+ data["manifest"] = data_core.get_manifest_json()
+
+
+ if(!ui || mode==3)
+ var/turf/T = get_turf_or_move(user.loc)
+ if(!isnull(T))
+ var/datum/gas_mixture/environment = T.return_air()
+
+ var/pressure = environment.return_pressure()
+ var/total_moles = environment.total_moles()
+
+ if (total_moles)
+ var/o2_level = environment.oxygen/total_moles
+ var/n2_level = environment.nitrogen/total_moles
+ var/co2_level = environment.carbon_dioxide/total_moles
+ var/plasma_level = environment.toxins/total_moles
+ var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level)
+ data["aircontents"] = list(\
+ "pressure" = "[round(pressure,0.1)]",\
+ "nitrogen" = "[round(n2_level*100,0.1)]",\
+ "oxygen" = "[round(o2_level*100,0.1)]",\
+ "carbon_dioxide" = "[round(co2_level*100,0.1)]",\
+ "plasma" = "[round(plasma_level*100,0.01)]",\
+ "other" = "[round(unknown_level, 0.01)]",\
+ "temp" = "[round(environment.temperature-T0C,0.1)]",\
+ "reading" = 1\
+ )
+ if(isnull(data["aircontents"]))
+ data["aircontents"] = list(\
+ "pressure" = null,\
+ "nitrogen" = null,\
+ "oxygen" = null,\
+ "carbon_dioxide" = null,\
+ "plasma" = null,\
+ "other" = null,\
+ "temp" = null,\
+ "reading" = 0\
+ )
+
+
+
+
+ if (!ui)
+ // the ui does not exist, so we'll create a new one
+ ui = new(user, src, ui_key, "pda.tmpl", title, 630, 600)
+ // When the UI is first opened this is the data it will use
+ ui.set_initial_data(data)
+ ui.open()
+ else
+ // The UI is already open so push the new data to it
+ ui.push_data(data)
+ return
+
+
+
//NOTE: graphic resources are loaded on client login
/obj/item/device/pda/attack_self(mob/user as mob)
@@ -318,203 +493,21 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(active_uplink_check(user))
return
- var/dat = "Personal Data Assistant"
-
- dat += "
Close"
-
- if ((!isnull(cartridge)) && (mode == 0))
- dat += " |
Eject [cartridge]"
- if (mode)
- dat += " |
Return"
- dat += " |
Refresh"
-
- dat += "
"
-
- if (!owner)
- dat += "Warning: No owner information entered. Please swipe card.
"
- dat += "
Retry"
- else
- switch (mode)
- if (0)
- dat += "PERSONAL DATA ASSISTANT v.1.2
"
- dat += "Owner: [owner], [ownjob]
"
- dat += text("ID: [id ? "[id.registered_name], [id.assignment]" : "----------"]")
- dat += text("
[id ? "Update PDA Info" : ""]
")
-
- dat += "Station Time: [worldtime2text()]"//:[world.time / 100 % 6][world.time / 100 % 10]"
-
- dat += "
"
-
- dat += "General Functions
"
- dat += ""
- if (cartridge.access_engine)
- dat += "Engineering Functions
"
- dat += ""
- if (cartridge.access_medical)
- dat += "Medical Functions
"
- dat += ""
- if (cartridge.access_security)
- dat += "Security Functions
"
- dat += ""
- else dat += ""
- if(cartridge.access_quartermaster)
- dat += "Quartermaster Functions:
"
- dat += ""
- dat += ""
-
- dat += "Utilities
"
- dat += ""
-
- if (1)
- dat += "
Notekeeper V2.1
"
- dat += " Edit
"
- dat += note
-
- if (2)
- dat += "
SpaceMessenger V3.9.4
"
- dat += "
Ringer: [silent == 1 ? "Off" : "On"] | "
- dat += "
Send / Receive: [toff == 1 ? "Off" : "On"] | "
- dat += "
Set Ringtone | "
- dat += "
Messages
"
-
- if (istype(cartridge, /obj/item/weapon/cartridge/syndicate))
- dat += "[cartridge:shock_charges] detonation charges left.
"
- if (istype(cartridge, /obj/item/weapon/cartridge/clown))
- dat += "[cartridge:honk_charges] viral files left.
"
- if (istype(cartridge, /obj/item/weapon/cartridge/mime))
- dat += "[cartridge:mime_charges] viral files left.
"
-
- dat += "
Detected PDAs
"
-
- dat += ""
-
- var/count = 0
-
- if (!toff)
- for (var/obj/item/device/pda/P in sortAtom(PDAs))
- if (!P.owner||P.toff||P == src||P.hidden) continue
- dat += "- [P]"
- if (istype(cartridge, /obj/item/weapon/cartridge/syndicate) && P.detonate)
- dat += " (
*Detonate*)"
- if (istype(cartridge, /obj/item/weapon/cartridge/clown))
- dat += " (
*Send Virus*)"
- if (istype(cartridge, /obj/item/weapon/cartridge/mime))
- dat += " (*Send Virus*)"
- dat += " "
- count++
- dat += "
"
- if (count == 0)
- dat += "None detected.
"
-
- if(21)
- dat += "
SpaceMessenger V3.9.4
"
- dat += "
Clear Messages"
-
- dat += "
Messages
"
-
- dat += tnote
- dat += "
"
-
- if (3)
- dat += "
Atmospheric Readings
"
-
- var/turf/T = get_turf_or_move(user.loc)
- if (isnull(T))
- dat += "Unable to obtain a reading.
"
- else
- var/datum/gas_mixture/environment = T.return_air()
-
- var/pressure = environment.return_pressure()
- var/total_moles = environment.total_moles()
-
- dat += "Air Pressure: [round(pressure,0.1)] kPa
"
-
- if (total_moles)
- var/o2_level = environment.oxygen/total_moles
- var/n2_level = environment.nitrogen/total_moles
- var/co2_level = environment.carbon_dioxide/total_moles
- var/plasma_level = environment.toxins/total_moles
- var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level)
- dat += "Nitrogen: [round(n2_level*100)]%
"
- dat += "Oxygen: [round(o2_level*100)]%
"
- dat += "Carbon Dioxide: [round(co2_level*100)]%
"
- dat += "Plasma: [round(plasma_level*100)]%
"
- if(unknown_level > 0.01)
- dat += "OTHER: [round(unknown_level)]%
"
- dat += "Temperature: [round(environment.temperature-T0C)]°C
"
- dat += "
"
-
- if (5)
- dat += "
Nanotrasen Relay Chat
"
-
- dat += "
Detected Channels
: "
- for(var/datum/chatroom/C in chatrooms)
- dat += "#[html_encode(lowertext(C.name))]"
- if(C.password != "")
- dat += "
"
- dat += ""
-
- if (41) //crew manifest
- dat += "
Crew Manifest
"
- dat += "Entries cannot be modified from this terminal.
"
- if(data_core)
- dat += data_core.get_manifest(1) // make it monochrome
- dat += "
"
-
- else//Else it links to the cart menu proc. Although, it really uses menu hub 4--menu 4 doesn't really exist as it simply redirects to hub.
- dat += cart
-
- dat += ""
- user << browse(dat, "window=pda;size=400x444;border=1;can_resize=1;can_close=0;can_minimize=0")
- onclose(user, "pda", src)
+ ui_interact(user) //NanoUI requires this proc
+ return
/obj/item/device/pda/Topic(href, href_list)
+ if(href_list["cartmenu"] && !isnull(cartridge))
+ cartridge.Topic(href, href_list)
+ return 1
+ if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio))
+ cartridge.radio.Topic(href, href_list)
+ return 1
+
+
..()
+ var/mob/user = usr
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
var/mob/living/U = usr
//Looking for master was kind of pointless since PDAs don't appear to have one.
//if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) )
@@ -531,7 +524,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if("Close")//Self explanatory
U.unset_machine()
- U << browse(null, "window=pda")
+ ui.close()
return
if("Refresh")//Refresh, goes to the end of the proc.
if("Return")//Return
@@ -539,11 +532,12 @@ var/global/list/obj/item/device/pda/PDAs = list()
mode = 0
else
mode = round(mode/10)
+ if(mode==2)
+ active_conversation = null
if(mode==4)//Fix for cartridges. Redirects to hub.
mode = 0
else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu.
cartridge.mode = mode
- cartridge.unlock()
if ("Authenticate")//Checks for ID
id_check(U, 1)
if("UpdateInfo")
@@ -555,6 +549,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(ismob(T))
T = T.loc
cartridge.loc = T
+ ui.close()
+ mode = 0
scanmode = 0
if (cartridge.radio)
cartridge.radio.hostpda = null
@@ -626,57 +622,80 @@ var/global/list/obj/item/device/pda/PDAs = list()
note = replacetext(n, "\n", "
")
notehtml = n
else
- U << browse(null, "window=pda")
- return
+ ui.close()
if("Toggle Messenger")
toff = !toff
if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status
silent = !silent
if("Clear")//Clears messages
- tnote = null
+ if(href_list["option"] == "All")
+ tnote.Cut()
+ conversations.Cut()
+ if(href_list["option"] == "Convo")
+ var/new_tnote[0]
+ for(var/i in tnote)
+ if(i["target"] != active_conversation)
+ new_tnote[++new_tnote.len] = i
+ tnote = new_tnote
+ conversations.Remove(active_conversation)
+
+ active_conversation = null
+ if(mode==21)
+ mode=2
+
if("Ringtone")
var/t = input(U, "Please enter new ringtone", name, ttone) as text
if (in_range(src, U) && loc == U)
if (t)
if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code)))
U << "The PDA softly beeps."
- U << browse(null, "window=pda")
+ ui.close()
else
t = copytext(sanitize(t), 1, 20)
ttone = t
else
- U << browse(null, "window=pda")
+ ui.close()
return
if("Message")
+
var/obj/item/device/pda/P = locate(href_list["target"])
src.create_message(U, P)
+ if(mode == 2)
+ active_conversation = href_list["target"]
+ mode = 21
+ if("Select Conversation")
+ var/P = href_list["convo"]
+ for(var/n in conversations)
+ if(P == n)
+ active_conversation=P
+ mode=21
if("Send Honk")//Honk virus
if(istype(cartridge, /obj/item/weapon/cartridge/clown))//Cartridge checks are kind of unnecessary since everything is done through switch.
var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess.
if(!isnull(P))
- if (!P.toff && cartridge:honk_charges > 0)
- cartridge:honk_charges--
+ if (!P.toff && cartridge.charges > 0)
+ cartridge.charges--
U.show_message("\blue Virus sent!", 1)
P.honkamt = (rand(15,20))
else
U << "PDA not found."
else
- U << browse(null, "window=pda")
+ ui.close()
return
if("Send Silence")//Silent virus
if(istype(cartridge, /obj/item/weapon/cartridge/mime))
var/obj/item/device/pda/P = locate(href_list["target"])
if(!isnull(P))
- if (!P.toff && cartridge:mime_charges > 0)
- cartridge:mime_charges--
+ if (!P.toff && cartridge.charges > 0)
+ cartridge.charges--
U.show_message("\blue Virus sent!", 1)
P.silent = 1
P.ttone = "silence"
else
U << "PDA not found."
else
- U << browse(null, "window=pda")
+ ui.close()
return
@@ -695,8 +714,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(istype(cartridge, /obj/item/weapon/cartridge/syndicate))
var/obj/item/device/pda/P = locate(href_list["target"])
if(!isnull(P))
- if (!P.toff && cartridge:shock_charges > 0)
- cartridge:shock_charges--
+ if (!P.toff && cartridge.charges > 0)
+ cartridge.charges--
var/difficulty = 0
@@ -713,7 +732,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
U.show_message("\red An error flashes on your [src].", 1)
else if (prob(difficulty * 3))
U.show_message("\red Energy feeds back into your [src]!", 1)
- U << browse(null, "window=pda")
+ ui.close()
explode()
log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up")
message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up", 1)
@@ -726,7 +745,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
U << "PDA not found."
else
U.unset_machine()
- U << browse(null, "window=pda")
+ ui.close()
return
//pAI FUNCTIONS===================================
@@ -738,33 +757,31 @@ var/global/list/obj/item/device/pda/PDAs = list()
var/turf/T = get_turf_or_move(src.loc)
if(T)
pai.loc = T
+ pai = null
-//LINK FUNCTIONS===================================
-
- else//Cartridge menu linking
+ else
mode = text2num(href_list["choice"])
- cartridge.mode = mode
- cartridge.unlock()
+ if(cartridge)
+ cartridge.mode = mode
+
+
else//If not in range or not using the pda.
U.unset_machine()
- U << browse(null, "window=pda")
+ ui.close()
return
//EXTRA FUNCTIONS===================================
if (mode == 2||mode == 21)//To clear message overlays.
overlays.Cut()
+ newmessage = 0
if ((honkamt > 0) && (prob(60)))//For clown virus.
honkamt--
playsound(loc, 'sound/items/bikehorn.ogg', 30, 1)
- if(U.machine == src && href_list["skiprefresh"]!="1")//Final safety.
- attack_self(U)//It auto-closes the menu prior if the user is not in range and so on.
- else
- U.unset_machine()
- U << browse(null, "window=pda")
- return
+ src.updateUsrDialog()
+ return 1 // return 1 tells it to refresh the UI in NanoUI
/obj/item/device/pda/proc/remove_id()
if (id)
@@ -793,7 +810,7 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(!can_use())
return
-
+
last_text = world.time
// check if telecomms I/O route 1459 is stable
//var/telecomms_intact = telecomms_process(P.owner, owner, t)
@@ -823,19 +840,24 @@ var/global/list/obj/item/device/pda/PDAs = list()
U << "ERROR: Cannot reach recepient."
return
useMS.send_pda_message("[P.owner]","[owner]","[t]")
+ tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]")))
+ P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]")))
+ if(!conversations.Find("\ref[P]"))
+ conversations.Add("\ref[P]")
+ if(!P.conversations.Find("\ref[src]"))
+ P.conversations.Add("\ref[src]")
- tnote += "→ To [P.owner]:
[t]
"
- P.tnote += "← From [owner] ([ownjob]):
[t]
"
if (prob(15)) //Give the AI a chance of intercepting the message
var/who = src.owner
if(prob(50))
- who = P:owner
+ who = P.owner
for(var/mob/living/silicon/ai/ai in mob_list)
// Allows other AIs to intercept the message but the AI won't intercept their own message.
if(ai.aiPDA != P && ai.aiPDA != src)
ai.show_message("Intercepted message from [who]: [t]")
+
if (!P.silent)
playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1)
for (var/mob/O in hearers(3, P.loc))
@@ -848,12 +870,14 @@ var/global/list/obj/item/device/pda/PDAs = list()
else
L = get(P, /mob/living/silicon)
+
if(L)
L << "\icon[P] Message from [src.owner] ([ownjob]), \"[t]\" (Reply)"
log_pda("[usr] (PDA: [src.name]) sent \"[t]\" to [P.name]")
P.overlays.Cut()
P.overlays += image('icons/obj/pda.dmi', "pda-r")
+ P.newmessage = 1
else
U << "ERROR: Messaging server is not responding."
@@ -923,12 +947,15 @@ var/global/list/obj/item/device/pda/PDAs = list()
/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob)
..()
if(istype(C, /obj/item/weapon/cartridge) && !cartridge)
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
cartridge = C
user.drop_item()
cartridge.loc = src
user << "You insert [cartridge] into [src]."
if(cartridge.radio)
cartridge.radio.hostpda = src
+ if(ui)
+ ui.close()
else if(istype(C, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/idcard = C
@@ -1132,8 +1159,8 @@ var/global/list/obj/item/device/pda/PDAs = list()
return
if ((istype(M, /mob/living/carbon/human) && (M.real_name != src.owner) && (istype(src.cartridge, /obj/item/weapon/cartridge/clown))))
- if (src.cartridge:honk_charges < 5)
- src.cartridge:honk_charges++
+ if (src.cartridge.charges < 5)
+ src.cartridge.charges++
M.stop_pulling()
M << "\blue You slipped on the PDA!"
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
index f0e3ee98f17..02dbf86b921 100644
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ b/code/game/objects/items/devices/PDA/cart.dm
@@ -21,6 +21,7 @@
var/access_status_display = 0
var/access_quartermaster = 0
var/access_hydroponics = 0
+ var/charges = 0
var/mode = null
var/menu
var/datum/data/record/active1 = null //General
@@ -32,575 +33,518 @@
var/message2
var/list/stored_data = list()
- engineering
- name = "Power-ON Cartridge"
- icon_state = "cart-e"
- access_engine = 1
+/obj/item/weapon/cartridge/engineering
+ name = "Power-ON Cartridge"
+ icon_state = "cart-e"
+ access_engine = 1
- atmos
- name = "BreatheDeep Cartridge"
- icon_state = "cart-a"
- access_atmos = 1
+/obj/item/weapon/cartridge/atmos
+ name = "BreatheDeep Cartridge"
+ icon_state = "cart-a"
+ access_atmos = 1
- medical
- name = "Med-U Cartridge"
- icon_state = "cart-m"
- access_medical = 1
+/obj/item/weapon/cartridge/medical
+ name = "Med-U Cartridge"
+ icon_state = "cart-m"
+ access_medical = 1
- chemistry
- name = "ChemWhiz Cartridge"
- icon_state = "cart-chem"
- access_reagent_scanner = 1
+/obj/item/weapon/cartridge/chemistry
+ name = "ChemWhiz Cartridge"
+ icon_state = "cart-chem"
+ access_reagent_scanner = 1
- security
- name = "R.O.B.U.S.T. Cartridge"
- icon_state = "cart-s"
- access_security = 1
+/obj/item/weapon/cartridge/security
+ name = "R.O.B.U.S.T. Cartridge"
+ icon_state = "cart-s"
+ access_security = 1
- New()
- ..()
- spawn(5)
- radio = new /obj/item/radio/integrated/beepsky(src)
+/obj/item/weapon/cartridge/security/New()
+ ..()
+ spawn(5)
+ radio = new /obj/item/radio/integrated/beepsky(src)
- detective
- name = "D.E.T.E.C.T. Cartridge"
- icon_state = "cart-s"
- access_security = 1
- access_medical = 1
+/obj/item/weapon/cartridge/detective
+ name = "D.E.T.E.C.T. Cartridge"
+ icon_state = "cart-s"
+ access_security = 1
+ access_medical = 1
- janitor
- name = "CustodiPRO Cartridge"
- desc = "The ultimate in clean-room design."
- icon_state = "cart-j"
- access_janitor = 1
+/obj/item/weapon/cartridge/janitor
+ name = "CustodiPRO Cartridge"
+ desc = "The ultimate in clean-room design."
+ icon_state = "cart-j"
+ access_janitor = 1
- lawyer
- name = "P.R.O.V.E. Cartridge"
- icon_state = "cart-s"
- access_security = 1
+/obj/item/weapon/cartridge/lawyer
+ name = "P.R.O.V.E. Cartridge"
+ icon_state = "cart-s"
+ access_security = 1
- clown
- name = "Honkworks 5.0"
- icon_state = "cart-clown"
- access_clown = 1
- var/honk_charges = 5
+/obj/item/weapon/cartridge/clown
+ name = "Honkworks 5.0"
+ icon_state = "cart-clown"
+ access_clown = 1
+ charges = 5
- mime
- name = "Gestur-O 1000"
- icon_state = "cart-mi"
- access_mime = 1
- var/mime_charges = 5
+/obj/item/weapon/cartridge/mime
+ name = "Gestur-O 1000"
+ icon_state = "cart-mi"
+ access_mime = 1
+ charges = 5
/*
- botanist
- name = "Green Thumb v4.20"
- icon_state = "cart-b"
- access_flora = 1
+/obj/item/weapon/cartridge/botanist
+ name = "Green Thumb v4.20"
+ icon_state = "cart-b"
+ access_flora = 1
*/
- signal
- name = "generic signaler cartridge"
- desc = "A data cartridge with an integrated radio signaler module."
-
- toxins
- name = "Signal Ace 2"
- desc = "Complete with integrated radio signaler!"
- icon_state = "cart-tox"
- access_reagent_scanner = 1
- access_atmos = 1
-
- New()
- ..()
- spawn(5)
- radio = new /obj/item/radio/integrated/signal(src)
-
-
-
- quartermaster
- name = "Space Parts & Space Vendors Cartridge"
- desc = "Perfect for the Quartermaster on the go!"
- icon_state = "cart-q"
- access_quartermaster = 1
-
- New()
- ..()
- spawn(5)
- radio = new /obj/item/radio/integrated/mule(src)
-
- head
- name = "Easy-Record DELUXE"
- icon_state = "cart-h"
- access_status_display = 1
-
- hop
- name = "HumanResources9001"
- icon_state = "cart-h"
- access_status_display = 1
- access_quartermaster = 1
- access_janitor = 1
- access_security = 1
-
- New()
- ..()
- spawn(5)
- radio = new /obj/item/radio/integrated/mule(src)
-
- hos
- name = "R.O.B.U.S.T. DELUXE"
- icon_state = "cart-hos"
- access_status_display = 1
- access_security = 1
-
- New()
- ..()
- spawn(5)
- radio = new /obj/item/radio/integrated/beepsky(src)
-
- ce
- name = "Power-On DELUXE"
- icon_state = "cart-ce"
- access_status_display = 1
- access_engine = 1
- access_atmos = 1
-
- cmo
- name = "Med-U DELUXE"
- icon_state = "cart-cmo"
- access_status_display = 1
- access_reagent_scanner = 1
- access_medical = 1
-
- rd
- name = "Signal Ace DELUXE"
- icon_state = "cart-rd"
- access_status_display = 1
- access_reagent_scanner = 1
- access_atmos = 1
-
- New()
- ..()
- spawn(5)
- radio = new /obj/item/radio/integrated/signal(src)
-
- captain
- name = "Value-PAK Cartridge"
- desc = "Now with 200% more value!"
- icon_state = "cart-c"
- access_engine = 1
- access_security = 1
- access_medical = 1
- access_reagent_scanner = 1
- access_status_display = 1
- access_atmos = 1
-
- syndicate
- name = "Detomatix Cartridge"
- icon_state = "cart"
- access_remote_door = 1
- remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
- var/shock_charges = 4
-
- proc/unlock()
- if (!istype(loc, /obj/item/device/pda))
- return
-
- generate_menu()
- print_to_host(menu)
- return
-
- proc/print_to_host(var/text)
- if (!istype(loc, /obj/item/device/pda))
- return
- loc:cart = text
-
- for (var/mob/M in viewers(1, loc.loc))
- if (M.client && M.machine == loc)
- loc:attack_self(M)
-
- return
-
- proc/post_status(var/command, var/data1, var/data2)
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
-
- if(!frequency) return
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = 1
- status_signal.data["command"] = command
-
- switch(command)
- if("message")
- status_signal.data["msg1"] = data1
- status_signal.data["msg2"] = data2
- if(loc)
- var/obj/item/PDA = loc
- var/mob/user = PDA.fingerprintslast
- if(istype(PDA.loc,/mob/living))
- name = PDA.loc
- log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
- message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
-
- if("alert")
- status_signal.data["picture_state"] = data1
-
- frequency.post_signal(src, status_signal)
-
- proc/generate_menu()
- switch(mode)
- if(40) //signaller
- menu = "
Remote Signaling System
"
-
- menu += {"
-Send Signal
-Frequency:
--
--
-[format_frequency(radio:frequency)]
-+
-+
-
-Code:
--
--
-[radio:code]
-+
-+
"}
-
- if (42) //status displays
- menu = "
Station Status Display Interlink
"
-
- menu += "\[ Clear \]
"
- menu += "\[ Shuttle ETA \]
"
- menu += "\[ Message \]"
- menu += "
"
- menu += "\[ Alert: None |"
- menu += " Red Alert |"
- menu += " Lockdown |"
- menu += " Biohazard \]
"
-
- if (43) //Muskets' and Rockdtben's power monitor :D
- menu = "
Power Monitors - Please select one
"
- powmonitor = null
- powermonitors = list()
- var/powercount = 0
-
-
-
- for(var/obj/machinery/power/monitor/pMon in world)
- if(!(pMon.stat & (NOPOWER|BROKEN)) )
- powercount++
- powermonitors += pMon
-
-
- if(!powercount)
- menu += "\red No connection
"
- else
-
- menu += ""
- var/count = 0
- for(var/obj/machinery/power/monitor/pMon in powermonitors)
- count++
- menu += " [pMon]
"
-
- menu += ""
-
- if (433) //Muskets' and Rockdtben's power monitor :D
- menu = "
Power Monitor
"
- if(!powmonitor)
- menu += "\red No connection
"
- else
- var/list/L = list()
- for(var/obj/machinery/power/terminal/term in powmonitor.powernet.nodes)
- if(istype(term.master, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = term.master
- L += A
-
- menu += "Total power: [powmonitor.powernet.avail] W
Total load: [num2text(powmonitor.powernet.viewload,10)] W
"
-
- menu += ""
-
- if(L.len > 0)
- menu += "Area Eqp./Lgt./Env. Load Cell
"
-
- var/list/S = list(" Off","AOff"," On", " AOn")
- var/list/chg = list("N","C","F")
-
- for(var/obj/machinery/power/apc/A in L)
- menu += copytext(add_tspace(A.area.name, 30), 1, 30)
- menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(A.lastused_total, 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]
"
-
- menu += "
"
-
- if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working.
- menu = "
Medical Record List
"
- if(!isnull(data_core.general))
- for (var/datum/data/record/R in sortRecord(data_core.general))
- menu += "[R.fields["id"]]: [R.fields["name"]]
"
- menu += "
"
- if(441)
- menu = "
Medical Record
"
-
- if (istype(active1, /datum/data/record) && (active1 in data_core.general))
- menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
"
- menu += "Sex: [active1.fields["sex"]]
"
- menu += "Age: [active1.fields["age"]]
"
- menu += "Rank: [active1.fields["rank"]]
"
- menu += "Fingerprint: [active1.fields["fingerprint"]]
"
- menu += "Physical Status: [active1.fields["p_stat"]]
"
- menu += "Mental Status: [active1.fields["m_stat"]]
"
- else
- menu += "Record Lost!
"
-
- menu += "
"
-
- menu += "
Medical Data
"
- if (istype(active2, /datum/data/record) && (active2 in data_core.medical))
- menu += "Blood Type: [active2.fields["b_type"]]
"
-
- menu += "Minor Disabilities: [active2.fields["mi_dis"]]
"
- menu += "Details: [active2.fields["mi_dis_d"]]
"
-
- menu += "Major Disabilities: [active2.fields["ma_dis"]]
"
- menu += "Details: [active2.fields["ma_dis_d"]]
"
-
- menu += "Allergies: [active2.fields["alg"]]
"
- menu += "Details: [active2.fields["alg_d"]]
"
-
- menu += "Current Diseases: [active2.fields["cdi"]]
"
- menu += "Details: [active2.fields["cdi_d"]]
"
-
- menu += "Important Notes: [active2.fields["notes"]]
"
- else
- menu += "Record Lost!
"
-
- menu += "
"
- if (45) //security records
- menu = "
Security Record List
"
- if(!isnull(data_core.general))
- for (var/datum/data/record/R in sortRecord(data_core.general))
- menu += "[R.fields["id"]]: [R.fields["name"]]
"
-
- menu += "
"
- if(451)
- menu = "
Security Record
"
-
- if (istype(active1, /datum/data/record) && (active1 in data_core.general))
- menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]
"
- menu += "Sex: [active1.fields["sex"]]
"
- menu += "Age: [active1.fields["age"]]
"
- menu += "Rank: [active1.fields["rank"]]
"
- menu += "Fingerprint: [active1.fields["fingerprint"]]
"
- menu += "Physical Status: [active1.fields["p_stat"]]
"
- menu += "Mental Status: [active1.fields["m_stat"]]
"
- else
- menu += "Record Lost!
"
-
- menu += "
"
-
- menu += "
Security Data
"
- if (istype(active3, /datum/data/record) && (active3 in data_core.security))
- menu += "Criminal Status: [active3.fields["criminal"]]
"
-
- menu += "Minor Crimes: [active3.fields["mi_crim"]]
"
- menu += "Details: [active3.fields["mi_crim"]]
"
-
- menu += "Major Crimes: [active3.fields["ma_crim"]]
"
- menu += "Details: [active3.fields["ma_crim_d"]]
"
-
- menu += "Important Notes:
"
- menu += "[active3.fields["notes"]]"
- else
- menu += "Record Lost!
"
-
- menu += "
"
- if (46) //beepsky control
- var/obj/item/radio/integrated/beepsky/SC = radio
- if(!SC)
- menu = "Interlink Error - Please reinsert cartridge."
- return
-
- menu = "
Securitron Interlink
"
-
- if(!SC.active)
- // list of bots
- if(!SC.botlist || (SC.botlist && SC.botlist.len==0))
- menu += "No bots found.
"
-
- else
- for(var/obj/machinery/bot/B in SC.botlist)
- if (B)
- menu += "[B] at [B.loc.loc]
"
-
- menu += "
Scan for active bots
"
-
- else // bot selected, control it
-
- menu += "[SC.active]
Status: (
refresh)
"
-
- if(!SC.botstatus)
- menu += "Waiting for response...
"
- else
-
- menu += "Location: [SC.botstatus["loca"] ]
"
- menu += "Mode: "
-
- switch(SC.botstatus["mode"])
- if(0)
- menu += "Ready"
- if(1)
- menu += "Apprehending target"
- if(2,3)
- menu += "Arresting target"
- if(4)
- menu += "Starting patrol"
- if(5)
- menu += "On patrol"
- if(6)
- menu += "Responding to summons"
-
- menu += "
\[Stop Patrol\] "
- menu += "\[Start Patrol\] "
- menu += "\[Summon Bot\]
"
- menu += "
Return to bot list"
-
- if (47) //quartermaster order records
- menu = "
Supply Record Interlink
"
-
- menu += "
Supply shuttle
"
- menu += "Location: [supply_shuttle.moving ? "Moving to station ([supply_shuttle.eta] Mins.)":supply_shuttle.at_station ? "Station":"Dock"]
"
- menu += "Current approved orders:
"
- for(var/S in supply_shuttle.shoppinglist)
- var/datum/supply_order/SO = S
- menu += "- #[SO.ordernum] - [SO.object.name] approved by [SO.orderedby] [SO.comment ? "([SO.comment])":""]
"
- menu += "
"
-
- menu += "Current requests:
"
- for(var/S in supply_shuttle.requestlist)
- var/datum/supply_order/SO = S
- menu += "- #[SO.ordernum] - [SO.object.name] requested by [SO.orderedby]
"
- menu += "
Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management."
-
- if (48) //mulebot control
- var/obj/item/radio/integrated/mule/QC = radio
- if(!QC)
- menu = "Interlink Error - Please reinsert cartridge."
- return
-
- menu = "
M.U.L.E. bot Interlink V0.8
"
-
- if(!QC.active)
- // list of bots
- if(!QC.botlist || (QC.botlist && QC.botlist.len==0))
- menu += "No bots found.
"
-
- else
- for(var/obj/machinery/bot/mulebot/B in QC.botlist)
- menu += "[B] at [get_area(B)]
"
- menu += "
Scan for active bots
"
-
- else // bot selected, control it
-
- menu += "[QC.active]
Status: (
refresh)
"
-
- if(!QC.botstatus)
- menu += "Waiting for response...
"
- else
-
- menu += "Location: [QC.botstatus["loca"] ]
"
- menu += "Mode: "
-
- switch(QC.botstatus["mode"])
- if(0)
- menu += "Ready"
- if(1)
- menu += "Loading/Unloading"
- if(2)
- menu += "Navigating to Delivery Location"
- if(3)
- menu += "Navigating to Home"
- if(4)
- menu += "Waiting for clear path"
- if(5,6)
- menu += "Calculating navigation path"
- if(7)
- menu += "Unable to locate destination"
- var/obj/structure/closet/crate/C = QC.botstatus["load"]
- menu += "
Current Load: [ !C ? "none" : "[C.name] (unload)" ]
"
- menu += "Destination: [!QC.botstatus["dest"] ? "none" : QC.botstatus["dest"] ] (set)
"
- menu += "Power: [QC.botstatus["powr"]]%
"
- menu += "Home: [!QC.botstatus["home"] ? "none" : QC.botstatus["home"] ]
"
- menu += "Auto Return Home: [QC.botstatus["retn"] ? "On Off" : "(On) Off"]
"
- menu += "Auto Pickup Crate: [QC.botstatus["pick"] ? "On Off" : "(On) Off"]
"
-
- menu += "\[Stop\] "
- menu += "\[Proceed\] "
- menu += "\[Return Home\]
"
- menu += "
Return to bot list"
-
- if (49) //janitorial locator
- menu = "
Persistent Custodial Object Locator
"
-
- var/turf/cl = get_turf(src)
- if (cl)
- menu += "Current Orbital Location: \[[cl.x],[cl.y]\]"
-
- menu += "Located Mops:
"
-
- var/ldat
- for (var/obj/item/weapon/mop/M in world)
- var/turf/ml = get_turf(M)
-
- if(ml)
- if (ml.z != cl.z)
- continue
- var/direction = get_dir(src, M)
- ldat += "Mop - \[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\] - [M.reagents.total_volume ? "Wet" : "Dry"]
"
-
- if (!ldat)
- menu += "None"
- else
- menu += "[ldat]"
-
- menu += "Located Mop Buckets:
"
-
- ldat = null
- for (var/obj/structure/mopbucket/B in world)
- var/turf/bl = get_turf(B)
-
- if(bl)
- if (bl.z != cl.z)
- continue
- var/direction = get_dir(src, B)
- ldat += "Bucket - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - Water level: [B.reagents.total_volume]/100
"
-
- if (!ldat)
- menu += "None"
- else
- menu += "[ldat]"
-
- menu += "Located Cleanbots:
"
-
- ldat = null
- for (var/obj/machinery/bot/cleanbot/B in world)
- var/turf/bl = get_turf(B)
-
- if(bl)
- if (bl.z != cl.z)
- continue
- var/direction = get_dir(src, B)
- ldat += "Cleanbot - \[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\] - [B.on ? "Online" : "Offline"]
"
-
- if (!ldat)
- menu += "None"
- else
- menu += "[ldat]"
-
- else
- menu += "ERROR: Unable to determine current location."
- menu += "
Refresh GPS Locator"
+/obj/item/weapon/cartridge/signal
+ name = "generic signaler cartridge"
+ desc = "A data cartridge with an integrated radio signaler module."
+
+/obj/item/weapon/cartridge/signal/toxins
+ name = "Signal Ace 2"
+ desc = "Complete with integrated radio signaler!"
+ icon_state = "cart-tox"
+ access_reagent_scanner = 1
+ access_atmos = 1
+
+/obj/item/weapon/cartridge/signal/New()
+ ..()
+ spawn(5)
+ radio = new /obj/item/radio/integrated/signal(src)
+
+
+
+/obj/item/weapon/cartridge/quartermaster
+ name = "Space Parts & Space Vendors Cartridge"
+ desc = "Perfect for the Quartermaster on the go!"
+ icon_state = "cart-q"
+ access_quartermaster = 1
+
+/obj/item/weapon/cartridge/quartermaster/New()
+ ..()
+ spawn(5)
+ radio = new /obj/item/radio/integrated/mule(src)
+
+/obj/item/weapon/cartridge/head
+ name = "Easy-Record DELUXE"
+ icon_state = "cart-h"
+ access_status_display = 1
+
+/obj/item/weapon/cartridge/hop
+ name = "HumanResources9001"
+ icon_state = "cart-h"
+ access_status_display = 1
+ access_quartermaster = 1
+ access_janitor = 1
+ access_security = 1
+
+/obj/item/weapon/cartridge/hop/New()
+ ..()
+ spawn(5)
+ radio = new /obj/item/radio/integrated/mule(src)
+
+/obj/item/weapon/cartridge/hos
+ name = "R.O.B.U.S.T. DELUXE"
+ icon_state = "cart-hos"
+ access_status_display = 1
+ access_security = 1
+
+/obj/item/weapon/cartridge/hos/New()
+ ..()
+ spawn(5)
+ radio = new /obj/item/radio/integrated/beepsky(src)
+
+/obj/item/weapon/cartridge/ce
+ name = "Power-On DELUXE"
+ icon_state = "cart-ce"
+ access_status_display = 1
+ access_engine = 1
+ access_atmos = 1
+
+/obj/item/weapon/cartridge/cmo
+ name = "Med-U DELUXE"
+ icon_state = "cart-cmo"
+ access_status_display = 1
+ access_reagent_scanner = 1
+ access_medical = 1
+
+/obj/item/weapon/cartridge/rd
+ name = "Signal Ace DELUXE"
+ icon_state = "cart-rd"
+ access_status_display = 1
+ access_reagent_scanner = 1
+ access_atmos = 1
+
+/obj/item/weapon/cartridge/rd/New()
+ ..()
+ spawn(5)
+ radio = new /obj/item/radio/integrated/signal(src)
+
+/obj/item/weapon/cartridge/captain
+ name = "Value-PAK Cartridge"
+ desc = "Now with 200% more value!"
+ icon_state = "cart-c"
+ access_quartermaster = 1
+ access_janitor = 1
+ access_engine = 1
+ access_security = 1
+ access_medical = 1
+ access_reagent_scanner = 1
+ access_status_display = 1
+ access_atmos = 1
+
+/obj/item/weapon/cartridge/syndicate
+ name = "Detomatix Cartridge"
+ icon_state = "cart"
+ access_remote_door = 1
+ remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
+ charges = 4
+
+/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2)
+
+ var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
+ if(!frequency) return
+
+ var/datum/signal/status_signal = new
+ status_signal.source = src
+ status_signal.transmission_method = 1
+ status_signal.data["command"] = command
+
+ switch(command)
+ if("message")
+ status_signal.data["msg1"] = data1
+ status_signal.data["msg2"] = data2
+ if(loc)
+ var/obj/item/PDA = loc
+ var/mob/user = PDA.fingerprintslast
+ if(istype(PDA.loc,/mob/living))
+ name = PDA.loc
+ log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
+ message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
+
+ if("alert")
+ status_signal.data["picture_state"] = data1
+
+ frequency.post_signal(src, status_signal)
+
+
+/*
+ This generates the nano values of the cart menus.
+ Because we close the UI when we insert a new cart
+ we don't have to worry about null values on items
+ the user can't access. Well, unless they are href hacking.
+ But in that case their UI will just lock up.
+*/
+
+
+/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob)
+ var/obj/item/device/pda/PDA = loc
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, PDA, "main")
+ var/values[0]
+
+ /* Signaler (Mode: 40) */
+
+
+ if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40 || !ui ))
+ var/obj/item/radio/integrated/signal/R = radio
+ values["signal_freq"] = format_frequency(R.frequency)
+ values["signal_code"] = R.code
+
+
+ /* Station Display (Mode: 42) */
+
+ if(mode==42 || !ui)
+ values["message1"] = message1 ? message1 : "(none)"
+ values["message2"] = message2 ? message2 : "(none)"
+
+
+
+ /* Power Monitor (Mode: 43 / 433) */
+ if(mode==43 || mode==433 || !ui)
+ var/pMonData[0]
+ for(var/obj/machinery/power/monitor/pMon in world)
+ if(!(pMon.stat & (NOPOWER|BROKEN)) )
+ pMonData[++pMonData.len] = list ("Name" = pMon.name, "ref" = "\ref[pMon]")
+ if(isnull(powmonitor)) powmonitor = pMon
+
+ values["powermonitors"] = pMonData
+
+ values["poweravail"] = powmonitor.powernet.avail
+ values["powerload"] = num2text(powmonitor.powernet.viewload,10)
+
+ var/list/L = list()
+ for(var/obj/machinery/power/terminal/term in powmonitor.powernet.nodes)
+ if(istype(term.master, /obj/machinery/power/apc))
+ var/obj/machinery/power/apc/A = term.master
+ L += A
+
+ var/list/Status = list(0,0,1,1) // Status: off, auto-off, on, auto-on
+ var/list/chg = list(0,1,1) // Charging: nope, charging, full
+ var/apcData[0]
+ for(var/obj/machinery/power/apc/A in L)
+ apcData[++apcData.len] = list("Name" = html_encode(A.area.name), "Equipment" = Status[A.equipment+1], "Lights" = Status[A.lighting+1], "Environment" = Status[A.environ+1], "CellPct" = A.cell ? round(A.cell.percent(),1) : -1, "CellStatus" = A.cell ? chg[A.charging+1] : 0)
+
+ values["apcs"] = apcData
+
+
+
+
+
+ /* General Records (Mode: 44 / 441 / 45 / 451) */
+ if(mode == 44 || mode == 441 || mode == 45 || mode ==451 || !ui)
+ if(istype(active1, /datum/data/record) && (active1 in data_core.general))
+ values["general"] = active1.fields
+ values["general_exists"] = 1
+
+ else
+
+ values["general"] = list("name" = null,\
+ "id" = null,\
+ "sex" = null,\
+ "species" = null,\
+ "age" = null,\
+ "rank" = null,\
+ "fingerprint" = null,\
+ "p_stat" = null,\
+ "m_stat" = null,\
+ )
+ values["general_exists"] = 0
+
+
+
+ /* Medical Records (Mode: 44 / 441) */
+
+ if(mode == 44 || mode == 441 || !ui)
+ var/medData[0]
+ for(var/datum/data/record/R in sortRecord(data_core.general))
+ medData[++medData.len] = list(Name = R.fields["name"],"ref" = "\ref[R]")
+ values["medical_records"] = medData
+
+ if(istype(active2, /datum/data/record) && (active2 in data_core.medical))
+ values["medical"] = active2.fields
+ values["medical_exists"] = 1
+ else
+ values["medical"] = list(\
+ "b_type" = null,\
+ "mi_dis" = null,\
+ "mi_dis_d" = null,\
+ "ma_dis" = null,\
+ "ma_dis_d" = null,\
+ "alg" = null,\
+ "alg_d" = null,\
+ "cdi" = null,\
+ "cdi_d" = null,\
+ "notes" = null,\
+ )
+ values["medical_exists"] = 0
+
+ /* Security Records (Mode:45 / 451) */
+
+ if(mode == 45 || mode == 451 || !ui)
+ var/secData[0]
+ for (var/datum/data/record/R in sortRecord(data_core.general))
+ secData[++secData.len] = list(Name = R.fields["name"], "ref" = "\ref[R]")
+ values["security_records"] = secData
+
+ if(istype(active3, /datum/data/record) && (active3 in data_core.security))
+ values["security"] = active3.fields
+ values["security_exists"] = 1
+ else
+ values["security"] = list(\
+ "criminal" = null,\
+ "mi_crim" = null,\
+ "ma_crim" = null,\
+ "ma_crim_d" = null,\
+ "notes"\
+ )
+ values["security_exists"] = 0
+
+ /* Security Bot Control (Mode: 46) */
+
+ if(mode==46 || !ui)
+ var/botsData[0]
+ var/beepskyData[0]
+ if(istype(radio,/obj/item/radio/integrated/beepsky))
+ var/obj/item/radio/integrated/beepsky/SC = radio
+ beepskyData["active"] = SC.active
+ if(SC.active && !isnull(SC.botstatus))
+ var/area/loca = SC.botstatus["loca"]
+ var/loca_name = sanitize(loca.name)
+ beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"])
+ else
+ beepskyData["botstatus"] = list("loca" = null, "mode" = -1)
+ var/botsCount=0
+ if(SC.botlist && SC.botlist.len)
+ for(var/obj/machinery/bot/B in SC.botlist)
+ botsCount++
+ if(B.loc)
+ botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
+
+ if(!botsData.len)
+ botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
+
+ beepskyData["bots"] = botsData
+ beepskyData["count"] = botsCount
+
+ else
+ beepskyData["active"] = 0
+ botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
+ beepskyData["botstatus"] = list("loca" = null, "mode" = null)
+ beepskyData["bots"] = botsData
+ beepskyData["count"] = 0
+
+ values["beepsky"] = beepskyData
+
+
+ /* MULEBOT Control (Mode: 48) */
+
+ if(mode==48 || !ui)
+ var/muleData[0]
+ var/mulebotsData[0]
+ if(istype(radio,/obj/item/radio/integrated/mule))
+ var/obj/item/radio/integrated/mule/QC = radio
+ muleData["active"] = QC.active
+ if(QC.active && !isnull(QC.botstatus))
+ var/area/loca = QC.botstatus["loca"]
+ var/loca_name = sanitize(loca.name)
+ muleData["botstatus"] = list("loca" = loca_name, "mode" = QC.botstatus["mode"],"home"=QC.botstatus["home"],"powr" = QC.botstatus["powr"],"retn" =QC.botstatus["retn"], "pick"=QC.botstatus["pick"], "load" = QC.botstatus["load"], "dest" = sanitize(QC.botstatus["dest"]))
+
+ else
+ muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null)
+
+
+ var/mulebotsCount=0
+ for(var/obj/machinery/bot/B in QC.botlist)
+ mulebotsCount++
+ if(B.loc)
+ mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
+
+ if(!mulebotsData.len)
+ mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
+
+ muleData["bots"] = mulebotsData
+ muleData["count"] = mulebotsCount
+
+ else
+ muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null)
+ muleData["active"] = 0
+ mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
+ muleData["bots"] = mulebotsData
+ muleData["count"] = 0
+
+ values["mulebot"] = muleData
+
+
+
+ /* Supply Shuttle Requests Menu (Mode: 47) */
+
+ if(mode==47 || !ui)
+ var/supplyData[0]
+ supplyData["shuttle_moving"] = supply_shuttle.moving
+ supplyData["shuttle_eta"] = supply_shuttle.eta
+ supplyData["shuttle_loc"] = supply_shuttle.at_station ? "Station" : "Dock"
+ var/supplyOrderCount = 0
+ var/supplyOrderData[0]
+ for(var/S in supply_shuttle.shoppinglist)
+ var/datum/supply_order/SO = S
+
+ supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.orderedby, "Comment" = html_encode(SO.comment))
+ if(!supplyOrderData.len)
+ supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null)
+
+ supplyData["approved"] = supplyOrderData
+ supplyData["approved_count"] = supplyOrderCount
+
+ var/requestCount = 0
+ var/requestData[0]
+ for(var/S in supply_shuttle.requestlist)
+ var/datum/supply_order/SO = S
+ requestCount++
+ requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.orderedby, "Comment" = html_encode(SO.comment))
+ if(!requestData.len)
+ requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null)
+
+ supplyData["requests"] = requestData
+ supplyData["requests_count"] = requestCount
+
+
+ values["supply"] = supplyData
+
+
+
+ /* Janitor Supplies Locator (Mode: 49) */
+ if(mode==49 || !ui)
+ var/JaniData[0]
+ var/turf/cl = get_turf(src)
+
+ if(cl)
+ JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y)
+ else
+ JaniData["user_loc"] = list("x" = 0, "y" = 0)
+ var/MopData[0]
+ for(var/obj/item/weapon/mop/M in world)
+ var/turf/ml = get_turf(M)
+ if(ml)
+ if(ml.z != cl.z)
+ continue
+ var/direction = get_dir(src, M)
+ MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry")
+
+ if(!MopData.len)
+ MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
+
+
+ var/BucketData[0]
+ for(var/obj/structure/mopbucket/B in world)
+ var/turf/bl = get_turf(B)
+ if(bl)
+ if(bl.z != cl.z)
+ continue
+ var/direction = get_dir(src,B)
+ BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100)
+
+ if(!BucketData.len)
+ BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
+
+ var/CbotData[0]
+ for(var/obj/machinery/bot/cleanbot/B in world)
+ var/turf/bl = get_turf(B)
+ if(bl)
+ if(bl.z != cl.z)
+ continue
+ var/direction = get_dir(src,B)
+ CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline")
+
+
+ if(!CbotData.len)
+ CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
+ var/CartData[0]
+ for(var/obj/structure/janitorialcart/B in world)
+ var/turf/bl = get_turf(B)
+ if(bl)
+ if(bl.z != cl.z)
+ continue
+ var/direction = get_dir(src,B)
+ CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100)
+ if(!CartData.len)
+ CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
+
+
+
+
+ JaniData["mops"] = MopData
+ JaniData["buckets"] = BucketData
+ JaniData["cleanbots"] = CbotData
+ JaniData["carts"] = CartData
+ values["janitor"] = JaniData
+
+ return values
+
+
+
/obj/item/weapon/cartridge/Topic(href, href_list)
@@ -611,6 +555,9 @@ Code:
usr << browse(null, "window=pda")
return
+
+
+
switch(href_list["choice"])
if("Medical Records")
var/datum/data/record/R = locate(href_list["target"])
@@ -668,10 +615,9 @@ Code:
else
post_status(href_list["statdisp"])
if("Power Select")
- var/pnum = text2num(href_list["target"])
- powmonitor = powermonitors[pnum]
+ var/pref = href_list["target"]
+ powmonitor = locate(pref)
loc:mode = 433
mode = 433
- generate_menu()
- print_to_host(menu)
+ return 1
diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm
index 45bcff1c052..9dc462814e4 100644
--- a/code/game/objects/items/devices/PDA/radio.dm
+++ b/code/game/objects/items/devices/PDA/radio.dm
@@ -31,15 +31,6 @@
frequency.post_signal(src, signal, filter = s_filter)
- proc/print_to_host(var/text)
- if (isnull(src.hostpda))
- return
- src.hostpda.cart = text
-
- for (var/mob/M in viewers(1, src.hostpda.loc))
- if (M.client && M.machine == src.hostpda)
- src.hostpda.cartridge.unlock()
-
return
proc/generate_menu()
@@ -107,7 +98,6 @@
if("summon")
post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT)
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
- PDA.cartridge.unlock()
/obj/item/radio/integrated/mule
var/list/botlist = null // list of bots
@@ -163,7 +153,6 @@
Topic(href, href_list)
..()
- var/obj/item/device/pda/PDA = src.hostpda
var/cmd = "command"
if(active) cmd = "command [active.suffix]"
@@ -208,7 +197,6 @@
if("stop", "go", "home")
post_signal(control_freq, cmd, href_list["op"], s_filter = RADIO_MULEBOT)
post_signal(control_freq, cmd, "bot_status", s_filter = RADIO_MULEBOT)
- PDA.cartridge.unlock()
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index a5a4093028f..7e616a8f35a 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -143,7 +143,9 @@ REAGENT SCANNER
user.show_message(text("\red Warning: [D.form] Detected\nName: [D.name].\nType: [D.spread].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure]"))
if (M.reagents && M.reagents.get_reagent_amount("inaprovaline"))
user.show_message("\blue Bloodstream Analysis located [M.reagents:get_reagent_amount("inaprovaline")] units of rejuvenation chemicals.")
- if (M.getBrainLoss() >= 100 || istype(M, /mob/living/carbon/human) && M:brain_op_stage == 4.0)
+ if (M.has_brain_worms())
+ user.show_message("\red Subject suffering from aberrant brain activity. Recommend further scanning.")
+ else if (M.getBrainLoss() >= 100 || istype(M, /mob/living/carbon/human) && M:brain_op_stage == 4.0)
user.show_message("\red Subject is brain dead.")
else if (M.getBrainLoss() >= 60)
user.show_message("\red Severe brain damage detected. Subject likely to have mental retardation.")
diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm
index ebe7b751de0..e04ab62671e 100644
--- a/code/game/objects/items/devices/uplinks.dm
+++ b/code/game/objects/items/devices/uplinks.dm
@@ -12,6 +12,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
var/item_data // raw item text
var/list/ItemList // Parsed list of items
var/uses // Numbers of crystals
+ var/nanoui_items[0]
// List of items not to shove in their hands.
var/list/NotInHand = list(/obj/machinery/singularity_beacon/syndicate)
@@ -23,6 +24,39 @@ A list of items and costs is stored under the datum of every game mode, alongsid
items = replacetext(item_data)
ItemList = text2list(src.items, ";") // Parsing the items text string
uses = ticker.mode.uplink_uses
+ nanoui_items = generate_nanoui_items()
+
+/*
+ Built the Items List for use with NanoUI
+*/
+
+/obj/item/device/uplink/proc/generate_nanoui_items()
+ var/items_nano[0]
+ for(var/D in ItemList)
+ var/list/O = stringsplit(D, ":")
+ if(O.len != 3) //If it is not an actual item, make a break in the menu.
+ if(O.len == 1) //If there is one item, it's probably a title
+ items_nano[++items_nano.len] = list("Category" = "[O[1]]", "items" = list())
+ continue
+
+ var/path_text = O[1]
+ var/cost = text2num(O[2])
+
+ var/path_obj = text2path(path_text)
+
+ // Because we're using strings, this comes up if item paths change.
+ // Failure to handle this error borks uplinks entirely. -Sayu
+ if(!path_obj)
+ error("Syndicate item is not a valid path: [path_text]")
+ else
+ var/itemname = O[3]
+ items_nano[items_nano.len]["items"] += list(list("Name" = itemname, "Cost" = cost, "obj_path" = path_text))
+
+ return items_nano
+
+
+
+
//Let's build a menu!
/obj/item/device/uplink/proc/generate_menu()
@@ -230,8 +264,8 @@ A list of items and costs is stored under the datum of every game mode, alongsid
feedback_add_details("traitor_uplink_items_bought","ST")
/obj/item/device/uplink/Topic(href, href_list)
-
if (href_list["buy_item"])
+
if(href_list["buy_item"] == "random")
var/boughtItem = chooseRandomItem()
if(boughtItem)
@@ -299,31 +333,48 @@ A list of items and costs is stored under the datum of every game mode, alongsid
return 1
return 0
-// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button.
-/obj/item/device/uplink/hidden/interact(mob/user as mob)
+/*
+ NANO UI FOR UPLINK WOOP WOOP
+*/
+/obj/item/device/uplink/hidden/ui_interact(mob/user, ui_key = "main")
+ var/title = "Syndicate Uplink"
+ var/data[0]
+
+ data["crystals"] = uses
+ data["nano_items"] = nanoui_items
+ data["welcome"] = welcome
- var/dat = ""
- dat += src.generate_menu()
- dat += "Lock"
- dat += ""
- user << browse(dat, "window=hidden")
- onclose(user, "hidden")
- return
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+ if (!ui)
+ // the ui does not exist, so we'll create a new one
+ ui = new(user, src, ui_key, "uplink.tmpl", title, 450, 600)
+ // When the UI is first opened this is the data it will use
+ ui.set_initial_data(data)
+ ui.open()
+ else
+ // The UI is already open so push the new data to it
+ ui.push_data(data)
+ return
+
+// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button.
+/obj/item/device/uplink/hidden/interact(mob/user)
+
+ ui_interact(user)
// The purchasing code.
/obj/item/device/uplink/hidden/Topic(href, href_list)
-
if (usr.stat || usr.restrained())
return
if (!( istype(usr, /mob/living/carbon/human)))
return 0
-
+ var/mob/user = usr
+ var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, "main")
if ((usr.contents.Find(src.loc) || (in_range(src.loc, usr) && istype(src.loc.loc, /turf))))
usr.set_machine(src)
if(href_list["lock"])
toggle()
- usr << browse(null, "window=hidden")
+ ui.close()
return 1
if(..(href, href_list) == 1)
@@ -334,7 +385,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
A.put_in_any_hand_if_possible(I)
purchase_log += "[usr] ([usr.ckey]) bought [I]."
interact(usr)
- return
+ return 1
// I placed this here because of how relevant it is.
// You place this in your uplinkable item to check if an uplink is active or not.
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 30fcfbdd494..5d5c9415d43 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -285,7 +285,7 @@
playsound(src.loc, 'sound/effects/glass_step.ogg', 50, 1)
if(ishuman(M))
var/mob/living/carbon/human/H = M
- if(!H.shoes && !(H.wear_suit.body_parts_covered & FEET))
+ if( !H.shoes && ( !H.wear_suit || !(H.wear_suit.body_parts_covered & FEET) ) )
var/datum/organ/external/affecting = H.get_organ(pick("l_foot", "r_foot"))
if(affecting.status & ORGAN_ROBOT)
return
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index c4578808cfb..f02824576cb 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -337,6 +337,12 @@
src.icon_state = "sword0"
src.item_state = "sword0"
src.w_class = 2
+
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
src.add_fingerprint(user)
return
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index 12db8fc376c..870b881eda3 100644
--- a/code/game/objects/items/weapons/cards_ids.dm
+++ b/code/game/objects/items/weapons/cards_ids.dm
@@ -203,23 +203,12 @@
/obj/item/weapon/card/id/syndicate/New(mob/user as mob)
..()
- var/t = reject_bad_name(input(user, "What name would you like to put on this card?\nNode: You can change this later by clicking on the ID card while it's in your hand.", "Agent card name", ishuman(user) ? user.real_name : user.name))
- if(!t)
- alert("Invalid name.")
- if(!registered_name)
- registered_name = ishuman(user) ? user.real_name : user.name
+ if(!isnull(user)) // Runtime prevention on laggy starts or where users log out because of lag at round start.
+ registered_name = ishuman(user) ? user.real_name : user.name
else
- registered_name = t
- var/u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Assistant")),1,MAX_MESSAGE_LEN)
- if(!u)
- alert("Invalid assignment.")
- assignment = "Assistant"
- else
- assignment = u
- name = "[registered_name]'s ID Card ([assignment])"
- user << "\blue You successfully forge the ID card."
- registered_user = user
-
+ registered_name = "Agent Card"
+ assignment = "Agent"
+ name = "[registered_name]'s ID Card ([assignment])"
/obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity)
if(!proximity) return
@@ -239,7 +228,7 @@
return
src.registered_name = t
- var u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Assistant")),1,MAX_MESSAGE_LEN)
+ var u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Agent")),1,MAX_MESSAGE_LEN)
if(!u)
alert("Invalid assignment.")
src.registered_name = ""
@@ -250,7 +239,7 @@
registered_user = user
else if(!registered_user || registered_user == user)
- if(!registered_user) registered_user = user // First one to pick it up is the owner if there is ever a wild case New() doens't work.
+ if(!registered_user) registered_user = user //
switch(alert("Would you like to display the ID, or retitle it?","Choose.","Rename","Show"))
if("Rename")
@@ -263,7 +252,6 @@
var u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Assistant")),1,MAX_MESSAGE_LEN)
if(!u)
alert("Invalid assignment.")
- src.registered_name = ""
return
src.assignment = u
src.name = "[src.registered_name]'s ID Card ([src.assignment])"
diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm
index 43e0f8caefb..87720c5f2c7 100644
--- a/code/game/objects/items/weapons/cigs_lighters.dm
+++ b/code/game/objects/items/weapons/cigs_lighters.dm
@@ -157,14 +157,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/turf/location = get_turf(src)
smoketime--
if(smoketime < 1)
- new type_butt(location)
- processing_objects.Remove(src)
- if(ismob(loc))
- var/mob/living/M = loc
- M << "Your [name] goes out."
- M.u_equip(src) //un-equip it so the overlays can update
- M.update_inv_wear_mask(0)
- del(src)
+ die()
return
if(location)
location.hotspot_expose(700, 5)
@@ -182,13 +175,21 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/clothing/mask/cigarette/attack_self(mob/user as mob)
if(lit == 1)
user.visible_message("[user] calmly drops and treads on the lit [src], putting it out instantly.")
- var/turf/T = get_turf(src)
- new type_butt(T)
- processing_objects.Remove(src)
- del(src)
+ die()
return ..()
+/obj/item/clothing/mask/cigarette/proc/die()
+ var/turf/T = get_turf(src)
+ var/obj/item/butt = new type_butt(T)
+ transfer_fingerprints_to(butt)
+ if(ismob(loc))
+ var/mob/living/M = loc
+ M << "Your [name] goes out."
+ M.u_equip(src) //un-equip it so the overlays can update
+ M.update_inv_wear_mask(0)
+ processing_objects.Remove(src)
+ del(src)
////////////
// CIGARS //
@@ -229,6 +230,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
w_class = 1
throwforce = 1
+/obj/item/weapon/cigbutt/New()
+ ..()
+ pixel_x = rand(-10,10)
+ pixel_y = rand(-10,10)
+ transform = turn(transform,rand(0,360))
+
/obj/item/weapon/cigbutt/cigarbutt
name = "cigar butt"
desc = "A manky old cigar butt."
diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm
index 5bf10ccd20e..d0b19f88e93 100644
--- a/code/game/objects/items/weapons/dna_injector.dm
+++ b/code/game/objects/items/weapons/dna_injector.dm
@@ -3,11 +3,8 @@
desc = "This injects the person with DNA."
icon = 'icons/obj/items.dmi'
icon_state = "dnainjector"
- var/dnatype = null
- var/dna = null
- var/block = null
- var/owner = null
- var/ue = null
+ var/block=0
+ var/datum/dna2/record/buf=null
var/s_time = 10.0
throw_speed = 1
throw_range = 5
@@ -17,40 +14,81 @@
var/is_bullet = 0
var/inuse = 0
+ // USE ONLY IN PREMADE SYRINGES. WILL NOT WORK OTHERWISE.
+ var/datatype=0
+ var/value=0
+
+/obj/item/weapon/dnainjector/New()
+ if(datatype && block)
+ buf=new
+ buf.dna=new
+ buf.types = datatype
+ buf.dna.ResetSE()
+ //testing("[name]: DNA2 SE blocks prior to SetValue: [english_list(buf.dna.SE)]")
+ SetValue(src.value)
+ //testing("[name]: DNA2 SE blocks after SetValue: [english_list(buf.dna.SE)]")
+
/obj/item/weapon/dnainjector/attack_paw(mob/user as mob)
return attack_hand(user)
+/obj/item/weapon/dnainjector/proc/GetRealBlock(var/selblock)
+ if(selblock==0)
+ return block
+ else
+ return selblock
+
+/obj/item/weapon/dnainjector/proc/GetState(var/selblock=0)
+ var/real_block=GetRealBlock(selblock)
+ if(buf.types&DNA2_BUF_SE)
+ return buf.dna.GetSEState(real_block)
+ else
+ return buf.dna.GetUIState(real_block)
+
+/obj/item/weapon/dnainjector/proc/SetState(var/on, var/selblock=0)
+ var/real_block=GetRealBlock(selblock)
+ if(buf.types&DNA2_BUF_SE)
+ return buf.dna.SetSEState(real_block,on)
+ else
+ return buf.dna.SetUIState(real_block,on)
+
+/obj/item/weapon/dnainjector/proc/GetValue(var/selblock=0)
+ var/real_block=GetRealBlock(selblock)
+ if(buf.types&DNA2_BUF_SE)
+ return buf.dna.GetSEValue(real_block)
+ else
+ return buf.dna.GetUIValue(real_block)
+
+/obj/item/weapon/dnainjector/proc/SetValue(var/val,var/selblock=0)
+ var/real_block=GetRealBlock(selblock)
+ if(buf.types&DNA2_BUF_SE)
+ return buf.dna.SetSEValue(real_block,val)
+ else
+ return buf.dna.SetUIValue(real_block,val)
/obj/item/weapon/dnainjector/proc/inject(mob/M as mob, mob/user as mob)
if(istype(M,/mob/living))
M.radiation += rand(5,20)
if (!(NOCLONE in M.mutations)) // prevents drained people from having their DNA changed
- if (dnatype == "ui")
+ if (buf.types & DNA2_BUF_UI)
if (!block) //isolated block?
- if (ue) //unique enzymes? yes
- M.dna.uni_identity = dna
- updateappearance(M, M.dna.uni_identity)
- M.real_name = ue
- M.name = ue
- uses--
- else //unique enzymes? no
- M.dna.uni_identity = dna
- updateappearance(M, M.dna.uni_identity)
- uses--
- else
- M.dna.uni_identity = setblock(M.dna.uni_identity,block,dna,3)
- updateappearance(M, M.dna.uni_identity)
- uses--
- if (dnatype == "se")
- if (!block) //isolated block?
- M.dna.struc_enzymes = dna
- domutcheck(M, null)
+ M.UpdateAppearance(buf.dna)
+ if (buf.types & DNA2_BUF_UE) //unique enzymes? yes
+ M.real_name = buf.dna.real_name
+ M.name = buf.dna.real_name
uses--
else
- M.dna.struc_enzymes = setblock(M.dna.struc_enzymes,block,dna,3)
- domutcheck(M, null,1)
+ M.dna.SetUIValue(block,src.GetValue())
+ M.UpdateAppearance()
uses--
+ if (buf.types & DNA2_BUF_SE)
+ if (!block) //isolated block?
+ M.dna.SE = buf.dna.SE
+ M.dna.UpdateSE()
+ else
+ M.dna.SetSEValue(block,src.GetValue())
+ domutcheck(M, null, block!=null)
+ uses--
if(prob(5))
trigger_side_effect(M)
@@ -85,12 +123,24 @@
spawn(50) // Not the best fix. There should be an failure proc, for /effect/equip_e/, which is called when the first initital checks fail
inuse = 0
M.requests += O
- if (dnatype == "se")
- if (isblockon(getblock(dna, 14,3),14) && istype(M, /mob/living/carbon/human))
- msg_admin_attack("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY) (JMP)")
+ if (buf.types & DNA2_BUF_SE)
+ if(block)// Isolated injector
+ testing("Isolated block [block] injector with contents: [GetValue()]")
+ if (GetState() && block == MONKEYBLOCK && istype(M, /mob/living/carbon/human) )
+ message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)")
+ log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name] (MONKEY)")
+ log_game("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)")
+ else
+ log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name]")
else
- // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]")
- log_attack("[key_name(user)] injected [key_name(M)] with the [name]")
+ testing("DNA injector with contents: [english_list(buf.dna.SE)]")
+ if (GetState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human) )
+ message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)")
+ log_attack("[key_name(user)] injected [key_name(M)] with the [name] (MONKEY)")
+ log_game("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)")
+ else
+ // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]")
+ log_attack("[key_name(user)] injected [key_name(M)] with the [name]")
else
// message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]")
log_attack("[key_name(user)] injected [key_name(M)] with the [name]")
@@ -107,13 +157,24 @@
if (!(istype(M, /mob/living/carbon/human) || istype(M, /mob/living/carbon/monkey)))
user << "\red Apparently it didn't work."
return
- if (dnatype == "se")
- if (isblockon(getblock(dna, 14,3),14) && istype(M, /mob/living/carbon/human))
- message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)")
- log_game("[key_name(user)] injected [key_name(M)] with the [name] (MONKEY)")
+
+ if (buf.types & DNA2_BUF_SE)
+ if(block)// Isolated injector
+ testing("Isolated block [block] injector with contents: [GetValue()]")
+ if (GetState() && block == MONKEYBLOCK && istype(M, /mob/living/carbon/human) )
+ message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)")
+ log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name] (MONKEY)")
+ log_game("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] \red(MONKEY)")
+ else
+ log_attack("[key_name(user)] injected [key_name(M)] with the Isolated [name]")
else
-// message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]")
- log_game("[key_name(user)] injected [key_name(M)] with the [name]")
+ testing("DNA injector with contents: [english_list(buf.dna.SE)]")
+ if (GetState(MONKEYBLOCK) && istype(M, /mob/living/carbon/human))
+ message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name] \red(MONKEY)")
+ log_game("[key_name(user)] injected [key_name(M)] with the [name] (MONKEY)")
+ else
+ // message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]")
+ log_game("[key_name(user)] injected [key_name(M)] with the [name]")
else
// message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the [name]")
log_game("[key_name(user)] injected [key_name(M)] with the [name]")
@@ -135,227 +196,465 @@
-/obj/item/weapon/dnainjector/antihulk
- name = "DNA-Injector (Anti-Hulk)"
- desc = "Cures green skin."
- dnatype = "se"
- dna = "708"
- //block = 2
- New()
- ..()
- block = HULKBLOCK
-
/obj/item/weapon/dnainjector/hulkmut
name = "DNA-Injector (Hulk)"
desc = "This will make you big and strong, but give you a bad skin condition."
- dnatype = "se"
- dna = "FED"
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
//block = 2
New()
- ..()
block = HULKBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antihulk
+ name = "DNA-Injector (Anti-Hulk)"
+ desc = "Cures green skin."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = HULKBLOCK
+ ..()
/obj/item/weapon/dnainjector/xraymut
name = "DNA-Injector (Xray)"
desc = "Finally you can see what the Captain does."
- dnatype = "se"
- dna = "FED"
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
//block = 8
New()
- ..()
block = XRAYBLOCK
+ ..()
/obj/item/weapon/dnainjector/antixray
name = "DNA-Injector (Anti-Xray)"
desc = "It will make you see harder."
- dnatype = "se"
- dna = "708"
+ datatype = DNA2_BUF_SE
+ value = 0x001
//block = 8
New()
- ..()
block = XRAYBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/firemut
+ name = "DNA-Injector (Fire)"
+ desc = "Gives you fire."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 10
+ New()
+ block = FIREBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antifire
+ name = "DNA-Injector (Anti-Fire)"
+ desc = "Cures fire."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 10
+ New()
+ block = FIREBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/telemut
+ name = "DNA-Injector (Tele.)"
+ desc = "Super brain man!"
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 12
+ New()
+ block = TELEBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antitele
+ name = "DNA-Injector (Anti-Tele.)"
+ desc = "Will make you not able to control your mind."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 12
+ New()
+ block = TELEBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/nobreath
+ name = "DNA-Injector (No Breath)"
+ desc = "Hold your breath and count to infinity."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = NOBREATHBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antinobreath
+ name = "DNA-Injector (Anti-No Breath)"
+ desc = "Hold your breath and count to 100."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = NOBREATHBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/remoteview
+ name = "DNA-Injector (Remote View)"
+ desc = "Stare into the distance for a reason."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = REMOTEVIEWBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antiremoteview
+ name = "DNA-Injector (Anti-Remote View)"
+ desc = "Cures green skin."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = REMOTEVIEWBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/regenerate
+ name = "DNA-Injector (Regeneration)"
+ desc = "Healthy but hungry."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = REGENERATEBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antiregenerate
+ name = "DNA-Injector (Anti-Regeneration)"
+ desc = "Sickly but sated."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = REGENERATEBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/runfast
+ name = "DNA-Injector (Increase Run)"
+ desc = "Running Man."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = INCREASERUNBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antirunfast
+ name = "DNA-Injector (Anti-Increase Run)"
+ desc = "Walking Man."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = INCREASERUNBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/morph
+ name = "DNA-Injector (Morph)"
+ desc = "A total makeover."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = MORPHBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antimorph
+ name = "DNA-Injector (Anti-Morph)"
+ desc = "Cures identity crisis."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = MORPHBLOCK
+ ..()
+
+/* No COLDBLOCK on bay
+/obj/item/weapon/dnainjector/cold
+ name = "DNA-Injector (Cold)"
+ desc = "Feels a bit chilly."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = COLDBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/anticold
+ name = "DNA-Injector (Anti-Cold)"
+ desc = "Feels room-temperature."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = COLDBLOCK
+ ..()
+*/
+
+/obj/item/weapon/dnainjector/noprints
+ name = "DNA-Injector (No Prints)"
+ desc = "Better than a pair of budget insulated gloves."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = NOPRINTSBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antinoprints
+ name = "DNA-Injector (Anti-No Prints)"
+ desc = "Not quite as good as a pair of budget insulated gloves."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = NOPRINTSBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/insulation
+ name = "DNA-Injector (Shock Immunity)"
+ desc = "Better than a pair of real insulated gloves."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = SHOCKIMMUNITYBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antiinsulation
+ name = "DNA-Injector (Anti-Shock Immunity)"
+ desc = "Not quite as good as a pair of real insulated gloves."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = SHOCKIMMUNITYBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/midgit
+ name = "DNA-Injector (Small Size)"
+ desc = "Makes you shrink."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = SMALLSIZEBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antimidgit
+ name = "DNA-Injector (Anti-Small Size)"
+ desc = "Makes you grow. But not too much."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = SMALLSIZEBLOCK
+ ..()
/////////////////////////////////////
/obj/item/weapon/dnainjector/antiglasses
name = "DNA-Injector (Anti-Glasses)"
desc = "Toss away those glasses!"
- dnatype = "se"
- dna = "708"
- block = 1
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 1
+ New()
+ block = GLASSESBLOCK
+ ..()
/obj/item/weapon/dnainjector/glassesmut
name = "DNA-Injector (Glasses)"
desc = "Will make you need dorkish glasses."
- dnatype = "se"
- dna = "BD6"
- block = 1
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 1
+ New()
+ block = GLASSESBLOCK
+ ..()
/obj/item/weapon/dnainjector/epimut
name = "DNA-Injector (Epi.)"
desc = "Shake shake shake the room!"
- dnatype = "se"
- dna = "FA0"
- block = 3
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 3
+ New()
+ block = HEADACHEBLOCK
+ ..()
/obj/item/weapon/dnainjector/antiepi
name = "DNA-Injector (Anti-Epi.)"
desc = "Will fix you up from shaking the room."
- dnatype = "se"
- dna = "708"
- block = 3
-////////////////////////////////////
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 3
+ New()
+ block = HEADACHEBLOCK
+ ..()
+
/obj/item/weapon/dnainjector/anticough
name = "DNA-Injector (Anti-Cough)"
desc = "Will stop that awful noise."
- dnatype = "se"
- dna = "708"
- block = 5
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 5
+ New()
+ block = COUGHBLOCK
+ ..()
/obj/item/weapon/dnainjector/coughmut
name = "DNA-Injector (Cough)"
desc = "Will bring forth a sound of horror from your throat."
- dnatype = "se"
- dna = "BD6"
- block = 5
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 5
+ New()
+ block = COUGHBLOCK
+ ..()
/obj/item/weapon/dnainjector/clumsymut
name = "DNA-Injector (Clumsy)"
desc = "Makes clumsy minions."
- dnatype = "se"
- dna = "FA0"
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
//block = 6
New()
- ..()
block = CLUMSYBLOCK
+ ..()
/obj/item/weapon/dnainjector/anticlumsy
name = "DNA-Injector (Anti-Clumy)"
desc = "Cleans up confusion."
- dnatype = "se"
- dna = "708"
+ datatype = DNA2_BUF_SE
+ value = 0x001
//block = 6
New()
- ..()
block = CLUMSYBLOCK
+ ..()
/obj/item/weapon/dnainjector/antitour
name = "DNA-Injector (Anti-Tour.)"
desc = "Will cure tourrets."
- dnatype = "se"
- dna = "708"
- block = 7
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 7
+ New()
+ block = TWITCHBLOCK
+ ..()
/obj/item/weapon/dnainjector/tourmut
name = "DNA-Injector (Tour.)"
desc = "Gives you a nasty case off tourrets."
- dnatype = "se"
- dna = "BD6"
- block = 7
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 7
+ New()
+ block = TWITCHBLOCK
+ ..()
/obj/item/weapon/dnainjector/stuttmut
name = "DNA-Injector (Stutt.)"
desc = "Makes you s-s-stuttterrr"
- dnatype = "se"
- dna = "FA0"
- block = 9
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 9
+ New()
+ block = NERVOUSBLOCK
+ ..()
/obj/item/weapon/dnainjector/antistutt
name = "DNA-Injector (Anti-Stutt.)"
desc = "Fixes that speaking impairment."
- dnatype = "se"
- dna = "708"
- block = 9
-
-/obj/item/weapon/dnainjector/antifire
- name = "DNA-Injector (Anti-Fire)"
- desc = "Cures fire."
- dnatype = "se"
- dna = "708"
- //block = 10
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 9
New()
+ block = NERVOUSBLOCK
..()
- block = FIREBLOCK
-
-/obj/item/weapon/dnainjector/firemut
- name = "DNA-Injector (Fire)"
- desc = "Gives you fire."
- dnatype = "se"
- dna = "FED"
- //block = 10
- New()
- ..()
- block = FIREBLOCK
/obj/item/weapon/dnainjector/blindmut
name = "DNA-Injector (Blind)"
desc = "Makes you not see anything."
- dnatype = "se"
- dna = "FA0"
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
//block = 11
New()
- ..()
block = BLINDBLOCK
+ ..()
/obj/item/weapon/dnainjector/antiblind
name = "DNA-Injector (Anti-Blind)"
desc = "ITS A MIRACLE!!!"
- dnatype = "se"
- dna = "708"
+ datatype = DNA2_BUF_SE
+ value = 0x001
//block = 11
New()
- ..()
block = BLINDBLOCK
-
-/obj/item/weapon/dnainjector/antitele
- name = "DNA-Injector (Anti-Tele.)"
- desc = "Will make you not able to control your mind."
- dnatype = "se"
- dna = "708"
- //block = 12
- New()
..()
- block = TELEBLOCK
-
-/obj/item/weapon/dnainjector/telemut
- name = "DNA-Injector (Tele.)"
- desc = "Super brain man!"
- dnatype = "se"
- dna = "FED"
- //block = 12
- New()
- ..()
- block = TELEBLOCK
/obj/item/weapon/dnainjector/deafmut
name = "DNA-Injector (Deaf)"
desc = "Sorry, what did you say?"
- dnatype = "se"
- dna = "FA0"
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
//block = 13
New()
- ..()
block = DEAFBLOCK
+ ..()
/obj/item/weapon/dnainjector/antideaf
name = "DNA-Injector (Anti-Deaf)"
desc = "Will make you hear once more."
- dnatype = "se"
- dna = "708"
+ datatype = DNA2_BUF_SE
+ value = 0x001
//block = 13
New()
- ..()
block = DEAFBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/hallucination
+ name = "DNA-Injector (Halluctination)"
+ desc = "What you see isn't always what you get."
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 2
+ New()
+ block = HALLUCINATIONBLOCK
+ ..()
+
+/obj/item/weapon/dnainjector/antihallucination
+ name = "DNA-Injector (Anti-Hallucination)"
+ desc = "What you see is what you get."
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 2
+ New()
+ block = HALLUCINATIONBLOCK
+ ..()
/obj/item/weapon/dnainjector/h2m
name = "DNA-Injector (Human > Monkey)"
desc = "Will make you a flea bag."
- dnatype = "se"
- dna = "FA0"
- block = 14
+ datatype = DNA2_BUF_SE
+ value = 0xFFF
+ //block = 14
+ New()
+ block = MONKEYBLOCK
+ ..()
/obj/item/weapon/dnainjector/m2h
name = "DNA-Injector (Monkey > Human)"
desc = "Will make you...less hairy."
- dnatype = "se"
- dna = "708"
- block = 14
\ No newline at end of file
+ datatype = DNA2_BUF_SE
+ value = 0x001
+ //block = 14
+ New()
+ block = MONKEYBLOCK
+ ..()
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/storage/secure.dm b/code/game/objects/items/weapons/storage/secure.dm
index c023cd247c1..8fa93d9f6ac 100644
--- a/code/game/objects/items/weapons/storage/secure.dm
+++ b/code/game/objects/items/weapons/storage/secure.dm
@@ -32,6 +32,12 @@
..()
usr << text("The service panel is [src.open ? "open" : "closed"].")
+ attack_alien(mob/user as mob)
+ return attack_hand(user)
+
+ attack_paw(mob/user as mob)
+ return attack_hand(user)
+
attackby(obj/item/weapon/W as obj, mob/user as mob)
if(locked)
if ( (istype(W, /obj/item/weapon/card/emag)||istype(W, /obj/item/weapon/melee/energy/blade)) && (!src.emagged))
diff --git a/code/game/objects/items/weapons/swords_axes_etc.dm b/code/game/objects/items/weapons/swords_axes_etc.dm
index 2e40b1fb9af..e6a1a4dff81 100644
--- a/code/game/objects/items/weapons/swords_axes_etc.dm
+++ b/code/game/objects/items/weapons/swords_axes_etc.dm
@@ -40,6 +40,7 @@
w_class = 4
playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
user << "\blue [src] is now active."
+
else
force = 3
if(istype(src,/obj/item/weapon/melee/energy/sword/pirate))
@@ -49,6 +50,12 @@
w_class = 2
playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
user << "\blue [src] can now be concealed."
+
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
add_fingerprint(user)
return
@@ -137,6 +144,12 @@
w_class = 2
force = 3//not so robust now
attack_verb = list("hit", "punched")
+
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
playsound(src.loc, 'sound/weapons/empty.ogg', 50, 1)
add_fingerprint(user)
@@ -242,11 +255,18 @@
w_class = 4
playsound(user, 'sound/weapons/saberon.ogg', 50, 1)
user << "\blue [src] is now active."
+
else
force = 3
icon_state = "eshield[active]"
w_class = 1
playsound(user, 'sound/weapons/saberoff.ogg', 50, 1)
user << "\blue [src] can now be concealed."
+
+ if(istype(user,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = user
+ H.update_inv_l_hand()
+ H.update_inv_r_hand()
+
add_fingerprint(user)
return
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 143ff13a041..e0e30e60cb9 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -15,7 +15,8 @@
var/distribute_pressure = ONE_ATMOSPHERE
var/integrity = 3
var/volume = 70
-
+ var/manipulated_by = null //Used by _onclick/hud/screen_objects.dm internals to determine if someone has messed with our tank or not.
+ //If they have and we haven't scanned it with the PDA or gas analyzer then we might just breath whatever they put in it.
/obj/item/weapon/tank/New()
..()
@@ -86,7 +87,7 @@
O << "\red [user] has used [W] on \icon[icon] [src]"
var/pressure = air_contents.return_pressure()
-
+ manipulated_by = user.real_name //This person is aware of the contents of the tank.
var/total_moles = air_contents.total_moles()
user << "\blue Results of analysis of \icon[icon]"
@@ -261,4 +262,4 @@
integrity--
else if(integrity < 3)
- integrity++
\ No newline at end of file
+ integrity++
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
index 1dc3ca6f58f..7dc173e33be 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
@@ -39,9 +39,12 @@
new /obj/item/clothing/suit/bio_suit/scientist(src)
new /obj/item/clothing/head/bio_hood/scientist(src)
new /obj/item/clothing/under/rank/research_director(src)
+ new /obj/item/clothing/under/rank/research_director/rdalt(src)
+ new /obj/item/clothing/under/rank/research_director/dress_rd(src)
new /obj/item/clothing/suit/storage/labcoat(src)
new /obj/item/weapon/cartridge/rd(src)
new /obj/item/clothing/shoes/white(src)
+ new /obj/item/clothing/shoes/leather(src)
new /obj/item/clothing/gloves/latex(src)
new /obj/item/device/radio/headset/heads/rd(src)
new /obj/item/weapon/tank/air(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index d115c40ff48..28e0958206e 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -367,5 +367,6 @@
new /obj/item/clothing/shoes/green(src)
new /obj/item/clothing/shoes/orange(src)
new /obj/item/clothing/shoes/purple(src)
+ new /obj/item/clothing/shoes/red(src)
new /obj/item/clothing/shoes/leather(src)
return
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 04f18fe3b6a..0096d763eab 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -145,9 +145,9 @@
return
var/obj/structure/window/WD
if(istype(W,/obj/item/stack/sheet/rglass))
- WD = new/obj/structure/window(loc,1) //reinforced window
+ WD = new/obj/structure/window/reinforced(loc) //reinforced window
else
- WD = new/obj/structure/window(loc,0) //normal window
+ WD = new/obj/structure/window/basic(loc) //normal window
WD.dir = dir_to_set
WD.ini_dir = dir_to_set
WD.anchored = 0
@@ -155,6 +155,7 @@
var/obj/item/stack/ST = W
ST.use(1)
user << "You place the [WD] on [src]."
+ WD.update_icon()
return
//window placing end
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index 7827749fa1e..7e894c13595 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -174,3 +174,28 @@
name = "\improper HYDROPONICS"
desc = "A warning sign which reads 'HYDROPONICS'"
icon_state = "hydro1"
+
+/obj/structure/sign/directions/science
+ name = "\improper Science department"
+ desc = "A direction sign, pointing out which way Science department is."
+ icon_state = "direction_sci"
+
+/obj/structure/sign/directions/engineering
+ name = "\improper Engineering department"
+ desc = "A direction sign, pointing out which way Engineering department is."
+ icon_state = "direction_eng"
+
+/obj/structure/sign/directions/security
+ name = "\improper Security department"
+ desc = "A direction sign, pointing out which way Security department is."
+ icon_state = "direction_sec"
+
+/obj/structure/sign/directions/medical
+ name = "\improper Medical Bay"
+ desc = "A direction sign, pointing out which way Meducal Bay is."
+ icon_state = "direction_med"
+
+/obj/structure/sign/directions/evac
+ name = "\improper Escape Arm"
+ desc = "A direction sign, pointing out which way escape shuttle dock is."
+ icon_state = "direction_evac"
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 16c5be21a88..81c017def59 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -46,6 +46,10 @@
density = 0
del(src)
+/obj/structure/rack/proc/destroy()
+ new parts(loc)
+ density = 0
+ del(src)
/obj/structure/table/update_icon()
spawn(2) //So it properly updates when deleting
@@ -423,6 +427,8 @@
set desc = "Flips a non-reinforced table"
set category = "Object"
set src in oview(1)
+ if(ismouse(usr))
+ return
if (!can_touch(usr))
return
if(!flip(get_cardinal_dir(usr,src)))
@@ -570,6 +576,7 @@
flags = FPRINT
anchored = 1.0
throwpass = 1 //You can throw objects over this, despite it's density.
+ var/parts = /obj/item/weapon/rack_parts
/obj/structure/rack/ex_act(severity)
switch(severity)
@@ -632,33 +639,22 @@
if(HULK in user.mutations)
visible_message("[user] smashes [src] apart!")
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
- new /obj/item/weapon/rack_parts(loc)
- density = 0
- del(src)
-
+ destroy()
/obj/structure/rack/attack_paw(mob/user)
if(HULK in user.mutations)
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
visible_message("[user] smashes [src] apart!")
- new /obj/item/weapon/rack_parts(loc)
- density = 0
- del(src)
-
+ destroy()
/obj/structure/rack/attack_alien(mob/user)
visible_message("[user] slices [src] apart!")
- new /obj/item/weapon/rack_parts(loc)
- density = 0
- del(src)
-
+ destroy()
/obj/structure/rack/attack_animal(mob/living/simple_animal/user)
if(user.wall_smash)
visible_message("[user] smashes [src] apart!")
- new /obj/item/weapon/rack_parts(loc)
- density = 0
- del(src)
+ destroy()
/obj/structure/rack/attack_tk() // no telehulk sorry
return
\ No newline at end of file
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 7d1041aaab3..482fdea6c09 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -9,7 +9,7 @@
flags = ON_BORDER
var/health = 14.0
var/ini_dir = null
- var/state = 0
+ var/state = 2
var/reinf = 0
var/basestate
var/shardtype = /obj/item/weapon/shard
@@ -338,6 +338,7 @@
spawn(2)
if(!src) return
if(!is_fulltile())
+ icon_state = "[basestate]"
return
var/junction = 0 //will be used to determine from which side the window is connected to other windows
if(anchored)
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index 2598a632443..241c84d3f97 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -20,12 +20,16 @@
if (istype(A,/mob/living/carbon))
var/mob/living/carbon/M = A
- if(M.lying) return
+ if(M.lying) return
dirt++
- if (dirt > 40)
- dirt = 0
- if (!locate(/obj/effect/decal/cleanable/dirt, src))
- new/obj/effect/decal/cleanable/dirt(src)
+ var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src)
+ if (dirt >= 30)
+ if (!dirtoverlay)
+ dirtoverlay = new/obj/effect/decal/cleanable/dirt(src)
+ dirtoverlay.alpha = 15
+ else if (dirt > 30)
+ dirtoverlay.alpha = min(dirtoverlay.alpha+20, 255)
+
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index c6dcc662a6f..097cf4cc271 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -581,7 +581,8 @@ var/global/floorIsLava = 0
Spawn a gravitational anomaly (aka lagitational anomolag)
Spawn wormholes
Spawn blob
- Trigger an Alien infestation
+ Trigger a Xenomorph infestation
+ Trigger a Cortical Borer infestation
Spawn an Alien silently
Trigger a Spider infestation
Send in a space ninja
diff --git a/code/modules/admin/admin_investigate.dm b/code/modules/admin/admin_investigate.dm
index a0627884385..1c90383f40a 100644
--- a/code/modules/admin/admin_investigate.dm
+++ b/code/modules/admin/admin_investigate.dm
@@ -26,12 +26,12 @@
F << "[time2text(world.timeofday,"hh:mm")] \ref[src] ([x],[y],[z]) || [src] [message]
"
//ADMINVERBS
-/client/proc/investigate_show( subject in list("hrefs","notes","singulo") )
+/client/proc/investigate_show( subject in list("hrefs","notes","singulo","telesci") )
set name = "Investigate"
set category = "Admin"
if(!holder) return
switch(subject)
- if("singulo") //general one-round-only stuff
+ if("singulo", "telesci") //general one-round-only stuff
var/F = investigate_subject2file(subject)
if(!F)
src << "Error: admin_investigate: [INVESTIGATE_DIR][subject] is an invalid path or cannot be accessed."
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 43dc61c73f9..54a865955ad 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -511,10 +511,10 @@
jobs += ""
counter = 0
- if(jobban_isbanned(M, "Internal Affairs Agent"))
+ if(jobban_isbanned(M, "Internal Affairs Agent"))
jobs += "| Internal Affairs Agent | "
else
- jobs += "Internal Affairs Agent | "
+ jobs += "Internal Affairs Agent | "
jobs += "
"
@@ -539,7 +539,7 @@
counter = 0
//pAI isn't technically a job, but it goes in here.
-
+
if(jobban_isbanned(M, "pAI"))
jobs += "pAI | "
else
@@ -1773,7 +1773,12 @@
log_admin("[key_name(usr)] spawned an alien infestation", 1)
message_admins("\blue [key_name_admin(usr)] attempted an alien infestation", 1)
new /datum/event/alien_infestation
-
+ if("borers")
+ feedback_inc("admin_secrets_fun_used",1)
+ feedback_add_details("admin_secrets_fun_used","Borers")
+ log_admin("[key_name(usr)] spawned a cortical borer infestation.", 1)
+ message_admins("\blue [key_name_admin(usr)] spawned a cortical borer infestation.", 1)
+ new /datum/event/borer_infestation
if("power")
feedback_inc("admin_secrets_fun_used",1)
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 1f5b3181bfd..871567cc0ad 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -447,9 +447,9 @@ Traitors and the like can also be revived with the previous role mostly intact.
if(record_found)//Pull up their name from database records if they did have a mind.
new_character.dna = new()//Let's first give them a new DNA.
new_character.dna.unique_enzymes = record_found.fields["b_dna"]//Enzymes are based on real name but we'll use the record for conformity.
- new_character.dna.struc_enzymes = record_found.fields["enzymes"]//This is the default of enzymes so I think it's safe to go with.
- new_character.dna.uni_identity = record_found.fields["identity"]//DNA identity is carried over.
- updateappearance(new_character,new_character.dna.uni_identity)//Now we configure their appearance based on their unique identity, same as with a DNA machine or somesuch.
+ new_character.dna.SE = record_found.fields["enzymes"]//This is the default of enzymes so I think it's safe to go with.
+ new_character.dna.UpdateSE()
+ new_character.UpdateAppearance(record_found.fields["identity"])//Now we configure their appearance based on their unique identity, same as with a DNA machine or somesuch.
else//If they have no records, we just do a random DNA for them, based on their random appearance/savefile.
new_character.dna.ready_dna(new_character)
diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm
index 8ea48ea4898..92de9fff491 100644
--- a/code/modules/admin/verbs/striketeam.dm
+++ b/code/modules/admin/verbs/striketeam.dm
@@ -124,7 +124,7 @@ var/global/sent_strike_team = 0
/mob/living/carbon/human/proc/equip_death_commando(leader_selected = 0)
var/obj/item/device/radio/R = new /obj/item/device/radio/headset(src)
- R.set_frequency(1441)
+ R.set_frequency(1341)
equip_to_slot_or_del(R, slot_l_ear)
if (leader_selected == 0)
equip_to_slot_or_del(new /obj/item/clothing/under/color/green(src), slot_w_uniform)
diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm
index 4d2c8fa53b9..5cea63edaea 100644
--- a/code/modules/assembly/mousetrap.dm
+++ b/code/modules/assembly/mousetrap.dm
@@ -45,6 +45,7 @@
visible_message("\red SPLAT!")
M.splat()
playsound(target.loc, 'sound/effects/snap.ogg', 50, 1)
+ layer = MOB_LAYER - 0.2
armed = 0
update_icon()
pulse(0)
@@ -112,4 +113,16 @@
/obj/item/device/assembly/mousetrap/armed
icon_state = "mousetraparmed"
- armed = 1
\ No newline at end of file
+ armed = 1
+
+
+/obj/item/device/assembly/mousetrap/verb/hide_under()
+ set src in oview(1)
+ set name = "Hide"
+ set category = "Object"
+
+ if(usr.stat)
+ return
+
+ layer = TURF_LAYER+0.2
+ usr << "You hide [src]."
\ No newline at end of file
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 95c5d638406..eabee2ba46d 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -254,13 +254,17 @@
'nano/templates/geoscanner.tmpl',
'nano/templates/dna_modifier.tmpl',
'nano/templates/telescience_console.tmpl',
+ 'nano/templates/pda.tmpl',
+ 'nano/templates/uplink.tmpl',
'nano/images/uiBackground.png',
'nano/images/uiIcons16.png',
'nano/images/uiIcons24.png',
+ 'nano/images/uiBackground-Syndicate.png',
'nano/images/uiLinkPendingIcon.gif',
'nano/images/uiMaskBackground.png',
'nano/images/uiNoticeBackground.jpg',
'nano/images/uiTitleFluff.png',
+ 'nano/images/uiTitleFluff-Syndicate.png',
'html/search.js',
'html/panels.css',
'icons/pda_icons/pda_atmos.png',
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 51d8bb92da0..153451431c7 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -44,6 +44,8 @@ datum/preferences
var/be_special = 0 //Special role selection
var/UI_style = "Midnight"
var/toggles = TOGGLES_DEFAULT
+ var/UI_style_color = "#ffffff"
+ var/UI_style_alpha = 255
//character preferences
var/real_name //our character's name
@@ -241,6 +243,9 @@ datum/preferences
dat += "
"
dat += "UI Style: [UI_style]
"
+ dat += "Custom UI(recommended for White UI):
"
+ dat += "-Color: [UI_style_color]
"
+ dat += "-Alpha(transparence): [UI_style_alpha]
"
dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"]
"
dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"]
"
dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
"
@@ -1120,6 +1125,16 @@ datum/preferences
else
UI_style = "Midnight"
+ if("UIcolor")
+ var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!") as color|null
+ if(!UI_style_color_new) return
+ UI_style_color = UI_style_color_new
+
+ if("UIalpha")
+ var/UI_style_alpha_new = input(user, "Select a new alpha(transparence) parametr for UI, between 50 and 255") as num
+ if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return
+ UI_style_alpha = UI_style_alpha_new
+
if("be_special")
var/num = text2num(href_list["num"])
be_special ^= (1<> be_special
S["default_slot"] >> default_slot
S["toggles"] >> toggles
+ S["UI_style_color"] >> UI_style_color
+ S["UI_style_alpha"] >> UI_style_alpha
//Sanitize
ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor))
lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog))
- UI_style = sanitize_inlist(UI_style, list("Midnight","Orange","old"), initial(UI_style))
+ UI_style = sanitize_inlist(UI_style, list("White", "Midnight","Orange","old"), initial(UI_style))
be_special = sanitize_integer(be_special, 0, 65535, initial(be_special))
default_slot = sanitize_integer(default_slot, 1, MAX_SAVE_SLOTS, initial(default_slot))
toggles = sanitize_integer(toggles, 0, 65535, initial(toggles))
+ UI_style_color = sanitize_hexcolor(UI_style_color, initial(UI_style_color))
+ UI_style_alpha = sanitize_integer(UI_style_alpha, 0, 255, initial(UI_style_alpha))
return 1
@@ -80,6 +84,8 @@
S["be_special"] << be_special
S["default_slot"] << default_slot
S["toggles"] << toggles
+ S["UI_style_color"] << UI_style_color
+ S["UI_style_alpha"] << UI_style_alpha
return 1
diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm
index e59546a470f..c1628c1f3fe 100644
--- a/code/modules/client/preferences_toggles.dm
+++ b/code/modules/client/preferences_toggles.dm
@@ -107,10 +107,12 @@
set desc = "Toggles seeing Local OutOfCharacter chat"
prefs.toggles ^= CHAT_LOOC
prefs.save_preferences()
+
src << "You will [(prefs.toggles & CHAT_LOOC) ? "now" : "no longer"] see messages on the LOOC channel."
feedback_add_details("admin_verb","TLOOC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
/client/verb/Toggle_Soundscape() //All new ambience should be added here so it works with this verb until someone better at things comes up with a fix that isn't awful
set name = "Hear/Silence Ambience"
set category = "Preferences"
@@ -135,4 +137,42 @@
prefs.be_special ^= role_flag
prefs.save_preferences()
src << "You will [(prefs.be_special & role_flag) ? "now" : "no longer"] be considered for [role] events (where possible)."
- feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
\ No newline at end of file
+ feedback_add_details("admin_verb","TBeSpecial") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+
+/client/verb/change_ui()
+ set name = "Change UI"
+ set category = "Preferences"
+ set desc = "Configure your user interface"
+
+ if(!ishuman(usr))
+ usr << "This only for human"
+ return
+
+ var/UI_style_new = input(usr, "Select a style, we recommend White for customization") in list("White", "Midnight", "Orange", "old")
+ if(!UI_style_new) return
+
+ var/UI_style_alpha_new = input(usr, "Select a new alpha(transparence) parametr for UI, between 50 and 255") as num
+ if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return
+
+ var/UI_style_color_new = input(usr, "Choose your UI color, dark colors are not recommended!") as color|null
+ if(!UI_style_color_new) return
+
+ //update UI
+ var/list/icons = usr.hud_used.adding + usr.hud_used.other +usr.hud_used.hotkeybuttons
+ icons.Add(usr.zone_sel)
+
+ for(var/obj/screen/I in icons)
+ if(I.color && I.alpha)
+ I.icon = ui_style2icon(UI_style_new)
+ I.color = UI_style_color_new
+ I.alpha = UI_style_alpha_new
+
+
+
+ if(alert("Like it? Save changes?",,"Yes", "No") == "Yes")
+ prefs.UI_style = UI_style_new
+ prefs.UI_style_alpha = UI_style_alpha_new
+ prefs.UI_style_color = UI_style_color_new
+ prefs.save_preferences()
+ usr << "UI was saved"
\ No newline at end of file
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index e3fff70f366..aedb20c70d6 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -73,6 +73,12 @@
holder.icon_state = "hudxeno"
else if(foundVirus)
holder.icon_state = "hudill"
+ else if(patient.has_brain_worms())
+ var/mob/living/simple_animal/borer/B = patient.has_brain_worms()
+ if(B.controlling)
+ holder.icon_state = "hudbrainworm"
+ else
+ holder.icon_state = "hudhealthy"
else
holder.icon_state = "hudhealthy"
C.images += holder
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index 277b42d364d..d168edc4c1c 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -35,6 +35,12 @@
icon_state = "amp"
siemens_coefficient = 0.8
+/obj/item/clothing/head/wizard/cap
+ name = "Gentlemans Cap"
+ desc = "A checkered gray flat cap woven together with the rarest of threads."
+ icon_state = "gentcap"
+ siemens_coefficient = 0.8
+
/obj/item/clothing/suit/wizrobe
name = "wizard robe"
desc = "A magnificant, gem-lined robe that seems to radiate power."
@@ -79,6 +85,12 @@
icon_state = "psyamp"
item_state = "psyamp"
+/obj/item/clothing/suit/wizrobe/gentlecoat
+ name = "Gentlemans Coat"
+ desc = "A heavy threaded twead gray jacket. For a different sort of Gentleman."
+ icon_state = "gentlecoat"
+ item_state = "gentlecoat"
+
/obj/item/clothing/suit/wizrobe/fake
name = "wizard robe"
desc = "A rather dull, blue robe meant to mimick real wizard robes."
diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm
index 4ae31f9d893..549a824d541 100644
--- a/code/modules/clothing/under/jobs/medsci.dm
+++ b/code/modules/clothing/under/jobs/medsci.dm
@@ -10,6 +10,24 @@
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0)
flags = FPRINT | TABLEPASS
+/obj/item/clothing/under/rank/research_director/rdalt
+ desc = "A dress suit and slacks stained with hard work and dedication to science. Perhaps other things as well, but mostly hard work and dedication."
+ name = "head researcher uniform"
+ icon_state = "rdalt"
+ item_state = "rdalt"
+ item_color = "rdalt"
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0)
+ flags = FPRINT | TABLEPASS
+
+/obj/item/clothing/under/rank/research_director/dress_rd
+ name = "research director dress uniform"
+ desc = "Feminine fashion for the style concious RD. Its fabric provides minor protection from biological contaminants."
+ icon_state = "dress_rd"
+ item_color = "dress_rd"
+ armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 10, rad = 0)
+ flags = FPRINT | TABLEPASS
+
+
/obj/item/clothing/under/rank/scientist
desc = "It's made of a special fiber that provides minor protection against biohazards. It has markings that denote the wearer as a scientist."
name = "scientist's jumpsuit"
diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm
index c35910d060c..e6dda9c6f76 100644
--- a/code/modules/clothing/under/jobs/security.dm
+++ b/code/modules/clothing/under/jobs/security.dm
@@ -80,7 +80,7 @@
item_color = "polsuit"
/obj/item/clothing/under/det/slob/verb/rollup()
- set name = "Roll suit sleevels"
+ set name = "Roll suit sleeves"
set category = "Object"
set src in usr
item_color = item_color == "polsuit" ? "polsuit_rolled" : "polsuit"
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 3681a43eca7..15365e1eacb 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -138,6 +138,13 @@
item_state = "psysuit"
item_color = "psysuit"
+/obj/item/clothing/under/gentlesuit
+ name = "Gentlemans Suit"
+ desc = "A silk black shirt with a white tie and a matching gray vest and slacks. Feels proper."
+ icon_state = "gentlesuit"
+ item_state = "gentlesuit"
+ item_color = "gentlesuit"
+
/obj/item/clothing/under/gimmick/rank/captain/suit
name = "captain's suit"
desc = "A green suit and yellow necktie. Exemplifies authority."
@@ -285,11 +292,6 @@
icon_state = "dress_saloon"
item_color = "dress_saloon"
-/obj/item/clothing/under/dress/dress_rd
- name = "research director dress uniform"
- desc = "Feminine fashion for the style concious RD."
- icon_state = "dress_rd"
- item_color = "dress_rd"
/obj/item/clothing/under/dress/dress_cap
name = "captain dress uniform"
@@ -358,7 +360,7 @@
flags_inv = HIDESHOES
/obj/item/clothing/under/wedding/bride_white
- name = "orange wedding dress"
+ name = "silky wedding dress"
desc = "A white wedding gown made from the finest silk."
icon_state = "bride_white"
item_color = "bride_white"
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index 52568ad005b..d898495697a 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -70,6 +70,7 @@
return
if(istype(A,/obj/machinery/computer/forensic_scanning)) //breaks shit.
return
+
if(istype(A,/obj/item/weapon/f_card))
user << "The scanner displays on the screen: \"ERROR 43: Object on Excluded Object List.\""
flick("forensic0",src)
@@ -77,9 +78,8 @@
add_fingerprint(user)
-
- //Special case for blood splaters.
- if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune))
+ //Special case for blood splatters, runes and gibs.
+ if (istype(A, /obj/effect/decal/cleanable/blood) || istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable/blood/gibs))
if(!isnull(A.blood_DNA))
for(var/blood in A.blood_DNA)
user << "\blue Blood type: [A.blood_DNA[blood]]\nDNA: [blood]"
diff --git a/code/modules/events/borers.dm b/code/modules/events/borers.dm
new file mode 100644
index 00000000000..2c6a2820fbb
--- /dev/null
+++ b/code/modules/events/borers.dm
@@ -0,0 +1,38 @@
+//Cortical borer spawn event - care of RobRichards1997 with minor editing by Zuhayr.
+
+/datum/event/borer_infestation
+ oneShot = 1
+
+/datum/event/borer_infestation
+ announceWhen = 400
+
+ var/spawncount = 1
+ var/successSpawn = 0 //So we don't make a command report if nothing gets spawned.
+
+/datum/event/borer_infestation/setup()
+ announceWhen = rand(announceWhen, announceWhen + 50)
+ spawncount = rand(1, 3)
+
+/datum/event/borer_infestation/announce()
+ if(successSpawn)
+ command_alert("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert")
+ world << sound('sound/AI/aliens.ogg')
+
+/datum/event/borer_infestation/start()
+ var/list/vents = list()
+ for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in world)
+ if(temp_vent.loc.z == 1 && !temp_vent.welded && temp_vent.network)
+ //Stops cortical borers getting stuck in small networks. See: Security, Virology
+ if(temp_vent.network.normal_members.len > 50)
+ vents += temp_vent
+
+ var/list/candidates = get_alien_candidates()
+ while(spawncount > 0 && vents.len && candidates.len)
+ var/obj/vent = pick_n_take(vents)
+ var/client/C = pick_n_take(candidates)
+
+ var/mob/living/simple_animal/borer/new_borer = new(vent.loc)
+ new_borer.key = C.key
+
+ spawncount--
+ successSpawn = 1
\ No newline at end of file
diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm
index fe6f56624f6..a424cdd72af 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -30,8 +30,8 @@
continue
var/datum/disease/dnaspread/D = new
D.strain_data["name"] = H.real_name
- D.strain_data["UI"] = H.dna.uni_identity
- D.strain_data["SE"] = H.dna.struc_enzymes
+ D.strain_data["UI"] = H.dna.UI
+ D.strain_data["SE"] = H.dna.SE
D.carrier = 1
D.holder = H
D.affected_mob = H
diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm
index ad79eed5164..91bf29e00af 100644
--- a/code/modules/events/radiation_storm.dm
+++ b/code/modules/events/radiation_storm.dm
@@ -34,10 +34,10 @@
H.apply_effect((rand(40,70)),IRRADIATE,0)
if (prob(75))
randmutb(H) // Applies bad mutation
- domutcheck(H,null,1)
+ domutcheck(H,null,MUTCHK_FORCED)
else
randmutg(H) // Applies good mutation
- domutcheck(H,null,1)
+ domutcheck(H,null,MUTCHK_FORCED)
for(var/mob/living/carbon/monkey/M in living_mob_list)
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index c410a51c00b..90b2cbf0e3f 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -5,6 +5,7 @@
#define ARTIFACT_SPAWN_CHANCE 20
/datum/controller/game_controller/var/list/artifact_spawning_turfs = list()
+/var/global/list/artifact_spawn = list() // Runtime fix for geometry loading before controller is instantiated.
/turf/simulated/mineral //wall piece
name = "Rock"
@@ -129,7 +130,7 @@
//dont create artifact machinery in animal or plant digsites, or if we already have one
if(!artifact_find && digsite != 1 && digsite != 2 && prob(ARTIFACT_SPAWN_CHANCE))
artifact_find = new()
- master_controller.artifact_spawning_turfs.Add(src)
+ artifact_spawn.Add(src)
if(!src.geological_data)
src.geological_data = new/datum/geosample(src)
diff --git a/code/modules/mob/abilities.dm b/code/modules/mob/abilities.dm
new file mode 100644
index 00000000000..e5e2be9af0b
--- /dev/null
+++ b/code/modules/mob/abilities.dm
@@ -0,0 +1,35 @@
+/*
+Creature-level abilities.
+*/
+
+/var/global/list/ability_verbs = list( )
+
+/*
+
+ Example ability:
+
+/client/proc/test_ability()
+
+ set category = "Ability"
+ set name = "Test ability"
+ set desc = "An ability for testing."
+
+ // Check if the client has a mob and if the mob is valid and alive.
+ if(!mob || !istype(mob,/mob/living) || mob.stat)
+ src << "\red You must be corporeal and alive to do that."
+ return 0
+
+ //Handcuff check.
+ if(mob.restrained())
+ src << "\red You cannot do this while restrained."
+ return 0
+
+ if(istype(mob,/mob/living/carbon))
+ var/mob/living/carbon/M = mob
+ if(M.handcuffed)
+ src << "\red You cannot do this while cuffed."
+ return 0
+
+ src << "\blue You perform an ability."
+
+*/
\ No newline at end of file
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index aad87026b27..b61c1224794 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -17,6 +17,7 @@
//If you died in the game and are a ghsot - this will remain as null.
//Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot.
var/has_enabled_antagHUD = 0
+ var/medHUD = 0
var/antagHUD = 0
universal_speak = 1
var/atom/movable/following = null
@@ -25,7 +26,7 @@
see_invisible = SEE_INVISIBLE_OBSERVER
see_in_dark = 100
verbs += /mob/dead/observer/proc/dead_tele
-
+
stat = DEAD
var/turf/T
@@ -92,12 +93,12 @@ Works together with spawning an observer, noted above.
/mob/dead/observer/Life()
..()
- if(!loc) return
+ if(!loc) return
if(!client) return 0
if(client.images.len)
- for(var/image/hud in client.images)
+ for(var/image/hud in client.images)
if(copytext(hud.icon_state,1,4) == "hud")
client.images.Remove(hud)
if(antagHUD)
@@ -107,8 +108,69 @@ Works together with spawning an observer, noted above.
target_list += target
if(target_list.len)
assess_targets(target_list, src)
+ if(medHUD)
+ process_medHUD(src)
+
+
+// Direct copied from medical HUD glasses proc, used to determine what health bar to put over the targets head.
+/mob/dead/proc/RoundHealth(var/health)
+ switch(health)
+ if(100 to INFINITY)
+ return "health100"
+ if(70 to 100)
+ return "health80"
+ if(50 to 70)
+ return "health60"
+ if(30 to 50)
+ return "health40"
+ if(18 to 30)
+ return "health25"
+ if(5 to 18)
+ return "health10"
+ if(1 to 5)
+ return "health1"
+ if(-99 to 0)
+ return "health0"
+ else
+ return "health-100"
+ return "0"
+
+
+// Pretty much a direct copy of Medical HUD stuff, except will show ill if they are ill instead of also checking for known illnesses.
+
+/mob/dead/proc/process_medHUD(var/mob/M)
+ var/client/C = M.client
+ var/image/holder
+ for(var/mob/living/carbon/human/patient in oview(M))
+ var/foundVirus = 0
+ if(patient.virus2.len)
+ foundVirus = 1
+ if(!C) return
+ holder = patient.hud_list[HEALTH_HUD]
+ if(patient.stat == 2)
+ holder.icon_state = "hudhealth-100"
+ else
+ holder.icon_state = "hud[RoundHealth(patient.health)]"
+ C.images += holder
+
+ holder = patient.hud_list[STATUS_HUD]
+ if(patient.stat == 2)
+ holder.icon_state = "huddead"
+ else if(patient.status_flags & XENO_HOST)
+ holder.icon_state = "hudxeno"
+ else if(foundVirus)
+ holder.icon_state = "hudill"
+ else if(patient.has_brain_worms())
+ var/mob/living/simple_animal/borer/B = patient.has_brain_worms()
+ if(B.controlling)
+ holder.icon_state = "hudbrainworm"
+ else
+ holder.icon_state = "hudhealthy"
+ else
+ holder.icon_state = "hudhealthy"
+
+ C.images += holder
-
/mob/dead/proc/assess_targets(list/target_list, mob/dead/observer/U)
var/icon/tempHud = 'icons/mob/hud.dmi'
@@ -238,6 +300,19 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
mind.current.key = key
return 1
+/mob/dead/observer/verb/toggle_medHUD()
+ set category = "Ghost"
+ set name = "Toggle MedicHUD"
+ set desc = "Toggles Medical HUD allowing you to see how everyone is doing"
+ if(!client)
+ return
+ if(medHUD)
+ medHUD = 0
+ src << "\blue Medical HUD Disabled"
+ else
+ medHUD = 1
+ src << "\blue Medical HUD Enabled"
+
/mob/dead/observer/verb/toggle_antagHUD()
set category = "Ghost"
set name = "Toggle AntagHUD"
@@ -251,7 +326,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(jobban_isbanned(M, "AntagHUD"))
src << "\red You have been banned from using this feature"
return
- if(config.antag_hud_restricted && !M.has_enabled_antagHUD &&!client.holder)
+ if(config.antag_hud_restricted && !M.has_enabled_antagHUD &&!client.holder)
var/response = alert(src, "If you turn this on, you will not be able to take any part in the round.","Are you sure you want to turn this feature on?","Yes","No")
if(response == "No") return
M.can_reenter_corpse = 0
@@ -378,6 +453,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Become mouse"
set category = "Ghost"
+ if(config.disable_player_mice)
+ src << "Spawning as a mouse is currently disabled."
+ return
+
var/timedifference = world.time - client.time_died_as_mouse
if(client.time_died_as_mouse && timedifference <= mouse_respawn_time * 600)
var/timedifference_text
@@ -385,6 +464,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
src << "You may only spawn again as a mouse more than [mouse_respawn_time] minutes after your death. You have [timedifference_text] left."
return
+ var/response = alert(src, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?","Squeek!","Nope!")
+ if(response != "Squeek!") return //Hit the wrong key...again.
+
+
//find a viable mouse candidate
var/mob/living/simple_animal/mouse/host
var/obj/machinery/atmospherics/unary/vent_pump/vent_found
@@ -399,6 +482,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
src << "Unable to find any unwelded vents to spawn mice at."
if(host)
+ if(config.uneducated_mice)
+ host.universal_understand = 0
host.ckey = src.ckey
host << "You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent."
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
index 7487ffa6313..2b084ce8b5c 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
@@ -31,6 +31,10 @@
continue
no_queen = 0
+ if(src.has_brain_worms())
+ src << "We cannot perform this ability at the present time!"
+ return
+
if(no_queen)
adjustToxLoss(-500)
src << "\green You begin to evolve!"
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index dbca1091c63..f841b09d13d 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -532,7 +532,7 @@
B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!"
//Check for brain worms in head.
-/mob/living/carbon/proc/has_brain_worms()
+/mob/proc/has_brain_worms()
for(var/I in contents)
if(istype(I,/mob/living/simple_animal/borer))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 74cab645053..1454b360b58 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -776,6 +776,14 @@
if(istype(usr,/mob/living/silicon/robot))
var/mob/living/silicon/robot/U = usr
R.fields[text("com_[counter]")] = text("Made by [U.name] ([U.modtype] [U.braintype]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
[t1]")
+
+ if (href_list["lookitem"])
+ var/obj/item/I = locate(href_list["lookitem"])
+ I.examine()
+
+ if (href_list["lookmob"])
+ var/mob/M = locate(href_list["lookmob"])
+ M.examine()
..()
return
@@ -1100,6 +1108,7 @@
return 0 //already bloodied with this blood. Cannot add more.
blood_DNA[M.dna.unique_enzymes] = M.dna.b_type
src.update_inv_gloves() //handles bloody hands overlays and updating
+ verbs += /mob/living/carbon/human/proc/bloody_doodle
return 1 //we applied blood to the item
/mob/living/carbon/human/clean_blood()
@@ -1266,3 +1275,56 @@ mob/living/carbon/human/yank_out_object()
return 1
else
return 0
+
+/mob/living/carbon/human/proc/bloody_doodle()
+ set category = "IC"
+ set name = "Write in blood"
+ set desc = "Use blood on your hands to write a short message on the floor or a wall, murder mystery style."
+
+ if (src.stat)
+ return
+
+ if (usr != src)
+ return 0 //something is terribly wrong
+
+ if (!bloody_hands)
+ verbs -= /mob/living/carbon/human/proc/bloody_doodle
+
+ if (src.gloves)
+ src << "Your [src.gloves] are getting in the way."
+ return
+
+ var/turf/simulated/T = src.loc
+ if (!istype(T)) //to prevent doodling out of mechs and lockers
+ src << "You cannot reach the floor."
+ return
+
+ var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West")
+ if (direction != "Here")
+ T = get_step(T,text2dir(direction))
+ if (!istype(T))
+ src << "You cannot doodle there."
+ return
+
+ var/num_doodles = 0
+ for (var/obj/effect/decal/cleanable/blood/writing/W in T)
+ num_doodles++
+ if (num_doodles > 4)
+ src << "There is no space to write on!"
+ return
+
+ var/max_length = bloody_hands * 30 //tweeter style
+
+ var/message = stripped_input(src,"Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")
+
+ if (message)
+ var/used_blood_amount = round(length(message) / 30, 1)
+ bloody_hands = max(0, bloody_hands - used_blood_amount) //use up some blood
+
+ if (length(message) > max_length)
+ message += "-"
+ src << "You ran out of blood to write with!"
+
+ var/obj/effect/decal/cleanable/blood/writing/W = new(T)
+ W.message = message
+ W.add_fingerprint(src)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 16a4733b276..b1a20b144ed 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -134,6 +134,16 @@ emp_act
protection += C.armor[type]
return protection
+/mob/living/carbon/human/proc/check_head_coverage()
+
+ var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform)
+ for(var/bp in body_parts)
+ if(!bp) continue
+ if(bp && istype(bp ,/obj/item/clothing))
+ var/obj/item/clothing/C = bp
+ if(C.body_parts_covered & HEAD)
+ return 1
+ return 0
/mob/living/carbon/human/proc/check_shields(var/damage = 0, var/attack_text = "the attack")
if(l_hand && istype(l_hand, /obj/item/weapon))//Current base is the prob(50-d/3)
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index 6c28acc72b5..1b0d0e1064a 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -13,6 +13,9 @@
set invisibility = 0
set background = 1
if (monkeyizing) return
+ if (update_muts)
+ update_muts=0
+ domutcheck(src,null,MUTCHK_FORCED)
..()
var/datum/gas_mixture/environment // Added to prevent null location errors-- TLE
@@ -67,8 +70,11 @@
G.process()
if(!client && stat == CONSCIOUS)
- if(prob(33) && canmove && isturf(loc))
+
+ if(prob(33) && canmove && isturf(loc) && !pulledby) //won't move if being pulled
+
step(src, pick(cardinal))
+
if(prob(1))
emote(pick("scratch","jump","roll","tail"))
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index fe3aeae8ba5..b0ddd30c73d 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -10,28 +10,31 @@
var/obj/item/weapon/card/id/wear_id = null // Fix for station bounced radios -- Skie
var/greaterform = "Human" // Used when humanizing a monkey.
- var/uni_append = "12C4E2" // Small appearance modifier for different species.
+ icon_state = "monkey1"
+ //var/uni_append = "12C4E2" // Small appearance modifier for different species.
+ var/list/uni_append = list(0x12C,0x4E2) // Same as above for DNA2.
+ var/update_muts = 1 // Monkey gene must be set at start.
/mob/living/carbon/monkey/tajara
name = "farwa"
voice_name = "farwa"
speak_emote = list("mews")
icon_state = "tajkey1"
- uni_append = "0A0E00"
+ uni_append = list(0x0A0,0xE00) // 0A0E00
/mob/living/carbon/monkey/skrell
name = "neaera"
voice_name = "neaera"
speak_emote = list("squicks")
icon_state = "skrellkey1"
- uni_append = "01CC92"
+ uni_append = list(0x01C,0xC92) // 01CC92
/mob/living/carbon/monkey/unathi
name = "stok"
voice_name = "stok"
speak_emote = list("hisses")
icon_state = "stokkey1"
- uni_append = "044C5D"
+ uni_append = list(0x044,0xC5D) // 044C5D
/mob/living/carbon/monkey/New()
var/datum/reagents/R = new/datum/reagents(1000)
@@ -47,16 +50,25 @@
gender = pick(MALE, FEMALE)
dna = new /datum/dna( null )
dna.real_name = real_name
- dna.uni_identity = "00600200A00E0110148FC01300B009"
- dna.struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6"
+ dna.ResetSE()
+ dna.ResetUI()
+ //dna.uni_identity = "00600200A00E0110148FC01300B009"
+ //dna.struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6"
dna.unique_enzymes = md5(name)
- //////////blah
- var/gendervar
- if (gender == MALE)
- gendervar = add_zero2(num2hex((rand(1,2049)),1), 3)
- else
- gendervar = add_zero2(num2hex((rand(2051,4094)),1), 3)
- dna.uni_identity += "[gendervar][uni_append]"
+
+ // We're a monkey
+ dna.SetSEState(MONKEYBLOCK, 1)
+ // Fix gender
+ dna.SetUIState(DNA_UI_GENDER, gender != MALE, 1)
+
+ // Set the blocks to uni_append, if needed.
+ if(uni_append.len>0)
+ for(var/b=1;b<=uni_append.len;b++)
+ dna.SetUIValue(DNA_UI_LENGTH-(uni_append.len-b),uni_append[b], 1)
+ dna.UpdateUI()
+
+ update_muts=1
+
..()
update_icons()
return
diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm
index 76ab17fbd47..c5d5351e3ff 100644
--- a/code/modules/mob/living/carbon/species.dm
+++ b/code/modules/mob/living/carbon/species.dm
@@ -37,6 +37,8 @@
var/flags = 0 // Various specific features.
+ var/list/abilities = list() // For species-derived or admin-given powers
+
/datum/species/human
name = "Human"
language = "Sol Common"
@@ -44,6 +46,9 @@
flags = HAS_SKIN_TONE | HAS_LIPS | HAS_UNDERWEAR
+ //If you wanted to add a species-level ability:
+ /*abilities = list(/client/proc/test_ability)*/
+
/datum/species/unathi
name = "Unathi"
icobase = 'icons/mob/human_races/r_lizard.dmi'
diff --git a/code/modules/mob/living/silicon/pai/hud.dm b/code/modules/mob/living/silicon/pai/hud.dm
index 74d5ec8f878..07df7cd9ead 100644
--- a/code/modules/mob/living/silicon/pai/hud.dm
+++ b/code/modules/mob/living/silicon/pai/hud.dm
@@ -80,6 +80,12 @@
holder.icon_state = "hudxeno"
else if(foundVirus)
holder.icon_state = "hudill"
+ else if(patient.has_brain_worms())
+ var/mob/living/simple_animal/borer/B = patient.has_brain_worms()
+ if(B.controlling)
+ holder.icon_state = "hudbrainworm"
+ else
+ holder.icon_state = "hudhealthy"
else
holder.icon_state = "hudhealthy"
client.images += holder
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 611243f6548..176a5a85270 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -1161,6 +1161,9 @@
var/turf/tile = loc
if(isturf(tile))
tile.clean_blood()
+ if (istype(tile, /turf/simulated))
+ var/turf/simulated/S = tile
+ S.dirt = 0
for(var/A in tile)
if(istype(A, /obj/effect))
if(istype(A, /obj/effect/rune) || istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/overlay))
diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm
index d3166dd974f..d3e0ea9518e 100644
--- a/code/modules/mob/living/simple_animal/borer.dm
+++ b/code/modules/mob/living/simple_animal/borer.dm
@@ -16,6 +16,12 @@
src << "You whisper silently, \"[message]\""
B.host << "The captive mind of [src] whispers, \"[message]\""
+ for (var/mob/M in player_list)
+ if (istype(M, /mob/new_player))
+ continue
+ else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
+ M << "The captive mind of [src] whispers, \"[message]\""
+
/mob/living/captive_brain/emote(var/message)
return
@@ -40,28 +46,53 @@
wander = 0
pass_flags = PASSTABLE
+ var/used_dominate
var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin.
var/mob/living/carbon/human/host // Human host for the brain worm.
var/truename // Name used for brainworm-speak.
var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth.
var/controlling // Used in human death check.
+ var/docile = 0 // Sugar can stop borers from acting.
/mob/living/simple_animal/borer/Life()
..()
+
+
if(host)
+
if(!stat && !host.stat)
+
+ if(host.reagents.has_reagent("sugar"))
+ if(!docile)
+ if(controlling)
+ host << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility."
+ else
+ src << "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility."
+ docile = 1
+ else
+ if(docile)
+ if(controlling)
+ host << "\blue You shake off your lethargy as the sugar leaves your host's blood."
+ else
+ src << "\blue You shake off your lethargy as the sugar leaves your host's blood."
+ docile = 0
+
if(chemicals < 250)
chemicals++
if(controlling)
+
+ if(docile)
+ host << "\blue You are feeling far too docile to continue controlling your host..."
+ host.release_control()
+ return
+
if(prob(5))
host.adjustBrainLoss(rand(1,2))
if(prob(host.brainloss/20))
host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]")
- //if(host.brainloss > 100)
-
/mob/living/simple_animal/borer/New()
..()
truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]"
@@ -104,6 +135,13 @@
src << "You drop words into [host]'s mind: \"[message]\""
host << "Your own thoughts speak: \"[message]\""
+ for (var/mob/M in player_list)
+ if (istype(M, /mob/new_player))
+ continue
+ else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
+ M << "[src.truename] whispers to [host], \"[message]\""
+
+
/mob/living/simple_animal/borer/Stat()
..()
statpanel("Status")
@@ -127,6 +165,46 @@
if(M.mind && (istype(M, /mob/living/simple_animal/borer) || istype(M, /mob/dead/observer)))
M << "Cortical link, [truename]: [copytext(message, 2)]"
+/mob/living/simple_animal/borer/verb/dominate_victim()
+ set category = "Alien"
+ set name = "Dominate Victim"
+ set desc = "Freeze the limbs of a potential host with supernatural fear."
+
+ if(world.time - used_dominate < 300)
+ src << "You cannot use that ability again so soon."
+ return
+
+ if(host)
+ src << "You cannot do that from within a host body."
+ return
+
+ if(src.stat)
+ src << "You cannot do that in your current state."
+ return
+
+ var/list/choices = list()
+ for(var/mob/living/carbon/C in view(3,src))
+ if(C.stat != 2)
+ choices += C
+
+ if(world.time - used_dominate < 300)
+ src << "You cannot use that ability again so soon."
+ return
+
+ var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices
+
+ if(!M || !src) return
+
+ if(M.has_brain_worms())
+ src << "You cannot infest someone who is already infested!"
+ return
+
+ src << "\red You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread."
+ M << "\red You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing."
+ M.Weaken(3)
+
+ used_dominate = world.time
+
/mob/living/simple_animal/borer/verb/bond_brain()
set category = "Alien"
set name = "Assume Control"
@@ -140,12 +218,20 @@
src << "You cannot do that in your current state."
return
+ if(host.internal_organs_by_name["brain"]) //this should only run in admin-weirdness situations, but it's here non the less - RR
+ src << "There is no brain here for us to command!"
+ return
+
+ if(docile)
+ src << "\blue You are feeling far too docile to do that."
+ return
+
src << "You begin delicately adjusting your connection to the host brain..."
spawn(300+(host.brainloss*5))
- if(!host || !src || controlling) return
-
+ if(!host || !src || controlling)
+ return
else
src << "\red You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system."
host << "\red You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours."
@@ -170,10 +256,14 @@
if(stat)
src << "You cannot secrete chemicals in your current state."
+ if(docile)
+ src << "\blue You are feeling far too docile to do that."
+ return
+
if(chemicals < 50)
src << "You don't have enough chemicals!"
- var/chem = input("Select a chemical to secrete.", "Chemicals") in list("bicaridine","tramadol","hyperzine")
+ var/chem = input("Select a chemical to secrete.", "Chemicals") in list("bicaridine","tramadol","hyperzine","alkysine")
if(chemicals < 50 || !host || controlling || !src || stat) //Sanity check.
return
@@ -194,6 +284,9 @@
if(stat)
src << "You cannot leave your host in your current state."
+ if(docile)
+ src << "\blue You are feeling far too docile to do that."
+ return
if(!host || !src) return
@@ -262,17 +355,25 @@ mob/living/simple_animal/borer/proc/detatch()
var/list/choices = list()
for(var/mob/living/carbon/C in view(1,src))
- if(C.stat != 2)
+ if(C.stat != 2 && src.Adjacent(C))
choices += C
var/mob/living/carbon/M = input(src,"Who do you wish to infest?") in null|choices
if(!M || !src) return
+ if(!(src.Adjacent(M))) return
+
if(M.has_brain_worms())
src << "You cannot infest someone who is already infested!"
return
+ if(istype(M,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = M
+ if(H.check_head_coverage())
+ src << "You cannot get through that host's protective gear."
+ return
+
M << "Something slimy begins probing at the opening of your ear canal..."
src << "You slither up [M] and begin probing at their ear canal..."
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index af36a591626..491841ebada 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -27,6 +27,7 @@
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 323 //Above 50 Degrees Celcius
universal_speak = 0
+ universal_understand = 1
/mob/living/simple_animal/mouse/Life()
..()
@@ -50,6 +51,7 @@
/mob/living/simple_animal/mouse/New()
..()
+ name = "[name] ([rand(1, 1000)])"
if(!body_color)
body_color = pick( list("brown","gray","white") )
icon_state = "mouse_[body_color]"
@@ -63,6 +65,7 @@
src.stat = DEAD
src.icon_dead = "mouse_[body_color]_splat"
src.icon_state = "mouse_[body_color]_splat"
+ layer = MOB_LAYER
if(client)
client.time_died_as_mouse = world.time
@@ -179,6 +182,7 @@
..()
/mob/living/simple_animal/mouse/Die()
+ layer = MOB_LAYER
if(client)
client.time_died_as_mouse = world.time
..()
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 1c3498802d1..b6b7edb7298 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -24,6 +24,7 @@
log_access("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).")
/mob/Login()
+
player_list |= src
update_Login_details()
world.update_status()
@@ -44,4 +45,13 @@
client.eye = src
client.perspective = MOB_PERSPECTIVE
+ //Clear ability list and update from mob.
+ client.verbs -= ability_verbs
+ if(abilities)
+ client.verbs |= abilities
+
+ if(istype(src,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = src
+ if(H.species && H.species.abilities)
+ client.verbs |= H.species.abilities
\ No newline at end of file
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index dc984663dd2..ab6d6214877 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -84,10 +84,11 @@
var/lastpuke = 0
var/unacidable = 0
var/small = 0
- var/list/pinned = list() //List of things pinning this creature to walls (see living_defense.dm)
- var/list/embedded = list() //Embedded items, since simple mobs don't have organs.
+ var/list/pinned = list() // List of things pinning this creature to walls (see living_defense.dm)
+ var/list/embedded = list() // Embedded items, since simple mobs don't have organs.
var/list/languages = list() // For speaking/listening.
- var/list/speak_emote = list("says") //Verbs used when speaking. Defaults to 'say' if speak_emote is null.
+ var/list/abilities = list() // For species-derived or admin-given powers.
+ var/list/speak_emote = list("says") // Verbs used when speaking. Defaults to 'say' if speak_emote is null.
var/name_archive //For admin things like possession
@@ -206,6 +207,7 @@
//Whether or not mobs can understand other mobtypes. These stay in /mob so that ghosts can hear everything.
var/universal_speak = 0 // Set to 1 to enable the mob to speak to everyone -- TLE
+ var/universal_understand = 0 // Set to 1 to enable the mob to understand everyone, not necessarily speak
var/robot_talk_understand = 0
var/alien_talk_understand = 0
@@ -215,3 +217,5 @@
var/immune_to_ssd = 0
var/turf/listed_turf = null //the current turf being examined in the stat panel
+
+ var/list/active_genes=list()
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 62378036386..88c0c38f6ed 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -391,9 +391,13 @@
new_character.dna.b_type = client.prefs.b_type
if(client.prefs.disabilities)
- new_character.dna.struc_enzymes = setblock(new_character.dna.struc_enzymes,GLASSESBLOCK,toggledblock(getblock(new_character.dna.struc_enzymes,GLASSESBLOCK,3)),3)
+ // Set defer to 1 if you add more crap here so it only recalculates struc_enzymes once. - N3X
+ new_character.dna.SetSEState(GLASSESBLOCK,1,0)
new_character.disabilities |= NEARSIGHTED
+ // And uncomment this, too.
+ //new_character.dna.UpdateSE()
+
new_character.key = key //Manually transfer the key to log them in
return new_character
diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm
index d23c2407c9a..230eca4cdf7 100644
--- a/code/modules/mob/new_player/sprite_accessories.dm
+++ b/code/modules/mob/new_player/sprite_accessories.dm
@@ -7,7 +7,7 @@
Enjoy! - Doohl
- Notice: This all gets automatically compiled in a list in dna.dm, so you do not
+ Notice: This all gets automatically compiled in a list in dna2.dm, so you do not
have to define any UI values for sprite accessories manually for hair and facial
hair. Just add in new hair types and the game will naturally adapt.
@@ -61,6 +61,10 @@
name = "Cut Hair"
icon_state = "hair_c"
+ flair
+ name = "Flaired Hair"
+ icon_state = "hair_flair"
+
long
name = "Shoulder-length Hair"
icon_state = "hair_b"
@@ -420,7 +424,7 @@
una_frills_short
name = "Short Unathi Frills"
- icon_state = "soghun_shortfrill"
+ icon_state = "soghun_shortfrills"
species_allowed = list("Unathi")
do_colouration = 0
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index f4a99e097fd..040c1615c50 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -66,7 +66,7 @@
if(!other)
return 1
//Universal speak makes everything understandable, for obvious reasons.
- else if(other.universal_speak || src.universal_speak)
+ else if(other.universal_speak || src.universal_speak || src.universal_understand)
return 1
else if (src.stat == 2)
return 1
@@ -83,11 +83,11 @@
else
return 0
- else if(other.universal_speak || src.universal_speak)
+ else if(other.universal_speak || src.universal_speak || src.universal_understand)
return 1
else if(isAI(src) && ispAI(other))
return 1
- else if (istype(other, src.type) || istype(src, other.type))
+ else if (istype(other, src.type) || istype(src, other.type))
return 1
return 0
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 0015620cc57..5ae6f0a7a30 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -30,8 +30,10 @@
O = new species.primitive(loc)
O.dna = dna
- O.dna.uni_identity = "000000000000000000DC00000660004DA0A0E00"
- O.dna.struc_enzymes = "[copytext(O.dna.struc_enzymes,1,1+3*(STRUCDNASIZE-1))]BB8"
+ //O.dna.uni_identity = "000000000000000000DC00000660004DA0A0E00"
+ //O.dna.struc_enzymes = "[copytext(O.dna.struc_enzymes,1,1+3*(STRUCDNASIZE-1))]BB8"
+ O.dna.SetSEState(MONKEYBLOCK,1)
+ O.loc = loc
O.viruses = viruses
O.a_intent = "hurt"
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index 474e955f57a..a6a73004698 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -136,10 +136,13 @@ nanoui is used to open and update nano browser uis
close()
return
+
if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat))
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
else if (user.restrained() || user.lying)
set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
+ else if (istype(src_object, /obj/item/device/uplink/hidden)) // You know what if they have the uplink open let them use the UI
+ set_status(STATUS_INTERACTIVE, push_update) // Will build in distance checks on the topics for sanity.
else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
else if (dist <= 1)
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 3bd5348318a..abd5f1baf67 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -240,7 +240,7 @@ This function completely restores a damaged organ to perfect condition.
//Possibly trigger an internal wound, too.
var/local_damage = brute_dam + burn_dam + damage
- if(damage > 10 && type != BURN && local_damage > 20 && prob(damage) && !(status & ORGAN_ROBOT))
+ if(damage > 15 && type != BURN && local_damage > 30 && prob(damage) && !(status & ORGAN_ROBOT))
var/datum/wound/internal_bleeding/I = new (15)
wounds += I
owner.custom_pain("You feel something rip in your [display_name]!", 1)
@@ -875,8 +875,8 @@ obj/item/weapon/organ/head/New(loc, mob/living/carbon/human/H)
H.regenerate_icons()
- H.stat = 2
- H.death()
+ brainmob.stat = 2
+ brainmob.death()
obj/item/weapon/organ/head/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->head
brainmob = new(src)
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index 379377072bc..1c491c126da 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -61,7 +61,7 @@
if(href_list["remove"])
var/obj/item/P = locate(href_list["remove"])
- if(P)
+ if(P && P.loc == src)
P.loc = usr.loc
usr.put_in_hands(P)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 66cbc91419a..0845454b83a 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -227,6 +227,30 @@
\[hr\] : Adds a horizontal rule.