diff --git a/baystation12.dme b/baystation12.dme
index 34471cc192f..a5526a8f53e 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1249,6 +1249,7 @@
#include "code\modules\surgery\eye.dm"
#include "code\modules\surgery\face.dm"
#include "code\modules\surgery\generic.dm"
+#include "code\modules\surgery\headreattach.dm"
#include "code\modules\surgery\implant.dm"
#include "code\modules\surgery\other.dm"
#include "code\modules\surgery\ribcage.dm"
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index b5b6cf74233..c9dfd7cf403 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/cult_ghostwriter = 1 //Allows ghosts to write in blood in cult rounds...
+ var/cult_ghostwriter_req_cultists = 10 //...so long as this many cultists are active.
+
var/disable_player_mice = 0
var/uneducated_mice = 0 //Set to 1 to prevent newly-spawned mice from understanding human speech
@@ -455,10 +458,15 @@
else //probably windows, if not this should work anyway
config.python_path = "python"
+ if("allow_cult_ghostwriter")
+ config.cult_ghostwriter = 1
+
+ if("req_cult_ghostwriter")
+ config.cult_ghostwriter_req_cultists = value
+
else
diary << "Unknown setting in configuration: '[name]'"
-
else if(type == "game_options")
if(!value)
diary << "Unknown value for setting [name] in [filename]."
diff --git a/code/game/gamemodes/blob/blobs/shield.dm b/code/game/gamemodes/blob/blobs/shield.dm
index 4c77520846a..0e1b6c07eb4 100644
--- a/code/game/gamemodes/blob/blobs/shield.dm
+++ b/code/game/gamemodes/blob/blobs/shield.dm
@@ -6,7 +6,7 @@
density = 1
opacity = 0
anchored = 1
- health = 100
+ health = 60
brute_resist = 1
fire_resist = 2
diff --git a/code/game/gamemodes/events/holidays/Christmas.dm b/code/game/gamemodes/events/holidays/Christmas.dm
index 2ee79e7c65b..72d42318e60 100644
--- a/code/game/gamemodes/events/holidays/Christmas.dm
+++ b/code/game/gamemodes/events/holidays/Christmas.dm
@@ -4,8 +4,8 @@
for(var/turf/simulated/floor/T in orange(1,xmas))
for(var/i=1,i<=rand(1,5),i++)
new /obj/item/weapon/a_gift(T)
- for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list)
- Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
+ //for(var/mob/living/simple_animal/corgi/Ian/Ian in mob_list)
+ // Ian.place_on_head(new /obj/item/clothing/head/helmet/space/santahat(Ian))
/proc/ChristmasEvent()
for(var/obj/structure/flora/tree/pine/xmas in world)
diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm
index c8848cd3ee8..dbebc649f53 100644
--- a/code/game/gamemodes/events/power_failure.dm
+++ b/code/game/gamemodes/events/power_failure.dm
@@ -61,7 +61,7 @@
if(C.cell && C.z == 1)
C.cell.charge = C.cell.maxcharge
for(var/obj/machinery/power/smes/S in world)
- if(S.z != 1)
+ if(istype(get_area(S), /area/turret_protected) || S.z != 1)
continue
S.charge = S.last_charge
S.output = S.last_output
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index 24a3df847a5..a58e8b553ff 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -82,6 +82,10 @@ var/bomb_set
flick("nuclearbombc", src)
return
+ if (istype(O, /obj/item/weapon/wirecutters) || istype(O, /obj/item/device/multitool))
+ if (src.opened == 1)
+ nukehack_win(user)
+ return
if (src.extended)
if (istype(O, /obj/item/weapon/disk/nuclear))
diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm
index 88b785b5c0d..e0a74e97223 100644
--- a/code/game/machinery/bots/cleanbot.dm
+++ b/code/game/machinery/bots/cleanbot.dm
@@ -194,7 +194,7 @@ text("[src.oddbutton ? "Yes" : "No"
if(!src.target || src.target == null)
for (var/obj/effect/decal/cleanable/D in view(7,src))
for(var/T in src.target_types)
- if(!(D in cleanbottargets) && (D.type == T || D.parent_type == T) && D != src.oldtarget)
+ if(!(D in cleanbottargets) && istype(D,T) && D != src.oldtarget)
src.oldtarget = D
src.target = D
return
@@ -293,17 +293,12 @@ text("[src.oddbutton ? "Yes" : "No"
/obj/machinery/bot/cleanbot/proc/get_targets()
src.target_types = new/list()
- target_types += /obj/effect/decal/cleanable/blood/oil
+ target_types += /obj/effect/decal/cleanable/blood
target_types += /obj/effect/decal/cleanable/vomit
- target_types += /obj/effect/decal/cleanable/blood/robot
target_types += /obj/effect/decal/cleanable/crayon
target_types += /obj/effect/decal/cleanable/liquid_fuel
target_types += /obj/effect/decal/cleanable/mucus
-
- if(src.blood)
- target_types += /obj/effect/decal/cleanable/blood/
- target_types += /obj/effect/decal/cleanable/blood/gibs/
- target_types += /obj/effect/decal/cleanable/dirt
+ target_types += /obj/effect/decal/cleanable/dirt
/obj/machinery/bot/cleanbot/proc/clean(var/obj/effect/decal/cleanable/target)
src.anchored = 1
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index d7bb61c0be4..62e7376c4d4 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -52,6 +52,8 @@
var/const/WIRE_SHOCK = 3
var/const/WIRE_SHOOTINV = 4
+ var/check_accounts = 0 // 1 = requires PIN and checks accounts. 0 = You slide an ID, it vends, SPACE COMMUNISM!
+
/obj/machinery/vending/New()
..()
spawn(4)
@@ -164,46 +166,51 @@
if (istype(I, /obj/item/weapon/card/id))
var/obj/item/weapon/card/id/C = I
visible_message("[usr] swipes a card through [src].")
- if(vendor_account)
- var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
- var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2)
- if(D)
- var/transaction_amount = currently_vending.price
- if(transaction_amount <= D.money)
+ if(check_accounts)
+ if(vendor_account)
+ var/attempt_pin = input("Enter pin code", "Vendor transaction") as num
+ var/datum/money_account/D = attempt_account_access(C.associated_account_number, attempt_pin, 2)
+ if(D)
+ var/transaction_amount = currently_vending.price
+ if(transaction_amount <= D.money)
+
+ //transfer the money
+ D.money -= transaction_amount
+ vendor_account.money += transaction_amount
- //transfer the money
- D.money -= transaction_amount
- vendor_account.money += transaction_amount
-
- //create entries in the two account transaction logs
- var/datum/transaction/T = new()
- T.target_name = "[vendor_account.owner_name] (via [src.name])"
- T.purpose = "Purchase of [currently_vending.product_name]"
- if(transaction_amount > 0)
- T.amount = "([transaction_amount])"
- else
+ //create entries in the two account transaction logs
+ var/datum/transaction/T = new()
+ T.target_name = "[vendor_account.owner_name] (via [src.name])"
+ T.purpose = "Purchase of [currently_vending.product_name]"
+ if(transaction_amount > 0)
+ T.amount = "([transaction_amount])"
+ else
+ T.amount = "[transaction_amount]"
+ T.source_terminal = src.name
+ T.date = current_date_string
+ T.time = worldtime2text()
+ D.transaction_log.Add(T)
+ //
+ T = new()
+ T.target_name = D.owner_name
+ T.purpose = "Purchase of [currently_vending.product_name]"
T.amount = "[transaction_amount]"
- T.source_terminal = src.name
- T.date = current_date_string
- T.time = worldtime2text()
- D.transaction_log.Add(T)
- //
- T = new()
- T.target_name = D.owner_name
- T.purpose = "Purchase of [currently_vending.product_name]"
- T.amount = "[transaction_amount]"
- T.source_terminal = src.name
- T.date = current_date_string
- T.time = worldtime2text()
- vendor_account.transaction_log.Add(T)
+ T.source_terminal = src.name
+ T.date = current_date_string
+ T.time = worldtime2text()
+ vendor_account.transaction_log.Add(T)
- // Vend the item
- src.vend(src.currently_vending, usr)
- currently_vending = null
+ // Vend the item
+ src.vend(src.currently_vending, usr)
+ currently_vending = null
+ else
+ usr << "\icon[src]You don't have that much money!"
else
- usr << "\icon[src]You don't have that much money!"
+ usr << "\icon[src]Unable to access account. Check security settings and try again."
else
- usr << "\icon[src]Unable to access account. Check security settings and try again."
+ //Just Vend it.
+ src.vend(src.currently_vending, usr)
+ currently_vending = null
else
usr << "\icon[src]Unable to access vendor account. Please record the machine ID and call CentComm Support."
diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm
index 00044afb58e..957369f3bf6 100644
--- a/code/game/objects/effects/decals/Cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/Cleanable/aliens.dm
@@ -1,53 +1,30 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-
/obj/effect/decal/cleanable/blood/xeno
name = "xeno blood"
desc = "It's green and acidic. It looks like... blood?"
icon = 'icons/effects/blood.dmi'
- icon_state = "xfloor1"
basecolor = "#05EE05"
- random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
-/obj/effect/decal/cleanable/blood/xeno/proc/streak(var/list/directions)
- spawn (0)
- var/direction = pick(directions)
- for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
- sleep(3)
- if (i > 0)
- var/obj/effect/decal/cleanable/blood/xeno/b = new /obj/effect/decal/cleanable/blood/xeno/xsplatter(src.loc)
- for(var/datum/disease/D in src.viruses)
- var/datum/disease/ND = D.Copy(1)
- b.viruses += ND
- ND.holder = b
- if (step_to(src, get_step(src, direction), 0))
- break
-
-/obj/effect/decal/cleanable/blood/xeno/xsplatter
- random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5")
-
-/obj/effect/decal/cleanable/blood/xeno/xgibs
+/obj/effect/decal/cleanable/blood/gibs/xeno
name = "xeno gibs"
desc = "Gnarly..."
- gender = PLURAL
- icon = 'icons/effects/blood.dmi'
icon_state = "xgib1"
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6")
+ basecolor = "#05EE05"
-/obj/effect/decal/cleanable/blood/xeno/xgibs/up
+/obj/effect/decal/cleanable/blood/gibs/xeno/up
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1")
-/obj/effect/decal/cleanable/blood/xeno/xgibs/down
+/obj/effect/decal/cleanable/blood/gibs/xeno/down
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibdown1","xgibdown1","xgibdown1")
-/obj/effect/decal/cleanable/blood/xeno/xgibs/body
+/obj/effect/decal/cleanable/blood/gibs/xeno/body
random_icon_states = list("xgibhead", "xgibtorso")
-/obj/effect/decal/cleanable/blood/xeno/xgibs/limb
+/obj/effect/decal/cleanable/blood/gibs/xeno/limb
random_icon_states = list("xgibleg", "xgibarm")
-/obj/effect/decal/cleanable/blood/xeno/xgibs/core
+/obj/effect/decal/cleanable/blood/gibs/xeno/core
random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3")
/obj/effect/decal/cleanable/blood/xtracks
- icon_state = "xtracks"
- random_icon_states = null
\ No newline at end of file
+ basecolor = "#05EE05"
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm
index c73291bc214..f971cb45c66 100644
--- a/code/game/objects/effects/decals/Cleanable/humans.dm
+++ b/code/game/objects/effects/decals/Cleanable/humans.dm
@@ -25,7 +25,7 @@ var/global/list/image/splatter_cache=list()
/obj/effect/decal/cleanable/blood/New()
..()
- color = basecolor
+ update_icon()
if(istype(src, /obj/effect/decal/cleanable/blood/gibs))
return
if(istype(src, /obj/effect/decal/cleanable/blood/tracks))
@@ -116,13 +116,16 @@ var/global/list/image/splatter_cache=list()
/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)
+ if(random_icon_states.len)
+ for(var/obj/effect/decal/cleanable/blood/writing/W in loc)
+ random_icon_states.Remove(W.icon_state)
+ icon_state = pick(random_icon_states)
+ else
+ icon_state = "writing1"
/obj/effect/decal/cleanable/blood/writing/examine()
..()
- usr << "It reads: \"[message]\""
+ usr << "It reads: \"[message]\""
/obj/effect/decal/cleanable/blood/gibs
name = "gibs"
@@ -135,6 +138,12 @@ var/global/list/image/splatter_cache=list()
icon_state = "gibbl5"
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
+/obj/effect/decal/cleanable/blood/gibs/update_icon()
+ color = "#FFFFFF"
+ //overlays.Cut()
+ //..()
+ //overlays += image(icon, src, "[icon_state]_flesh")
+
/obj/effect/decal/cleanable/blood/gibs/up
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
@@ -159,6 +168,7 @@ var/global/list/image/splatter_cache=list()
if (i > 0)
var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc)
b.basecolor = src.basecolor
+ b.update_icon()
for(var/datum/disease/D in src.viruses)
var/datum/disease/ND = D.Copy(1)
b.viruses += ND
diff --git a/code/game/objects/effects/decals/Cleanable/misc.dm b/code/game/objects/effects/decals/Cleanable/misc.dm
index 67c82a8f440..0b257a3e111 100644
--- a/code/game/objects/effects/decals/Cleanable/misc.dm
+++ b/code/game/objects/effects/decals/Cleanable/misc.dm
@@ -16,6 +16,13 @@
icon_state = "ash"
anchored = 1
+/obj/effect/decal/cleanable/ash/attack_hand(mob/user as mob)
+ user << "[src] sifts through your fingers."
+ var/turf/simulated/floor/F = get_turf(src)
+ if (istype(F))
+ F.dirt += 4
+ del(src)
+
/obj/effect/decal/cleanable/greenglow
New()
diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm
index f76f4863b6b..43a6c1954eb 100644
--- a/code/game/objects/effects/decals/Cleanable/robots.dm
+++ b/code/game/objects/effects/decals/Cleanable/robots.dm
@@ -1,29 +1,23 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-
-/obj/effect/decal/cleanable/blood/robot
+/obj/effect/decal/cleanable/blood/gibs/robot
name = "robot debris"
desc = "It's a useless heap of junk... or is it?"
icon = 'icons/mob/robots.dmi'
icon_state = "gib1"
- basecolor="#2B2B2B"
+ basecolor="#030303"
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
-/obj/effect/decal/cleanable/blood/robot/dry() //pieces of robots do not dry up like
+/obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like
return
-/obj/effect/decal/cleanable/blood/robot/update_icon()
- color = "#FFFFFF"
- return
-
-/obj/effect/decal/cleanable/blood/robot/proc/streak(var/list/directions)
+/obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions)
spawn (0)
var/direction = pick(directions)
for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++)
sleep(3)
if (i > 0)
if (prob(40))
- /*var/obj/effect/decal/cleanable/oil/o =*/
- new /obj/effect/decal/cleanable/blood/oil/streak(src.loc)
+ var/obj/effect/decal/cleanable/blood/oil/streak = new(src.loc)
+ streak.update_icon()
else if (prob(10))
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
@@ -31,22 +25,23 @@
if (step_to(src, get_step(src, direction), 0))
break
-/obj/effect/decal/cleanable/blood/robot/limb
+/obj/effect/decal/cleanable/blood/gibs/robot/limb
random_icon_states = list("gibarm", "gibleg")
-/obj/effect/decal/cleanable/blood/robot/up
+/obj/effect/decal/cleanable/blood/gibs/robot/up
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1") //2:7 is close enough to 1:4
-/obj/effect/decal/cleanable/blood/robot/down
+/obj/effect/decal/cleanable/blood/gibs/robot/down
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1") //2:7 is close enough to 1:4
/obj/effect/decal/cleanable/blood/oil
name = "motor oil"
desc = "It's black and greasy. Looks like Beepsky made another mess."
- basecolor="#3B3B3B"
- icon = 'icons/mob/robots.dmi'
- icon_state = "floor1"
- random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
+ basecolor="#030303"
+
+/obj/effect/decal/cleanable/blood/oil/dry()
+ return
/obj/effect/decal/cleanable/blood/oil/streak
- random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
\ No newline at end of file
+ random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5")
+ amount = 2
\ No newline at end of file
diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm
index 70ddaed1d3d..5446ba348e6 100644
--- a/code/game/objects/effects/spawners/gibspawner.dm
+++ b/code/game/objects/effects/spawners/gibspawner.dm
@@ -17,7 +17,7 @@
..()
xeno
- gibtypes = list(/obj/effect/decal/cleanable/blood/xeno/xgibs/up,/obj/effect/decal/cleanable/blood/xeno/xgibs/down,/obj/effect/decal/cleanable/blood/xeno/xgibs,/obj/effect/decal/cleanable/blood/xeno/xgibs,/obj/effect/decal/cleanable/blood/xeno/xgibs/body,/obj/effect/decal/cleanable/blood/xeno/xgibs/limb,/obj/effect/decal/cleanable/blood/xeno/xgibs/core)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/xeno/up,/obj/effect/decal/cleanable/blood/gibs/xeno/down,/obj/effect/decal/cleanable/blood/gibs/xeno,/obj/effect/decal/cleanable/blood/gibs/xeno,/obj/effect/decal/cleanable/blood/gibs/xeno/body,/obj/effect/decal/cleanable/blood/gibs/xeno/limb,/obj/effect/decal/cleanable/blood/gibs/xeno/core)
gibamounts = list(1,1,1,1,1,1,1)
New()
@@ -27,7 +27,7 @@
robot
sparks = 1
- gibtypes = list(/obj/effect/decal/cleanable/blood/robot/up,/obj/effect/decal/cleanable/blood/robot/down,/obj/effect/decal/cleanable/blood/robot,/obj/effect/decal/cleanable/blood/robot,/obj/effect/decal/cleanable/blood/robot,/obj/effect/decal/cleanable/blood/robot/limb)
+ gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/robot/up,/obj/effect/decal/cleanable/blood/gibs/robot/down,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot,/obj/effect/decal/cleanable/blood/gibs/robot/limb)
gibamounts = list(1,1,1,1,1,1)
New()
diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm
index e04ab62671e..4e42765238d 100644
--- a/code/game/objects/items/devices/uplinks.dm
+++ b/code/game/objects/items/devices/uplinks.dm
@@ -7,8 +7,10 @@ A list of items and costs is stored under the datum of every game mode, alongsid
*/
/obj/item/device/uplink
+
var/welcome // Welcoming menu message
var/items // List of items
+ var/valid_items = list()
var/item_data // raw item text
var/list/ItemList // Parsed list of items
var/uses // Numbers of crystals
@@ -58,6 +60,12 @@ A list of items and costs is stored under the datum of every game mode, alongsid
+ //Halfassed fix for href exploit ~Z
+ for(var/D in ItemList)
+ var/list/O = stringsplit(D, ":")
+ if(O.len>0)
+ valid_items += O[1]
+
//Let's build a menu!
/obj/item/device/uplink/proc/generate_menu()
@@ -87,7 +95,7 @@ A list of items and costs is stored under the datum of every game mode, alongsid
continue
path_text = O[1]
- cost = text2num(O[2])
+ cost = Clamp(text2num(O[2]),1,20) //Another halfassed fix for href exploit ~Z
if(cost>uses)
continue
@@ -378,7 +386,12 @@ A list of items and costs is stored under the datum of every game mode, alongsid
return 1
if(..(href, href_list) == 1)
+
+ if(!(href_list["buy_item"] in valid_items))
+ return
+
var/path_obj = text2path(href_list["buy_item"])
+
var/obj/I = new path_obj(get_turf(usr))
if(ishuman(usr))
var/mob/living/carbon/human/A = usr
@@ -427,6 +440,3 @@ A list of items and costs is stored under the datum of every game mode, alongsid
..()
hidden_uplink = new(src)
hidden_uplink.uses = 10
-
-
-
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 884b0671eed..98efacef1a3 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -65,6 +65,7 @@ var/list/admin_verbs_admin = list(
/client/proc/cmd_admin_rejuvenate,
/client/proc/toggleattacklogs,
/client/proc/toggledebuglogs,
+ /client/proc/toggleghostwriters,
/datum/admins/proc/show_skills,
/client/proc/check_customitem_activity,
/client/proc/man_up,
@@ -724,6 +725,21 @@ var/list/admin_verbs_mod = list(
usr << "You now won't get attack log messages"
+/client/proc/toggleghostwriters()
+ set name = "Toggle ghost writers"
+ set category = "Server"
+ if(!holder) return
+ if(config)
+ if(config.cult_ghostwriter)
+ config.cult_ghostwriter = 0
+ src << "Disallowed ghost writers."
+ message_admins("Admin [key_name_admin(usr)] has disabled ghost writers.", 1)
+ else
+ config.cult_ghostwriter = 1
+ src << "Enabled ghost writers."
+ message_admins("Admin [key_name_admin(usr)] has enabled ghost writers.", 1)
+
+
/client/proc/toggledebuglogs()
set name = "Toggle Debug Log Messages"
set category = "Preferences"
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index 1b55ca6b039..87ed4787058 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -479,7 +479,6 @@
dat += "
Show Objective | "
dat += ""
- /*
if(ticker.mode.ninjas.len > 0)
dat += "
| Ninjas | | |
"
for(var/datum/mind/ninja in ticker.mode.ninjas)
@@ -491,7 +490,6 @@
else
dat += "| Ninja not found! |
"
dat += "
"
- */
if(ticker.mode.cult.len)
dat += "
| Cultists | |
"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 153451431c7..304e96b0fad 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1122,6 +1122,8 @@ datum/preferences
UI_style = "Orange"
if("Orange")
UI_style = "old"
+ if("old")
+ UI_style = "White"
else
UI_style = "Midnight"
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index b61c1224794..9627c55d824 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -21,6 +21,7 @@
var/antagHUD = 0
universal_speak = 1
var/atom/movable/following = null
+
/mob/dead/observer/New(mob/body)
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
see_invisible = SEE_INVISIBLE_OBSERVER
@@ -496,3 +497,79 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
dat += data_core.get_manifest()
src << browse(dat, "window=manifest;size=370x420;can_close=1")
+
+//Used for drawing on walls with blood puddles as a spooky ghost.
+/mob/dead/verb/bloody_doodle()
+
+ set category = "Ghost"
+ set name = "Write in blood"
+ set desc = "If the round is sufficiently spooky, write a short message in blood on the floor or a wall. Remember, no IC in OOC or OOC in IC."
+
+ if(!(config.cult_ghostwriter))
+ src << "\red That verb is not currently permitted."
+ return
+
+ if (!src.stat)
+ return
+
+ if (usr != src)
+ return 0 //something is terribly wrong
+
+ var/ghosts_can_write
+ if(ticker.mode.name == "cult")
+ var/datum/game_mode/cult/C = ticker.mode
+ if(C.cult.len > config.cult_ghostwriter_req_cultists)
+ ghosts_can_write = 1
+
+ if(!ghosts_can_write)
+ src << "\red The veil is not thin enough for you to do that."
+ return
+
+ var/list/choices = list()
+ for(var/obj/effect/decal/cleanable/blood/B in view(1,src))
+ if(B.amount > 0)
+ choices += B
+
+ if(!choices.len)
+ src << "There is no blood to use nearby."
+ return
+
+ var/obj/effect/decal/cleanable/blood/choice = input(src,"What blood would you like to use?") in null|choices
+
+ var/direction = input(src,"Which way?","Tile selection") as anything in list("Here","North","South","East","West")
+ var/turf/simulated/T = src.loc
+ if (direction != "Here")
+ T = get_step(T,text2dir(direction))
+
+ if (!istype(T))
+ src << "You cannot doodle there."
+ return
+
+ if(!choice || choice.amount == 0 || !(src.Adjacent(choice)))
+ return
+
+ var/doodle_color = (choice.basecolor) ? choice.basecolor : "#A10808"
+
+ 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 = 50
+
+ var/message = stripped_input(src,"Write a message. It cannot be longer than [max_length] characters.","Blood writing", "")
+
+ if (message)
+
+ 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.basecolor = doodle_color
+ W.update_icon()
+ W.message = message
+ W.add_hiddenprint(src)
+ W.visible_message("\red Invisible fingers crudely paint something in blood on [T]...")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index 546a9231456..6063f544d62 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -520,7 +520,7 @@ proc/get_damage_icon_part(damage_state, body_part)
else
if(blood_DNA)
var/image/bloodsies = image("icon" = 'icons/effects/blood.dmi', "icon_state" = "bloodyhands")
- bloodsies.color = blood_color
+ bloodsies.color = hand_blood_color
overlays_standing[GLOVES_LAYER] = bloodsies
else
overlays_standing[GLOVES_LAYER] = null
diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm
index 0141d9c5c1a..8c98daaa872 100644
--- a/code/modules/mob/living/simple_animal/friendly/corgi.dm
+++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm
@@ -22,6 +22,7 @@
var/obj/item/inventory_back
var/facehugger
+/*
/mob/living/simple_animal/corgi/Life()
..()
regenerate_icons()
@@ -253,6 +254,7 @@
if(/obj/item/clothing/head/soft)
name = "Corgi Tech [real_name]"
desc = "The reason your yellow gloves have chew-marks."
+*/
//IAN! SQUEEEEEEEEE~
diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm
index 6fd7db5d10e..b375755f546 100644
--- a/code/modules/mob/living/simple_animal/hostile/bear.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bear.dm
@@ -79,7 +79,7 @@
if(stance_step in list(1,4,7)) //every 3 ticks
var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) )
if(action)
- emote(action)
+ custom_emote(1,action)
if(!found_mob)
stance_step--
@@ -90,7 +90,7 @@
if(HOSTILE_STANCE_ATTACKING)
if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest
- emote( "is worn out and needs to rest" )
+ custom_emote(1, "is worn out and needs to rest" )
stance = HOSTILE_STANCE_TIRED
stance_step = 0
walk(src, 0) //This stops the bear's walking
@@ -118,14 +118,16 @@
/mob/living/simple_animal/hostile/bear/FindTarget()
. = ..()
if(.)
- emote("stares alertly at [.]")
+ custom_emote(1,"stares alertly at [.]")
stance = HOSTILE_STANCE_ALERT
/mob/living/simple_animal/hostile/bear/LoseTarget()
..(5)
/mob/living/simple_animal/hostile/bear/AttackingTarget()
- emote( pick( list("slashes at [target_mob]", "bites [target_mob]") ) )
+ if(!Adjacent(target_mob))
+ return
+ custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) )
var/damage = rand(20,30)
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index 353ca6156f3..f1a5c15c4b9 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -44,7 +44,7 @@
/mob/living/simple_animal/hostile/carp/FindTarget()
. = ..()
if(.)
- emote("nashes at [.]")
+ custom_emote(1,"nashes at [.]")
/mob/living/simple_animal/hostile/carp/AttackingTarget()
. =..()
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
index 88aa24d29e2..cdefaa644e7 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
@@ -47,7 +47,7 @@
/mob/living/simple_animal/hostile/hivebot/Die()
..()
visible_message("[src] blows apart!")
- new /obj/effect/decal/cleanable/blood/robot(src.loc)
+ new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 403c31b17f2..2dcbe0d949f 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -87,6 +87,8 @@
return 1
/mob/living/simple_animal/hostile/proc/AttackingTarget()
+ if(!Adjacent(target_mob))
+ return
if(isliving(target_mob))
var/mob/living/L = target_mob
L.attack_animal(src)
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index bb3bbcdb3dc..560590cbad0 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -218,6 +218,7 @@
if (istype(user, /mob/living/silicon) && get_dist(src,user)>1)
return src.attack_hand(user)
+ src.add_fingerprint(user)
if (istype(W, /obj/item/weapon/crowbar) && opened)
if (has_electronics==1)
if (terminal)
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 685122e05c5..18be233b9b9 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -51,6 +51,9 @@
if(istype(A, /obj/item/ammo_magazine))
if((load_method == MAGAZINE) && loaded.len) return
var/obj/item/ammo_magazine/AM = A
+ if(AM.stored_ammo.len <= 0)
+ user << "The magazine is empty!"
+ return
for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
if(loaded.len >= max_shells)
break
@@ -93,6 +96,7 @@
AM.loc = get_turf(src)
empty_mag = null
update_icon()
+ AM.update_icon()
user << "\blue You unload magazine from \the [src]!"
else
user << "\red Nothing loaded in \the [src]!"
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index 0b3145cb9a5..07bf9bd0f6c 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -89,6 +89,7 @@
if(!loaded.len && empty_mag)
empty_mag.loc = get_turf(src.loc)
empty_mag = null
+ user << "The Magazine falls out and clatters on the floor!"
return
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index 96e037a23a6..17f8d1ce11e 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -12,7 +12,7 @@
var/filled = 0
afterattack(obj/target, mob/user , flag)
- if(!target.reagents) return
+ if(!target.reagents || !flag) return
if(filled)
@@ -105,4 +105,4 @@
////////////////////////////////////////////////////////////////////////////////
/// Droppers. END
-////////////////////////////////////////////////////////////////////////////////
\ No newline at end of file
+////////////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 3a0a200efa2..04eff0de6ea 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -1325,7 +1325,7 @@
src.streak(dirs)
-/obj/effect/decal/cleanable/blood/robot/gib/pipe_eject(var/direction)
+/obj/effect/decal/cleanable/blood/gibs/robot/pipe_eject(var/direction)
var/list/dirs
if(direction)
dirs = list( direction, turn(direction, -45), turn(direction, 45))
diff --git a/config/example/config.txt b/config/example/config.txt
index fb320da581a..1075a5ab677 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -229,3 +229,9 @@ USEALIENWHITELIST
## Path to the python2 executable on the system. Leave blank for default.
## Default is "python" on Windows, "/usr/bin/env python2" on UNIX.
#PYTHON_PATH
+
+## Uncommen to allow ghosts to write in blood during Cult rounds.
+ALLOW_CULT_GHOSTWRITER
+
+## Sets the minimum number of cultists needed for ghosts to write in blood.
+REQ_CULT_GHOSTWRITER 6
\ No newline at end of file
diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi
index 74ee727581e..6f634b9447b 100644
Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ
diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi
index 84aa670c5a1..05f5f846a73 100644
Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ
diff --git a/maps/tgstation2.dmm b/maps/tgstation2.dmm
index d8655a8517a..5b0ab4a0118 100644
--- a/maps/tgstation2.dmm
+++ b/maps/tgstation2.dmm
@@ -935,7 +935,7 @@
"arY" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold{pipe_color = "red"; dir = 1; icon_state = "manifold-r-f"; level = 1; name = "pipe manifold"},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fsmaint)
"arZ" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/fsmaint)
"asa" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fsmaint)
-"asb" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/effect/decal/cleanable/blood/robot,/obj/machinery/space_heater,/turf/simulated/floor/plating,/area/maintenance/fsmaint)
+"asb" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/effect/decal/cleanable/blood/gibs/robot,/obj/machinery/space_heater,/turf/simulated/floor/plating,/area/maintenance/fsmaint)
"asc" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 10},/turf/simulated/wall,/area/maintenance/fsmaint)
"asd" = (/obj/structure/rack{dir = 1},/obj/item/clothing/suit/fire/firefighter,/obj/item/weapon/tank/oxygen,/obj/item/clothing/mask/gas,/obj/item/weapon/extinguisher,/obj/item/clothing/head/hardhat/red,/obj/item/clothing/glasses/meson,/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 10},/area/maintenance/fsmaint)
"ase" = (/obj/machinery/atmospherics/portables_connector{dir = 1},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 6},/area/maintenance/fsmaint)