diff --git a/.travis.yml b/.travis.yml
index 0eccf6708e..56fa54f58d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,7 +27,6 @@ matrix:
addons:
apt:
packages:
- - libc6-i386
- libstdc++6:i386
cache:
directories:
@@ -39,7 +38,6 @@ matrix:
mariadb: '10.2'
apt:
packages:
- - libc6-i386
- libstdc++6:i386
- libssl-dev:i386
- gcc-multilib
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 13fcc94b4b..a0051c3b1e 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -203,21 +203,20 @@
//Print a list of antagonists to the server log
var/list/total_antagonists = list()
//Look into all mobs in world, dead or alive
- for(var/datum/mind/Mind in minds)
- var/temprole = Mind.special_role
- if(temprole) //if they are an antagonist of some sort.
- if(temprole in total_antagonists) //If the role exists already, add the name to it
- total_antagonists[temprole] += ", [Mind.name]([Mind.key])"
- else
- total_antagonists.Add(temprole) //If the role doesnt exist in the list, create it and add the mob
- total_antagonists[temprole] += ": [Mind.name]([Mind.key])"
+ for(var/datum/antagonist/A in GLOB.antagonists)
+ if(!A.owner)
+ continue
+ if(!(A.name in total_antagonists))
+ total_antagonists[A.name] = list()
+ total_antagonists[A.name] += "[key_name(A.owner)]"
CHECK_TICK
//Now print them all into the log!
log_game("Antagonists at round end were...")
- for(var/i in total_antagonists)
- log_game("[i]s[total_antagonists[i]].")
+ for(var/antag_name in total_antagonists)
+ var/list/L = total_antagonists[antag_name]
+ log_game("[antag_name]s :[L.Join(", ")].")
CHECK_TICK
SSdbcore.SetRoundEnd()
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index bb2cb98cd2..5b9bb8c184 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -375,6 +375,7 @@ Turf and target are separate in case you want to teleport some distance from a t
var/client/C
var/key
var/ckey
+ var/fallback_name
if(!whom)
return "*null*"
@@ -394,6 +395,16 @@ Turf and target are separate in case you want to teleport some distance from a t
C = GLOB.directory[ckey]
if(C)
M = C.mob
+ else if(istype(whom,/datum/mind))
+ var/datum/mind/mind = whom
+ key = mind.key
+ ckey = ckey(key)
+ if(mind.current)
+ M = mind.current
+ if(M.client)
+ C = M.client
+ else
+ fallback_name = mind.name
else
return "*invalid*"
@@ -419,11 +430,14 @@ Turf and target are separate in case you want to teleport some distance from a t
else
. += "*no key*"
- if(include_name && M)
- if(M.real_name)
- . += "/([M.real_name])"
- else if(M.name)
- . += "/([M.name])"
+ if(include_name)
+ if(M)
+ if(M.real_name)
+ . += "/([M.real_name])"
+ else if(M.name)
+ . += "/([M.name])"
+ else if(fallback_name)
+ . += "/([fallback_name])"
return .
diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm
index 0e1f1fb8fd..88423e8b6d 100644
--- a/code/controllers/subsystem/dbcore.dm
+++ b/code/controllers/subsystem/dbcore.dm
@@ -237,11 +237,29 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
item = list()
_db_query = _dm_db_new_query()
+/datum/DBQuery/Destroy()
+ Close()
+ SSdbcore.active_queries -= src
+ return ..()
+
+/datum/DBQuery/CanProcCall(proc_name)
+ //fuck off kevinz
+ return FALSE
+
+/datum/DBQuery/proc/Activity(activity)
+ last_activity = activity
+ last_activity_time = world.time
+
/datum/DBQuery/proc/warn_execute()
. = Execute()
if(!.)
to_chat(usr, "A SQL error occurred during this operation, check the server logs.")
+/datum/DBQuery/proc/SetQuery(new_sql)
+ Activity("SetQuery")
+ Close()
+ sql = new_sql
+
/datum/DBQuery/proc/Execute(sql_query = sql, cursor_handler = default_cursor, log_error = TRUE)
var/start_time
var/timeout = CONFIG_GET(number/query_debug_log_timeout)
diff --git a/code/controllers/subsystem/processing/circuit.dm b/code/controllers/subsystem/processing/circuit.dm
index db1bf1ff5f..dad71a005a 100644
--- a/code/controllers/subsystem/processing/circuit.dm
+++ b/code/controllers/subsystem/processing/circuit.dm
@@ -78,5 +78,8 @@ PROCESSING_SUBSYSTEM_DEF(circuit)
/obj/item/integrated_electronics/wirer,
/obj/item/integrated_electronics/debugger,
/obj/item/integrated_electronics/analyzer,
- /obj/item/integrated_electronics/detailer
+ /obj/item/integrated_electronics/detailer,
+ /obj/item/card/data,
+ /obj/item/card/data/full_color,
+ /obj/item/card/data/disk
)
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 445ed389b7..d1e3de1248 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -45,8 +45,9 @@
/obj/machinery/computer/communications/process()
if(..())
- if(state != STATE_STATUSDISPLAY && state != STATE_CALLSHUTTLE && state != STATE_PURCHASE && state != STATE_VIEWMESSAGE)
- updateDialog()
+ var/ai_autoupdate = aistate != STATE_STATUSDISPLAY && aistate != STATE_CALLSHUTTLE && aistate != STATE_PURCHASE && aistate != STATE_VIEWMESSAGE
+ var/machine_user_autoupdate = state != STATE_STATUSDISPLAY && state != STATE_CALLSHUTTLE && state != STATE_PURCHASE && state != STATE_VIEWMESSAGE
+ updateDialog(machine_user_autoupdate,ai_autoupdate)
/obj/machinery/computer/communications/Topic(href, href_list)
if(..())
diff --git a/code/game/objects/effects/bump_teleporter.dm b/code/game/objects/effects/bump_teleporter.dm
index 42f59cc535..307a912fe3 100644
--- a/code/game/objects/effects/bump_teleporter.dm
+++ b/code/game/objects/effects/bump_teleporter.dm
@@ -11,8 +11,8 @@
var/static/list/AllTeleporters
-/obj/effect/bump_teleporter/New()
- ..()
+/obj/effect/bump_teleporter/Initialize()
+ . = ..()
LAZYADD(AllTeleporters, src)
/obj/effect/bump_teleporter/Destroy()
diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm
index d62146be5e..1165ee50a0 100644
--- a/code/game/objects/effects/countdown.dm
+++ b/code/game/objects/effects/countdown.dm
@@ -14,9 +14,9 @@
anchored = TRUE
layer = GHOST_LAYER
-/obj/effect/countdown/New(atom/A)
+/obj/effect/countdown/Initialize()
. = ..()
- attach(A)
+ attach(loc)
/obj/effect/countdown/examine(mob/user)
. = ..()
diff --git a/code/game/objects/effects/effect_system/effect_system.dm b/code/game/objects/effects/effect_system/effect_system.dm
index 8c31847f78..eb4c562c36 100644
--- a/code/game/objects/effects/effect_system/effect_system.dm
+++ b/code/game/objects/effects/effect_system/effect_system.dm
@@ -12,13 +12,13 @@ would spawn and follow the beaker, even if it is carried or thrown.
pass_flags = PASSTABLE | PASSGRILLE
anchored = TRUE
-/obj/effect/particle_effect/New()
- ..()
+/obj/effect/particle_effect/Initialize()
+ . = ..()
GLOB.cameranet.updateVisibility(src)
/obj/effect/particle_effect/Destroy()
GLOB.cameranet.updateVisibility(src)
- . = ..()
+ return ..()
/datum/effect_system
var/number = 3
diff --git a/code/game/objects/effects/effect_system/effects_explosion.dm b/code/game/objects/effects/effect_system/effects_explosion.dm
index 33ecd308d1..d208510e86 100644
--- a/code/game/objects/effects/effect_system/effects_explosion.dm
+++ b/code/game/objects/effects/effect_system/effects_explosion.dm
@@ -4,8 +4,8 @@
opacity = 1
anchored = TRUE
-/obj/effect/particle_effect/expl_particles/New()
- ..()
+/obj/effect/particle_effect/expl_particles/Initialize()
+ . = ..()
QDEL_IN(src, 15)
/datum/effect_system/expl_particles
@@ -29,8 +29,8 @@
pixel_x = -32
pixel_y = -32
-/obj/effect/explosion/New()
- ..()
+/obj/effect/explosion/Initialize()
+ . = ..()
QDEL_IN(src, 10)
/datum/effect_system/explosion
diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm
index d9a7d6fb7b..e7b7472e86 100644
--- a/code/game/objects/effects/effect_system/effects_foam.dm
+++ b/code/game/objects/effects/effect_system/effects_foam.dm
@@ -270,8 +270,8 @@
max_integrity = 20
CanAtmosPass = ATMOS_PASS_DENSITY
-/obj/structure/foamedmetal/New()
- ..()
+/obj/structure/foamedmetal/Initialize()
+ . = ..()
air_update_turf(1)
diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index 5618ca9a91..472261003f 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -30,8 +30,8 @@
set_opacity(0) //if we were blocking view, we aren't now because we're fading out
stoplag()
-/obj/effect/particle_effect/smoke/New()
- ..()
+/obj/effect/particle_effect/smoke/Initialize()
+ . = ..()
create_reagents(500)
START_PROCESSING(SSobj, src)
diff --git a/code/game/objects/effects/effect_system/effects_sparks.dm b/code/game/objects/effects/effect_system/effects_sparks.dm
index 695c835a89..8453b6438d 100644
--- a/code/game/objects/effects/effect_system/effects_sparks.dm
+++ b/code/game/objects/effects/effect_system/effects_sparks.dm
@@ -22,8 +22,8 @@
anchored = TRUE
light_range = 1
-/obj/effect/particle_effect/sparks/New()
- ..()
+/obj/effect/particle_effect/sparks/Initialize()
+ . = ..()
flick("sparks", src) // replay the animation
playsound(src.loc, "sparks", 100, 1)
var/turf/T = loc
diff --git a/code/game/objects/effects/effect_system/effects_water.dm b/code/game/objects/effects/effect_system/effects_water.dm
index 4c84c97650..469b05176a 100644
--- a/code/game/objects/effects/effect_system/effects_water.dm
+++ b/code/game/objects/effects/effect_system/effects_water.dm
@@ -7,8 +7,8 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-/obj/effect/particle_effect/water/New()
- ..()
+/obj/effect/particle_effect/water/Initialize()
+ . = ..()
QDEL_IN(src, 70)
/obj/effect/particle_effect/water/Move(turf/newloc)
@@ -45,8 +45,8 @@ steam.start() -- spawns the effect
icon_state = "extinguish"
density = FALSE
-/obj/effect/particle_effect/steam/New()
- ..()
+/obj/effect/particle_effect/steam/Initialize()
+ . = ..()
QDEL_IN(src, 20)
/datum/effect_system/steam_spread
diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm
index ef074f4cec..6aab4f386a 100644
--- a/code/game/objects/effects/forcefields.dm
+++ b/code/game/objects/effects/forcefields.dm
@@ -8,8 +8,8 @@
CanAtmosPass = ATMOS_PASS_DENSITY
var/timeleft = 300 //Set to 0 for permanent forcefields (ugh)
-/obj/effect/forcefield/New()
- ..()
+/obj/effect/forcefield/Initialize()
+ . = ..()
if(timeleft)
QDEL_IN(src, timeleft)
diff --git a/code/game/objects/effects/manifest.dm b/code/game/objects/effects/manifest.dm
index 2082f2b495..fbf403a765 100644
--- a/code/game/objects/effects/manifest.dm
+++ b/code/game/objects/effects/manifest.dm
@@ -3,8 +3,9 @@
icon = 'icons/mob/screen_gen.dmi'
icon_state = "x"
-/obj/effect/manifest/New()
- src.invisibility = INVISIBILITY_ABSTRACT
+/obj/effect/manifest/Initialize()
+ . = ..()
+ invisibility = INVISIBILITY_ABSTRACT
/obj/effect/manifest/proc/manifest()
var/dat = "Crew Manifest:
"
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index 8f256f1102..2ae4f5e5c5 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -98,8 +98,8 @@
density = FALSE
var/duration = 0
-/obj/effect/mine/pickup/New()
- ..()
+/obj/effect/mine/pickup/Initialize()
+ . = ..()
animate(src, pixel_y = 4, time = 20, loop = -1)
/obj/effect/mine/pickup/triggermine(mob/victim)
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index c1abc2c02e..a0634928ce 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -13,8 +13,8 @@
icon_state="b_beam"
var/atom/BeamSource
-/obj/effect/overlay/beam/New()
- ..()
+/obj/effect/overlay/beam/Initialize()
+ . = ..()
QDEL_IN(src, 10)
/obj/effect/overlay/palmtree_r
diff --git a/code/game/objects/items/airlock_painter.dm b/code/game/objects/items/airlock_painter.dm
index be9cb0b89a..82c272e7f9 100644
--- a/code/game/objects/items/airlock_painter.dm
+++ b/code/game/objects/items/airlock_painter.dm
@@ -15,8 +15,8 @@
var/obj/item/toner/ink = null
-/obj/item/airlock_painter/New()
- ..()
+/obj/item/airlock_painter/Initialize()
+ . = ..()
ink = new /obj/item/toner(src)
//This proc doesn't just check if the painter can be used, but also uses it.
diff --git a/code/game/objects/items/candle.dm b/code/game/objects/items/candle.dm
index a0ec648a1a..b660801f90 100644
--- a/code/game/objects/items/candle.dm
+++ b/code/game/objects/items/candle.dm
@@ -14,8 +14,8 @@
var/start_lit = FALSE
heat = 1000
-/obj/item/candle/New()
- ..()
+/obj/item/candle/Initialize()
+ . = ..()
if(start_lit)
// No visible message
light(show_message = FALSE)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index 4c96bf3b84..2d30a015e2 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -9,7 +9,7 @@
/*
- * DATA CARDS - Used for the teleporter
+ * DATA CARDS - Used for the IC data card reader
*/
/obj/item/card
name = "card"
@@ -24,30 +24,49 @@
return BRUTELOSS
/obj/item/card/data
- name = "data disk"
- desc = "A disk of data."
- icon_state = "data"
+ name = "data card"
+ desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one has a stripe running down the middle."
+ icon_state = "data_1"
+ obj_flags = UNIQUE_RENAME
var/function = "storage"
var/data = "null"
var/special = null
item_state = "card-id"
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
+ var/detail_color = COLOR_ASSEMBLY_ORANGE
-/obj/item/card/data/verb/label(t as text)
- set name = "Label Disk"
- set category = "Object"
- set src in usr
+/obj/item/card/data/Initialize()
+ .=..()
+ update_icon()
- if(usr.stat || !usr.canmove || usr.restrained())
+/obj/item/card/data/update_icon()
+ cut_overlays()
+ if(detail_color == COLOR_FLOORTILE_GRAY)
return
+ var/mutable_appearance/detail_overlay = mutable_appearance('icons/obj/card.dmi', "[icon_state]-color")
+ detail_overlay.color = detail_color
+ add_overlay(detail_overlay)
- if (t)
- src.name = "data disk- '[t]'"
- else
- src.name = "data disk"
- src.add_fingerprint(usr)
- return
+/obj/item/card/data/attackby(obj/item/I, mob/living/user)
+ if(istype(I, /obj/item/integrated_electronics/detailer))
+ var/obj/item/integrated_electronics/detailer/D = I
+ detail_color = D.detail_color
+ update_icon()
+ return ..()
+
+/obj/item/proc/GetCard()
+
+/obj/item/card/data/GetCard()
+ return src
+
+/obj/item/card/data/full_color
+ desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one has the entire card colored."
+ icon_state = "data_2"
+
+/obj/item/card/data/disk
+ desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one inexplicibly looks like a floppy disk."
+ icon_state = "data_3"
/*
* ID CARDS
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 5ab8000402..6731caffd7 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -92,8 +92,12 @@ GLOBAL_LIST_EMPTY(PDAs)
..()
if(!id && !inserted_item)
return
- else
- to_chat(user, "Alt-click to remove contents.")
+
+ if(id)
+ to_chat(user, "Alt-click to remove the id.")
+
+ if(inserted_item && (!isturf(loc)))
+ to_chat(user, "Ctrl-click to remove [inserted_item].")
/obj/item/pda/Initialize()
. = ..()
@@ -712,6 +716,15 @@ GLOBAL_LIST_EMPTY(PDAs)
else
remove_pen()
+/obj/item/pda/CtrlClick()
+ ..()
+
+ if(issilicon(usr))
+ return
+
+ if(usr.canUseTopic(src) && !isturf(loc))
+ remove_pen()
+
/obj/item/pda/verb/verb_remove_id()
set category = "Object"
set name = "Eject ID"
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 0ef20dea19..fca7f9bc6d 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -160,11 +160,22 @@
if(sensor.on && sensor.visible)
add_overlay("proxy_beam")
-/obj/item/transfer_valve/proc/merge_gases()
- tank_two.air_contents.volume += tank_one.air_contents.volume
+/obj/item/transfer_valve/proc/merge_gases(datum/gas_mixture/target, change_volume = TRUE)
+ var/target_self = FALSE
+ if(!target || (target == tank_one.air_contents))
+ target = tank_two.air_contents
+ if(target == tank_two.air_contents)
+ target_self = TRUE
+ if(change_volume)
+ if(!target_self)
+ target.volume += tank_two.volume
+ target.volume += tank_one.air_contents.volume
var/datum/gas_mixture/temp
temp = tank_one.air_contents.remove_ratio(1)
- tank_two.air_contents.merge(temp)
+ target.merge(temp)
+ if(!target_self)
+ temp = tank_two.air_contents.remove_ratio(1)
+ target.merge(temp)
/obj/item/transfer_valve/proc/split_gases()
if (!valve_open || !tank_one || !tank_two)
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index 936accce39..4da0fd8a44 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -67,6 +67,7 @@
attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
novariants = TRUE
grind_results = list("bluespace" = 20)
+ point_value = 30
var/crystal_type = /obj/item/stack/ore/bluespace_crystal/refined
/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 3264deae88..996576d8e5 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -24,6 +24,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/glass
grind_results = list("silicon" = 20)
+ point_value = 1
/obj/item/stack/sheet/glass/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins to slice [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -138,6 +139,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/rglass
grind_results = list("silicon" = 20, "iron" = 10)
+ point_value = 4
/obj/item/stack/sheet/rglass/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
@@ -180,6 +182,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmarglass
grind_results = list("silicon" = 20, "plasma" = 10, "iron" = 10)
+ point_value = 23
/obj/item/stack/sheet/plasmarglass/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.prglass_recipes
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 300f18cbeb..87d1985b18 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -104,6 +104,7 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \
materials = list(MAT_DIAMOND=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
grind_results = list("carbon" = 20)
+ point_value = 25
GLOBAL_LIST_INIT(diamond_recipes, list ( \
new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, one_per_turf = 1, on_floor = 1), \
@@ -129,6 +130,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
grind_results = list("uranium" = 20)
+ point_value = 20
GLOBAL_LIST_INIT(uranium_recipes, list ( \
new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, one_per_turf = 1, on_floor = 1), \
@@ -154,6 +156,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
max_integrity = 100
materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
grind_results = list("plasma" = 20)
+ point_value = 20
/obj/item/stack/sheet/mineral/plasma/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins licking \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -193,6 +196,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
sheettype = "gold"
materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
grind_results = list("gold" = 20)
+ point_value = 20
GLOBAL_LIST_INIT(gold_recipes, list ( \
new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, one_per_turf = 1, on_floor = 1), \
@@ -220,6 +224,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
sheettype = "silver"
materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
grind_results = list("silver" = 20)
+ point_value = 20
GLOBAL_LIST_INIT(silver_recipes, list ( \
new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, one_per_turf = 1, on_floor = 1), \
@@ -247,6 +252,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
grind_results = list("banana" = 20)
+ point_value = 50
GLOBAL_LIST_INIT(bananium_recipes, list ( \
new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20), \
@@ -272,6 +278,7 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \
throw_range = 3
sheettype = "titanium"
materials = list(MAT_TITANIUM=MINERAL_MATERIAL_AMOUNT)
+ point_value = 20
GLOBAL_LIST_INIT(titanium_recipes, list ( \
new/datum/stack_recipe("titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20), \
@@ -300,6 +307,7 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \
throw_range = 3
sheettype = "plastitanium"
materials = list(MAT_TITANIUM=MINERAL_MATERIAL_AMOUNT, MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
+ point_value = 45
GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
new/datum/stack_recipe("plas-titanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20), \
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 52fdf558ee..014e4738b0 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -106,6 +106,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/metal
grind_results = list("iron" = 20)
+ point_value = 2
/obj/item/stack/sheet/metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -166,6 +167,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/plasteel
grind_results = list("iron" = 20, "plasma" = 20)
+ point_value = 23
/obj/item/stack/sheet/plasteel/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.plasteel_recipes
diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm
index 315cc94b66..21b43eba20 100644
--- a/code/game/objects/items/stacks/sheets/sheets.dm
+++ b/code/game/objects/items/stacks/sheets/sheets.dm
@@ -11,4 +11,5 @@
attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "smashed")
novariants = FALSE
var/perunit = MINERAL_MATERIAL_AMOUNT
- var/sheettype = null //this is used for girders in the creation of walls/false walls
\ No newline at end of file
+ var/sheettype = null //this is used for girders in the creation of walls/false walls
+ var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity.
\ No newline at end of file
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index fe46141614..c338f24d26 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -231,3 +231,35 @@
new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
for(var/i in 1 to 3)
new /obj/item/reagent_containers/pill/patch/styptic(src)
+
+/obj/item/storage/pill_bottle/zoom
+ name = "suspicious pill bottle"
+ desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds."
+
+/obj/item/storage/pill_bottle/zoom/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/zoom(src)
+
+/obj/item/storage/pill_bottle/happy
+ name = "suspicious pill bottle"
+ desc = "There is a smiley on the top."
+
+/obj/item/storage/pill_bottle/happy/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/happy(src)
+
+/obj/item/storage/pill_bottle/lsd
+ name = "suspicious pill bottle"
+ desc = "There is a badly drawn thing with the shape of a mushroom."
+
+/obj/item/storage/pill_bottle/lsd/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/lsd(src)
+
+/obj/item/storage/pill_bottle/aranesp
+ name = "suspicious pill bottle"
+ desc = "The label says 'gotta go fast'."
+
+/obj/item/storage/pill_bottle/aranesp/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/aranesp(src)
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 447a83422b..74aea29768 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -226,7 +226,6 @@
air_contents.react()
check_status()
-
/obj/item/tank/proc/check_status()
//Handle exploding, leaking, and rupturing of the tank
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 02e1cc9bd0..664cdbf383 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -138,19 +138,22 @@
else
obj_flags &= ~IN_USE
-/obj/proc/updateDialog()
+/obj/proc/updateDialog(update_viewers = TRUE,update_ais = TRUE)
// Check that people are actually using the machine. If not, don't update anymore.
if(obj_flags & IN_USE)
- var/list/nearby = viewers(1, src)
- var/is_in_use = 0
- for(var/mob/M in nearby)
- if ((M.client && M.machine == src))
- is_in_use = 1
- src.interact(M)
- var/ai_in_use = AutoUpdateAI(src)
+ var/is_in_use = FALSE
+ if(update_viewers)
+ for(var/mob/M in viewers(1, src))
+ if ((M.client && M.machine == src))
+ is_in_use = TRUE
+ src.interact(M)
+ var/ai_in_use = FALSE
+ if(update_ais)
+ ai_in_use = AutoUpdateAI(src)
- if(!ai_in_use && !is_in_use)
- obj_flags &= ~IN_USE
+ if(update_viewers && update_ais) //State change is sure only if we check both
+ if(!ai_in_use && !is_in_use)
+ obj_flags &= ~IN_USE
/obj/attack_ghost(mob/user)
diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm
index b5dfbf7817..85feb3026c 100644
--- a/code/modules/admin/fun_balloon.dm
+++ b/code/modules/admin/fun_balloon.dm
@@ -6,7 +6,7 @@
anchored = TRUE
var/popped = FALSE
-/obj/effect/fun_balloon/New()
+/obj/effect/fun_balloon/Initialize()
. = ..()
SSobj.processing |= src
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index 410e976b85..daa1ce473a 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -57,7 +57,7 @@
var/mob/living/carbon/human/H = null
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
- if(isReadytoRumble(applicant, ROLE_TRAITOR, FALSE))
+ if(isReadytoRumble(applicant, ROLE_TRAITOR))
if(temp.age_check(applicant.client))
if(!(applicant.job in temp.restricted_jobs))
candidates += applicant
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 2bfe1cec71..5bd8c548f7 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -496,10 +496,4 @@
#undef STIMULUM_SECOND_RISE
#undef STIMULUM_ABSOLUTE_DROP
#undef REACTION_OPPRESSION_THRESHOLD
-#undef PLASMA_BINDING_ENERGY
-#undef MAX_CATALYST_EFFICENCY
-#undef PLASMA_FUSED_COEFFICENT
-#undef CATALYST_COEFFICENT
-#undef FUSION_PURITY_THRESHOLD
-#undef FUSION_HEAT_DROPOFF
#undef NOBLIUM_FORMATION_ENERGY
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index e6b4a29502..cffd954b0e 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -1746,14 +1746,26 @@
/datum/supply_pack/costumes_toys/randomised/contraband
name = "Contraband Crate"
- desc = "Psst.. bud... want some contraband? I can get you a poster, some nice cigs, bling, even some ambrosia deus...you know, the good stuff. Just keep it away from the cops, kay?"
+ desc = "Psst.. bud... want some contraband? I can get you a poster, some nice cigs, dank, even some sponsored items...you know, the good stuff. Just keep it away from the cops, kay?"
contraband = TRUE
cost = 3000
- num_contained = 5
+ num_contained = 7
contains = list(/obj/item/poster/random_contraband,
+ /obj/item/poster/random_contraband,
+ /obj/item/reagent_containers/food/snacks/grown/cannabis,
+ /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow,
+ /obj/item/reagent_containers/food/snacks/grown/cannabis/white,
+ /obj/item/storage/pill_bottle/zoom,
+ /obj/item/storage/pill_bottle/happy,
+ /obj/item/storage/pill_bottle/lsd,
+ /obj/item/storage/pill_bottle/aranesp,
+ /obj/item/storage/pill_bottle/stimulant,
+ /obj/item/toy/cards/deck/syndicate,
+ /obj/item/reagent_containers/food/drinks/bottle/absinthe,
+ /obj/item/clothing/under/syndicate/tacticool,
+ /obj/item/storage/fancy/cigarettes/cigpack_syndicate,
/obj/item/storage/fancy/cigarettes/cigpack_shadyjims,
- /obj/item/storage/fancy/cigarettes/cigpack_midori,
- /obj/item/seeds/ambrosia/deus,
+ /obj/item/clothing/mask/gas/syndicate,
/obj/item/clothing/neck/necklace/dope)
crate_name = "crate"
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index cb797c34d4..8245148096 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -100,6 +100,11 @@
icon_state = "scarf"
color = "#4A4A4B" //Grey but it looks black
+/obj/item/clothing/neck/scarf/pink
+ name = "pink scarf"
+ icon_state = "scarf"
+ color = "#F699CD" //Pink
+
/obj/item/clothing/neck/scarf/red
name = "red scarf"
icon_state = "scarf"
@@ -118,7 +123,7 @@
/obj/item/clothing/neck/scarf/purple
name = "purple scarf"
icon_state = "scarf"
- color = "#9557C5" //purple
+ color = "#9557C5" //Purple
/obj/item/clothing/neck/scarf/yellow
name = "yellow scarf"
@@ -128,7 +133,7 @@
/obj/item/clothing/neck/scarf/orange
name = "orange scarf"
icon_state = "scarf"
- color = "#C67A4B" //orange
+ color = "#C67A4B" //Orange
/obj/item/clothing/neck/scarf/cyan
name = "cyan scarf"
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 29be63a2bb..dc903dce85 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -59,7 +59,7 @@
if(!proximity)
return
- if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
+ if(target.is_refillable() && is_drainable()) //Something like a glass. Player probably wants to transfer TO it.
if(!reagents.total_volume)
to_chat(user, "[src] is empty.")
return
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index e9ffb9e450..7e541f2471 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -427,7 +427,7 @@
/obj/item/disk/plantgene/proc/update_name()
if(gene)
- name = "[gene.get_name()] (Plant Data Disk)"
+ name = "[gene.get_name()] (plant data disk)"
else
name = "plant data disk"
@@ -437,4 +437,6 @@
/obj/item/disk/plantgene/examine(mob/user)
..()
+ if(gene && (istype(gene, /datum/plant_gene/core/potency)))
+ to_chat(user,"Percent is relative to potency, not maximum volume of the plant.")
to_chat(user, "The write-protect tab is set to [src.read_only ? "protected" : "unprotected"].")
diff --git a/code/modules/integrated_electronics/subtypes/access.dm b/code/modules/integrated_electronics/subtypes/access.dm
index bf710be0e2..9012cd1089 100644
--- a/code/modules/integrated_electronics/subtypes/access.dm
+++ b/code/modules/integrated_electronics/subtypes/access.dm
@@ -1,5 +1,5 @@
/obj/item/integrated_circuit/input/card_reader
- name = "card reader"
+ name = "ID card reader" //To differentiate it from the data card reader
desc = "A circuit that can read the registred name, assignment, and PassKey string from an ID card."
icon_state = "card_reader"
@@ -14,6 +14,10 @@
"on read" = IC_PINTYPE_PULSE_OUT
)
+/obj/item/integrated_circuit/input/card_reader/old
+ name = "card reader"
+ spawn_flags = 0
+
/obj/item/integrated_circuit/input/card_reader/attackby_react(obj/item/I, mob/living/user, intent)
var/obj/item/card/id/card = I.GetID()
var/list/access = I.GetAccess()
diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm
index b780762cd4..02500e5ed6 100644
--- a/code/modules/integrated_electronics/subtypes/input.dm
+++ b/code/modules/integrated_electronics/subtypes/input.dm
@@ -1104,3 +1104,43 @@
else
activate_pin(3)
+/obj/item/integrated_circuit/input/data_card_reader
+ name = "data card reader"
+ desc = "A circuit that can read from and write to data cards."
+ extended_desc = "Setting the \"write mode\" boolean to true will cause any data cards that are used on the assembly to replace\
+ their existing function and data strings with the given strings, if it is set to false then using a data card on the assembly will cause\
+ the function and data strings stored on the card to be written to the output pins."
+ icon_state = "card_reader"
+ complexity = 4
+ spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
+ inputs = list(
+ "function" = IC_PINTYPE_STRING,
+ "data to store" = IC_PINTYPE_STRING,
+ "write mode" = IC_PINTYPE_BOOLEAN
+ )
+ outputs = list(
+ "function" = IC_PINTYPE_STRING,
+ "stored data" = IC_PINTYPE_STRING
+ )
+ activators = list(
+ "on write" = IC_PINTYPE_PULSE_OUT,
+ "on read" = IC_PINTYPE_PULSE_OUT
+ )
+
+/obj/item/integrated_circuit/input/data_card_reader/attackby_react(obj/item/I, mob/living/user, intent)
+ var/obj/item/card/data/card = I.GetCard()
+ var/write_mode = get_pin_data(IC_INPUT, 3)
+ if(card)
+ if(write_mode == TRUE)
+ card.function = get_pin_data(IC_INPUT, 1)
+ card.data = get_pin_data(IC_INPUT, 2)
+ push_data()
+ activate_pin(1)
+ else
+ set_pin_data(IC_OUTPUT, 1, card.function)
+ set_pin_data(IC_OUTPUT, 2, card.data)
+ push_data()
+ activate_pin(2)
+ else
+ return FALSE
+ return TRUE
diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm
index a6c28b4146..59ce11baeb 100644
--- a/code/modules/lighting/lighting_source.dm
+++ b/code/modules/lighting/lighting_source.dm
@@ -56,10 +56,10 @@
if (top_atom)
LAZYREMOVE(top_atom.light_sources, src)
-
+
if (needs_update)
GLOB.lighting_update_lights -= src
-
+
. = ..()
// Yes this doesn't align correctly on anything other than 4 width tabs.
@@ -116,7 +116,6 @@
. = LUM_FALLOFF(C, pixel_turf); \
. *= light_power; \
var/OLD = effect_str[C]; \
- \
effect_str[C] = .; \
\
C.update_lumcount \
@@ -126,7 +125,6 @@
(. * lum_b) - (OLD * applied_lum_b) \
);
-
#define REMOVE_CORNER(C) \
. = -effect_str[C]; \
C.update_lumcount \
@@ -167,8 +165,9 @@
/datum/light_source/proc/update_corners()
var/update = FALSE
+ var/atom/source_atom = src.source_atom
- if (!source_atom || QDELETED(source_atom))
+ if (QDELETED(source_atom))
qdel(src)
return
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index a8d94e9ce4..765f9d92e0 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -1,3 +1,5 @@
+GLOBAL_LIST(labor_sheet_values)
+
/**********************Prisoners' Console**************************/
/obj/machinery/mineral/labor_claim_console
@@ -20,6 +22,18 @@
Radio.listening = FALSE
locate_stacking_machine()
+ if(!GLOB.labor_sheet_values)
+ var/sheet_list = list()
+ for(var/sheet_type in subtypesof(/obj/item/stack/sheet))
+ var/obj/item/stack/sheet/sheet = sheet_type
+ if(!initial(sheet.point_value) || (initial(sheet.merge_type) && initial(sheet.merge_type) != sheet_type)) //ignore no-value sheets and x/fifty subtypes
+ continue
+ sheet_list += list(list("ore" = initial(sheet.name), "value" = initial(sheet.point_value)))
+ GLOB.labor_sheet_values = sortList(sheet_list, /proc/cmp_sheet_list)
+
+/proc/cmp_sheet_list(list/a, list/b)
+ return a["value"] - b["value"]
+
/obj/machinery/mineral/labor_claim_console/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id/prisoner))
if(!inserted_id)
@@ -52,16 +66,10 @@
if(check_auth())
can_go_home = TRUE
- var/list/ores = list()
if(stacking_machine)
data["unclaimed_points"] = stacking_machine.points
- for(var/ore in stacking_machine.ore_values)
- var/list/O = list()
- O["ore"] = ore
- O["value"] = stacking_machine.ore_values[ore]
- ores += list(O)
- data["ores"] = ores
+ data["ores"] = GLOB.labor_sheet_values
data["can_go_home"] = can_go_home
return data
@@ -127,15 +135,10 @@
/obj/machinery/mineral/stacking_machine/laborstacker
- var/points = 0 //The unclaimed value of ore stacked. Value for each ore loosely relative to its rarity.
- var/list/ore_values = list("glass" = 1, "metal" = 2, "reinforced glass" = 4, "gold" = 20, "silver" = 20, "uranium" = 20, "titanium" = 20, "solid plasma" = 20, "plasteel" = 23, "plasma glass" = 23, "diamond" = 25, "bluespace polycrystal" = 30, "plastitanium" = 45, "bananium" = 50)
+ var/points = 0 //The unclaimed value of ore stacked.
/obj/machinery/mineral/stacking_machine/laborstacker/process_sheet(obj/item/stack/sheet/inp)
- if(istype(inp))
- var/n = inp.name
- var/a = inp.amount
- if(n in ore_values)
- points += ore_values[n] * a
+ points += inp.point_value * inp.amount
..()
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index f0a06429c5..dcc9034e2d 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -105,8 +105,8 @@
stack_list[inp.type] = s
var/obj/item/stack/sheet/storage = stack_list[inp.type]
storage.amount += inp.amount //Stack the sheets
- qdel(inp) //Let the old sheet garbage collect
while(storage.amount > stack_amt) //Get rid of excessive stackage
var/obj/item/stack/sheet/out = new inp.type(null, stack_amt)
unload_mineral(out)
storage.amount -= stack_amt
+ qdel(inp) //Let the old sheet garbage collect
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index e13a8e5c39..03a93a6a52 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -171,8 +171,6 @@
if("Survival Capsule and Explorer's Webbing")
new /obj/item/storage/belt/mining/vendor(drop_location)
if("Resonator Kit")
- new /obj/item/storage/belt/mining/alt(drop_location)
- new /obj/item/t_scanner/adv_mining_scanner(drop_location)
new /obj/item/extinguisher/mini(drop_location)
new /obj/item/resonator(drop_location)
if("Minebot Kit")
@@ -185,8 +183,6 @@
new /obj/item/fulton_core(drop_location)
new /obj/item/stack/marker_beacon/thirty(drop_location)
if("Crusher Kit")
- new /obj/item/storage/belt/mining/alt(drop_location)
- new /obj/item/t_scanner/adv_mining_scanner(drop_location)
new /obj/item/extinguisher/mini(drop_location)
new /obj/item/twohanded/required/kinetic_crusher(drop_location)
if("Mining Conscription Kit")
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 40ec50d67e..a469bf5258 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -164,8 +164,8 @@
//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
/mob/living/silicon/robot/Destroy()
+ var/atom/T = drop_location()//To hopefully prevent run time errors.
if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
- var/turf/T = get_turf(loc)//To hopefully prevent run time errors.
if(T)
mmi.forceMove(T)
if(mmi.brainmob)
@@ -184,6 +184,10 @@
connected_ai.connected_robots -= src
if(shell)
GLOB.available_ai_shells -= src
+ else
+ if(T && istype(radio) && istype(radio.keyslot))
+ radio.keyslot.forceMove(T)
+ radio.keyslot = null
qdel(wires)
qdel(module)
qdel(eye_lights)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index 6d3a9f9631..7d03ad4b9e 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -1,3 +1,5 @@
+#define MEDAL_PREFIX "Bubblegum"
+
/*
BUBBLEGUM
@@ -7,22 +9,15 @@ Bubblegum's footsteps are heralded by shaking booms, proving its tremendous size
It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage.
-It tries to strike at its target through any bloodpools under them; if it fails to do that, it will spray blood and then attempt to warp to a bloodpool near the target.
-If it fails to warp to a target, it may summon up to 6 slaughterlings from the blood around it.
-If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood.
-At half health, it will either charge three times or warp, then charge, instead of doing a single charge.
+It often charges, dealing massive damage to anything unfortunate enough to be standing where it's aiming.
+Whenever it isn't chasing something down, it will sink into nearby blood pools (if possible) and springs out of the closest one to its target.
+To make this possible, it sprays streams of blood at random.
+From these blood pools Bubblegum may summon slaughterlings - weak, low-damage minions designed to impede the target's progress.
-<<<<<<< HEAD
-When Bubblegum dies, it leaves behind a H.E.C.K. mining suit as well as a chest that can contain three things:
- 1. A bottle that, when activated, drives everyone nearby into a frenzy
- 2. A contract that marks for death the chosen target
- 3. A spellblade that can slice off limbs at range
-=======
When Bubblegum dies, it leaves behind a H.E.C.K. suit+helmet as well as a chest that can contain three things:
1. A spellblade that can slice off limbs at range
2. A bottle that, when activated, drives everyone nearby into a frenzy
3. A contract that marks for death the chosen target
->>>>>>> c6ca01f... Merge pull request #38661 from 81Denton/fug
Difficulty: Hard
@@ -51,8 +46,7 @@ Difficulty: Hard
del_on_death = 1
crusher_loot = list(/obj/structure/closet/crate/necropolis/bubblegum/crusher)
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
- blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
- var/charging = FALSE
+ var/charging = 0
medal_type = BOSS_MEDAL_BUBBLEGUM
score_type = BUBBLEGUM_SCORE
deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... "
@@ -64,54 +58,33 @@ Difficulty: Hard
desc = "You're not quite sure how a signal can be bloody."
invisibility = 100
-/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount, updating_health = TRUE, forced = FALSE)
- . = ..()
- if(. > 0 && prob(25))
- var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc)
- if(prob(40))
- step(B, pick(GLOB.cardinals))
- else
- B.setDir(pick(GLOB.cardinals))
-
-/obj/effect/decal/cleanable/blood/gibs/bubblegum
- name = "thick blood"
- desc = "Thick, splattered blood."
- random_icon_states = list("gib3", "gib5", "gib6")
- bloodiness = 20
-
-/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in()
- return TRUE
-
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life()
..()
- move_to_delay = CLAMP((health/maxHealth) * 10, 5, 10)
+ move_to_delay = CLAMP(round((health/maxHealth) * 10), 5, 10)
/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
- anger_modifier = CLAMP(((maxHealth - health)/60),0,20)
+ anger_modifier = CLAMP(((maxHealth - health)/50),0,20)
if(charging)
return
ranged_cooldown = world.time + ranged_cooldown_time
- var/warped = FALSE
- if(!try_bloodattack())
- INVOKE_ASYNC(src, .proc/blood_spray)
- warped = blood_warp()
- if(warped && prob(100 - anger_modifier))
- return
+ blood_warp()
- if(prob(90 - anger_modifier) || slaughterlings())
- if(health > maxHealth * 0.5)
+ if(prob(25))
+ INVOKE_ASYNC(src, .proc/blood_spray)
+
+ else if(prob(5+anger_modifier/2))
+ slaughterlings()
+ else
+ if(health > maxHealth/2 && !client)
INVOKE_ASYNC(src, .proc/charge)
else
- if(prob(70) || warped)
- INVOKE_ASYNC(src, .proc/charge, 2)
- else
- INVOKE_ASYNC(src, .proc/warp_charge)
+ INVOKE_ASYNC(src, .proc/triple_charge)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Initialize()
. = ..()
- for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_living_list)
+ for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in GLOB.mob_list)
if(B != src)
return INITIALIZE_HINT_QDEL //There can be only one
var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new
@@ -125,56 +98,53 @@ Difficulty: Hard
if(.)
SSshuttle.shuttle_purchase_requirements_met |= "bubblegum"
-/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon)
- if(!charging)
- ..()
+/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A)
+ if(charging)
+ return
+ ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget()
- if(!charging)
- return ..()
+ if(charging)
+ return
+ ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance)
- if(!charging)
- ..()
+ if(charging)
+ return
+ ..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
+ if(!stat)
+ playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
if(charging)
- new /obj/effect/temp_visual/decoy/fading(loc,src)
+ new/obj/effect/temp_visual/decoy/fading(loc,src)
DestroySurroundings()
. = ..()
- if(!stat && .)
- playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
if(charging)
DestroySurroundings()
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge()
- blood_warp()
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge()
+ charge()
+ sleep(10)
+ charge()
+ sleep(10)
charge()
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge(bonus_charges)
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
var/turf/T = get_turf(target)
if(!T || T == loc)
return
- new /obj/effect/temp_visual/dragon_swoop/bubblegum(T)
- charging = TRUE
+ new /obj/effect/temp_visual/dragon_swoop(T)
+ charging = 1
DestroySurroundings()
walk(src, 0)
setDir(get_dir(src, T))
var/obj/effect/temp_visual/decoy/D = new /obj/effect/temp_visual/decoy(loc,src)
- animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 3)
- sleep(3)
- throw_at(T, get_dist(src, T), 1, src, 0, callback = CALLBACK(src, .charge_end, bonus_charges))
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge_end(bonus_charges, list/effects_to_destroy)
- charging = FALSE
- try_bloodattack()
- if(target)
- if(bonus_charges)
- bonus_charges--
- charge(bonus_charges)
- else
- Goto(target, move_to_delay, minimum_distance)
- SetRecoveryTime(MEGAFAUNA_DEFAULT_RECOVERY_TIME)
+ animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5)
+ sleep(5)
+ throw_at(T, get_dist(src, T), 1, src, 0)
+ charging = 0
+ Goto(target, move_to_delay, minimum_distance)
/mob/living/simple_animal/hostile/megafauna/bubblegum/Collide(atom/A)
@@ -198,142 +168,20 @@ Difficulty: Hard
var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src)))
L.throw_at(throwtarget, 3)
- charging = FALSE
+ charging = 0
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood()
- var/list/targets = ListTargets()
- . = list()
- for(var/mob/living/L in targets)
- var/list/bloodpool = get_pools(get_turf(L), 0)
- if(bloodpool.len && (!faction_check_mob(L) || L.stat == DEAD))
- . += L
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
- var/list/targets = get_mobs_on_blood()
- if(targets.len)
- INVOKE_ASYNC(src, .proc/bloodattack, targets, prob(50))
-
- return TRUE
- return FALSE
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets, handedness)
- var/mob/living/target_one = pick_n_take(targets)
- var/turf/target_one_turf = get_turf(target_one)
- var/mob/living/target_two
- if(targets.len)
- target_two = pick_n_take(targets)
- var/turf/target_two_turf = get_turf(target_two)
- if(target_two.stat != CONSCIOUS || prob(10))
- bloodgrab(target_two_turf, handedness)
- else
- bloodsmack(target_two_turf, handedness)
-
- if(target_one)
- var/list/pools = get_pools(get_turf(target_one), 0)
- if(pools.len)
- target_one_turf = get_turf(target_one)
- if(target_one_turf)
- if(target_one.stat != CONSCIOUS || prob(10))
- bloodgrab(target_one_turf, !handedness)
- else
- bloodsmack(target_one_turf, !handedness)
-
- if(!target_two && target_one)
- var/list/poolstwo = get_pools(get_turf(target_one), 0)
- if(poolstwo.len)
- target_one_turf = get_turf(target_one)
- if(target_one_turf)
- if(target_one.stat != CONSCIOUS || prob(10))
- bloodgrab(target_one_turf, handedness)
- else
- bloodsmack(target_one_turf, handedness)
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T, handedness)
- if(handedness)
- new /obj/effect/temp_visual/bubblegum_hands/rightsmack(T)
- else
- new /obj/effect/temp_visual/bubblegum_hands/leftsmack(T)
- sleep(2.5)
- for(var/mob/living/L in T)
- if(!faction_check_mob(L))
- to_chat(L, "[src] rends you!")
- playsound(T, attack_sound, 100, 1, -1)
- var/limb_to_hit = L.get_bodypart(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
- L.apply_damage(25, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration))
- sleep(3)
-
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
- if(handedness)
- new /obj/effect/temp_visual/bubblegum_hands/rightpaw(T)
- new /obj/effect/temp_visual/bubblegum_hands/rightthumb(T)
- else
- new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
- new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
- sleep(6)
- for(var/mob/living/L in T)
- if(!faction_check_mob(L))
- to_chat(L, "[src] drags you through the blood!")
- playsound(T, 'sound/magic/enter_blood.ogg', 100, 1, -1)
- var/turf/targetturf = get_step(src, dir)
- L.forceMove(targetturf)
- playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, 1, -1)
- if(L.stat != CONSCIOUS)
- addtimer(CALLBACK(src, .proc/devour, L), 2)
- sleep(1)
-
-/obj/effect/temp_visual/dragon_swoop/bubblegum
- duration = 10
-
-/obj/effect/temp_visual/bubblegum_hands
- icon = 'icons/effects/bubblegum.dmi'
- duration = 9
-
-/obj/effect/temp_visual/bubblegum_hands/rightthumb
- icon_state = "rightthumbgrab"
-
-/obj/effect/temp_visual/bubblegum_hands/leftthumb
- icon_state = "leftthumbgrab"
-
-/obj/effect/temp_visual/bubblegum_hands/rightpaw
- icon_state = "rightpawgrab"
- layer = BELOW_MOB_LAYER
-
-/obj/effect/temp_visual/bubblegum_hands/leftpaw
- icon_state = "leftpawgrab"
- layer = BELOW_MOB_LAYER
-
-/obj/effect/temp_visual/bubblegum_hands/rightsmack
- icon_state = "rightsmack"
-
-/obj/effect/temp_visual/bubblegum_hands/leftsmack
- icon_state = "leftsmack"
-
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp()
- if(Adjacent(target))
- return FALSE
- var/list/can_jaunt = get_pools(get_turf(src), 1)
- if(!can_jaunt.len)
- return FALSE
-
- var/list/pools = get_pools(get_turf(target), 2)
- var/list/pools_to_remove = get_pools(get_turf(target), 1)
- pools -= pools_to_remove
- if(!pools.len)
- return FALSE
-
- var/obj/effect/temp_visual/decoy/DA = new /obj/effect/temp_visual/decoy(loc,src)
- DA.color = "#FF0000"
- var/oldtransform = DA.transform
- DA.transform = matrix()*2
- animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 3)
- sleep(3)
- qdel(DA)
-
var/obj/effect/decal/cleanable/blood/found_bloodpool
- pools = get_pools(get_turf(target), 2)
- pools_to_remove = get_pools(get_turf(target), 1)
- pools -= pools_to_remove
+ var/list/pools = list()
+ var/can_jaunt = FALSE
+ for(var/obj/effect/decal/cleanable/blood/nearby in view(src,2))
+ can_jaunt = TRUE
+ break
+ if(!can_jaunt)
+ return
+ for(var/obj/effect/decal/cleanable/blood/nearby in view(get_turf(target),2))
+ pools += nearby
if(pools.len)
shuffle_inplace(pools)
found_bloodpool = pick(pools)
@@ -343,51 +191,30 @@ Difficulty: Hard
forceMove(get_turf(found_bloodpool))
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
visible_message("And springs back out!")
- return TRUE
- return FALSE
-/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range)
- . = list()
- for(var/obj/effect/decal/cleanable/nearby in view(T, range))
- if(nearby.can_bloodcrawl_in())
- . += nearby
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
visible_message("[src] sprays a stream of gore!")
- var/range = 6 + round(anger_modifier * 0.4)
+ var/turf/E = get_edge_target_turf(src, src.dir)
+ var/range = 10
var/turf/previousturf = get_turf(src)
- var/turf/J = previousturf
- var/targetdir = get_dir(src, target)
- if(target.loc == loc)
- targetdir = dir
- face_atom(target)
- new /obj/effect/decal/cleanable/blood/bubblegum(J)
- for(var/i in 1 to range)
- J = get_step(previousturf, targetdir)
- new /obj/effect/temp_visual/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
- playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1)
- if(!J || !previousturf.atmos_adjacent_turfs || !previousturf.atmos_adjacent_turfs[J])
+ for(var/turf/J in getline(src,E))
+ if(!range)
break
- new /obj/effect/decal/cleanable/blood/bubblegum(J)
+ new /obj/effect/temp_visual/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J))
+ if(!previousturf.CanAtmosPass(J))
+ break
+ playsound(J,'sound/effects/splat.ogg', 100, 1, -1)
+ new /obj/effect/decal/cleanable/blood(J)
+ range--
previousturf = J
sleep(1)
-/obj/effect/decal/cleanable/blood/bubblegum
- bloodiness = 0
-
-/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in()
- return TRUE
-
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
visible_message("[src] summons a shoal of slaughterlings!")
- var/max_amount = 6
- for(var/H in get_pools(get_turf(src), 1))
- if(!max_amount)
- break
- max_amount--
- var/obj/effect/decal/cleanable/blood/B = H
- new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter(B.loc)
- return max_amount
+ for(var/obj/effect/decal/cleanable/blood/H in range(src, 10))
+ if(prob(25))
+ new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter(H.loc)
/mob/living/simple_animal/hostile/asteroid/hivelordbrood/slaughter
name = "slaughterling"
@@ -405,3 +232,5 @@ Difficulty: Hard
if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum))
return 1
return 0
+
+#undef MEDAL_PREFIX
\ No newline at end of file
diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm
index e7b628653f..df1f9fdfbd 100644
--- a/code/modules/projectiles/guns/misc/blastcannon.dm
+++ b/code/modules/projectiles/guns/misc/blastcannon.dm
@@ -11,8 +11,21 @@
clumsy_check = FALSE
randomspread = FALSE
+ var/hugbox = TRUE
+ var/max_power = INFINITY
+ var/reaction_volume_mod = 0
+ var/reaction_cycles = 3 //How many times gases react() before calculation. Very finnicky value, do not mess with without good reason.
+ var/prereaction = TRUE
+
+ var/bombcheck = TRUE
+ var/debug_power = 0
+
var/obj/item/transfer_valve/bomb
+/obj/item/gun/blastcannon/debug
+ debug_power = 80
+ bombcheck = FALSE
+
/obj/item/gun/blastcannon/Initialize()
. = ..()
if(!pin)
@@ -56,27 +69,33 @@
return TRUE
return ..()
+//returns the third value of a bomb blast
/obj/item/gun/blastcannon/proc/calculate_bomb()
if(!istype(bomb) || !istype(bomb.tank_one) || !istype(bomb.tank_two))
return 0
- var/datum/gas_mixture/temp = new(60) //directional buff.
- temp.merge(bomb.tank_one.air_contents.remove_ratio(1))
- temp.merge(bomb.tank_two.air_contents.remove_ratio(2))
- for(var/i in 1 to 6)
+ var/datum/gas_mixture/temp = new(max(reaction_volume_mod, 0))
+ bomb.merge_gases(temp)
+ if(prereaction)
+ temp.react(src)
+ var/prereaction_pressure = temp.return_pressure()
+ if(prereaction_pressure < TANK_FRAGMENT_PRESSURE)
+ return 0
+ for(var/i in 1 to reaction_cycles)
temp.react(src)
var/pressure = temp.return_pressure()
qdel(temp)
if(pressure < TANK_FRAGMENT_PRESSURE)
return 0
- return (pressure / TANK_FRAGMENT_SCALE)
+ return ((pressure - TANK_FRAGMENT_PRESSURE) / TANK_FRAGMENT_SCALE)
/obj/item/gun/blastcannon/afterattack(atom/target, mob/user, flag, params)
- if((!bomb) || (!target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
+ if((!bomb && bombcheck) || (!target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
return ..()
- var/power = calculate_bomb()
+ var/power = bomb? calculate_bomb() : debug_power
+ power = min(power, max_power)
QDEL_NULL(bomb)
update_icon()
- var/heavy = power * 0.2
+ var/heavy = power * 0.25
var/medium = power * 0.5
var/light = power
user.visible_message("[user] opens [bomb] on [user.p_their()] [name] and fires a blast wave at [target]!","You open [bomb] on your [name] and fire a blast wave at [target]!")
@@ -87,7 +106,8 @@
message_admins(log_str)
log_game(log_str)
var/obj/item/projectile/blastwave/BW = new(loc, heavy, medium, light)
- BW.preparePixelProjectile(target, get_turf(target), user, params, 0)
+ BW.hugbox = hugbox
+ BW.preparePixelProjectile(target, get_turf(src), params, 0)
BW.fire()
/obj/item/projectile/blastwave
@@ -99,6 +119,7 @@
var/heavyr = 0
var/mediumr = 0
var/lightr = 0
+ var/hugbox = TRUE
range = 150
/obj/item/projectile/blastwave/Initialize(mapload, _h, _m, _l)
@@ -110,14 +131,25 @@
/obj/item/projectile/blastwave/Range()
..()
var/amount_destruction = EXPLODE_NONE
+ var/wallbreak_chance = 0
if(heavyr)
amount_destruction = EXPLODE_DEVASTATE
+ wallbreak_chance = 99
else if(mediumr)
amount_destruction = EXPLODE_HEAVY
+ wallbreak_chance = 66
else if(lightr)
amount_destruction = EXPLODE_LIGHT
+ wallbreak_chance = 33
if(amount_destruction)
- loc.ex_act(amount_destruction)
+ if(hugbox)
+ loc.contents_explosion(EXPLODE_HEAVY, loc)
+ if(istype(loc, /turf/closed/wall))
+ var/turf/closed/wall/W = loc
+ if(prob(wallbreak_chance))
+ W.dismantle_wall(TRUE, TRUE)
+ else
+ loc.ex_act(amount_destruction)
else
qdel(src)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index f5d46a240e..d2f840cda3 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -151,10 +151,32 @@
icon_state = "pill18"
list_reagents = list("insulin" = 50)
roundstart = 1
-
+///////////////////////////////////////// this pill is used only in a legion mob drop
/obj/item/reagent_containers/pill/shadowtoxin
name = "black pill"
desc = "I wouldn't eat this if I were you."
icon_state = "pill9"
color = "#454545"
- list_reagents = list("shadowmutationtoxin" = 1)
\ No newline at end of file
+ list_reagents = list("shadowmutationtoxin" = 1)
+//////////////////////////////////////// drugs
+/obj/item/reagent_containers/pill/zoom
+ name = "zoom pill"
+ list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1)
+
+
+/obj/item/reagent_containers/pill/happy
+ name = "happy pill"
+ list_reagents = list("sugar" = 10, "space_drugs" = 10)
+
+
+/obj/item/reagent_containers/pill/lsd
+ name = "hallucinogen pill"
+ list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15)
+
+
+/obj/item/reagent_containers/pill/aranesp
+ name = "speedy pill"
+ list_reagents = list("aranesp" = 10)
+
+
+
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index aa0b714cc8..c806a68867 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -199,7 +199,7 @@
/obj/item/bodypart/r_leg/drop_limb(special)
if(owner && !special)
if(owner.legcuffed)
- owner.legcuffed.forceMove(drop_location())
+ owner.legcuffed.forceMove(owner.drop_location()) //At this point bodypart is still in nullspace
owner.legcuffed.dropped(owner)
owner.legcuffed = null
owner.update_inv_legcuffed()
@@ -210,7 +210,7 @@
/obj/item/bodypart/l_leg/drop_limb(special) //copypasta
if(owner && !special)
if(owner.legcuffed)
- owner.legcuffed.forceMove(drop_location())
+ owner.legcuffed.forceMove(owner.drop_location())
owner.legcuffed.dropped(owner)
owner.legcuffed = null
owner.update_inv_legcuffed()
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 89197a7f07..619e2c8193 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -1412,6 +1412,16 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
limited_stock = 2 //you can't use more than two!
restricted_roles = list("Shaft Miner")
+/datum/uplink_item/role_restricted/blastcannon
+ name = "Blast Cannon"
+ desc = "A highly specialized weapon, the Blast Cannon is actually relatively simple. It contains an attachment for a tank transfer valve mounted to an angled pipe specially constructed \
+ withstand extreme pressure and temperatures, and has a mechanical trigger for triggering the transfer valve. Essentially, it turns the explosive force of a bomb into a narrow-angle \
+ blast wave \"projectile\". Aspiring scientists may find this highly useful, as forcing the pressure shockwave into a narrow angle seems to be able to bypass whatever quirk of physics \
+ disallows explosive ranges above a certain distance, allowing for the device to use the theoretical yield of a transfer valve bomb, instead of the factual yield."
+ item = /obj/item/gun/blastcannon
+ cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled scientist.
+ restricted_roles = list("Research Director", "Scientist")
+
/datum/uplink_item/device_tools/clown_bomb
name = "Clown Bomb"
desc = "The Clown bomb is a hilarious device capable of massive pranks. It has an adjustable timer, \
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index f3ab636fb0..ad5b38575c 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -35,6 +35,7 @@
/obj/item/clothing/neck/tie/red = 1,
/obj/item/clothing/neck/tie/black = 1,
/obj/item/clothing/neck/tie/horrible = 1,
+ /obj/item/clothing/neck/scarf/pink = 1,
/obj/item/clothing/neck/scarf/red = 1,
/obj/item/clothing/neck/scarf/green = 1,
/obj/item/clothing/neck/scarf/darkblue = 1,
@@ -118,5 +119,5 @@
/obj/item/vending_refill/clothing
machine_name = "ClothesMate"
icon_state = "refill_clothes"
- charges = list(37, 4, 4)// of 111 standard, 12 contraband, 10 premium(?)
- init_charges = list(37, 4, 4)
+ charges = list(38, 4, 4)// of 112 standard, 12 contraband, 10 premium(?)
+ init_charges = list(38, 4, 4)
diff --git a/html/changelogs/AutoChangeLog-pr-7188.yml b/html/changelogs/AutoChangeLog-pr-7188.yml
new file mode 100644
index 0000000000..d27aee5b1b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7188.yml
@@ -0,0 +1,8 @@
+author: "JStheguy"
+delete-after: True
+changes:
+ - rscadd: "Added the data card reader circuit, a circuit that is able to read data cards, as well as write to them."
+ - tweak: "Data cards are now longer inexplicably called data disks despite clearly being cards, and can be printed from the \"tools\" section of the integrated circuit printer."
+ - tweak: "Data cards no longer have a special \"label card\" verb and instead can have their names and descriptions changed with a pen."
+ - rscadd: "Also, some aesthetically different variants of the data cards, because why not."
+ - imageadd: "Data cards have new sprites, with support for coloring them via the assembly detailer."
diff --git a/html/changelogs/AutoChangeLog-pr-7189.yml b/html/changelogs/AutoChangeLog-pr-7189.yml
new file mode 100644
index 0000000000..f0718609b9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7189.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Added a pink scarf to vendomats"
diff --git a/html/changelogs/AutoChangeLog-pr-7190.yml b/html/changelogs/AutoChangeLog-pr-7190.yml
new file mode 100644
index 0000000000..ac2f2cf485
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7190.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Players can now ctrl-click the PDA to remove the item in its pen slot"
diff --git a/html/changelogs/AutoChangeLog-pr-7201.yml b/html/changelogs/AutoChangeLog-pr-7201.yml
new file mode 100644
index 0000000000..562c8e4190
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7201.yml
@@ -0,0 +1,5 @@
+author: "Cobby"
+delete-after: True
+changes:
+ - rscdel: "Removed Advanced Mining Scanner from roundstart voucher kits."
+ - rscdel: "Removed Explorer Webbing from all voucher kits besides the shelter capsule pack."
diff --git a/html/changelogs/AutoChangeLog-pr-7218.yml b/html/changelogs/AutoChangeLog-pr-7218.yml
new file mode 100644
index 0000000000..6bb568d088
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7218.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - spellcheck: "Plant disks with potency genes clarify the percent is for potency scaling and not relative to max volume on examine."
diff --git a/html/changelogs/AutoChangeLog-pr-7219.yml b/html/changelogs/AutoChangeLog-pr-7219.yml
new file mode 100644
index 0000000000..b50be06a75
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7219.yml
@@ -0,0 +1,4 @@
+author: "Dax Dupont"
+delete-after: True
+changes:
+ - admin: "Create antags now checks for people being on station before applying."
diff --git a/html/changelogs/AutoChangeLog-pr-7220.yml b/html/changelogs/AutoChangeLog-pr-7220.yml
new file mode 100644
index 0000000000..ba87335d1e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7220.yml
@@ -0,0 +1,6 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Blast cannons have been fixed and are now available for purchase by traitorous scientists for a low low price of 14TC."
+ - rscadd: "Blast cannons take the explosive power of a TTV bomb and ejects a linear projectile that will apply what the bomb would do to a certain tile at that distance to that tile. However, this will not cause breaches, or gib mobs, unless the gods (admins) so will it.
+experimental: Blast cannons do not respect maxcap. (Unless the admins so will it.)"
diff --git a/html/changelogs/AutoChangeLog-pr-7222.yml b/html/changelogs/AutoChangeLog-pr-7222.yml
new file mode 100644
index 0000000000..1fb99a2d63
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7222.yml
@@ -0,0 +1,4 @@
+author: "Kor"
+delete-after: True
+changes:
+ - rscadd: "Bubblegum has regained his original (deadlier) move set."
diff --git a/html/changelogs/AutoChangeLog-pr-7230.yml b/html/changelogs/AutoChangeLog-pr-7230.yml
new file mode 100644
index 0000000000..b1674293b5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7230.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - rscadd: "Cyborgs now drop keys on deconstruction/detonation"
diff --git a/html/changelogs/AutoChangeLog-pr-7231.yml b/html/changelogs/AutoChangeLog-pr-7231.yml
new file mode 100644
index 0000000000..4bd894c04e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7231.yml
@@ -0,0 +1,4 @@
+author: "Time-Green"
+delete-after: True
+changes:
+ - bugfix: "Soda is no longer intangible to the laws of physics"
diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi
index e6778c51af..507801844c 100644
Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ
diff --git a/sound/effects/comfyfire.ogg b/sound/effects/comfyfire.ogg
index 9b796219b3..1bc7fc02d0 100644
Binary files a/sound/effects/comfyfire.ogg and b/sound/effects/comfyfire.ogg differ