Autolathe Menu:
"
dat += materials_printout()
@@ -380,4 +386,4 @@
//Called when the object is constructed by an autolathe
//Has a reference to the autolathe so you can do !!FUN!! things with hacked lathes
/obj/item/proc/autolathe_crafted(obj/machinery/autolathe/A)
- return
\ No newline at end of file
+ return
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index a982411692..fc6cac785a 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -28,6 +28,8 @@
. += "There's [charging ? "a" : "no"] cell in the charger."
if(charging)
. += "Current charge: [round(charging.percent(), 1)]%."
+ if(in_range(user, src) || isobserver(user))
+ . += "
The status display reads: Charge rate at [charge_rate]J per cycle."
/obj/machinery/cell_charger/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stock_parts/cell) && !panel_open)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 413621d8b9..711b221c54 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -102,8 +102,13 @@
/obj/machinery/clonepod/examine(mob/user)
. = ..()
var/mob/living/mob_occupant = occupant
+ . += "
The linking device can be scanned with a multitool."
if(mess)
. += "It's filled with blood and viscera. You swear you can see it moving..."
+ if(in_range(user, src) || isobserver(user))
+ . += "
The status display reads: Cloning speed at [speed_coeff*50]%.
Predicted amount of cellular damage: [100-heal_level]%."
+ if(efficiency > 5)
+ to_chat(user, "
Pod has been upgraded to support autoprocessing.")
if(is_operational() && mob_occupant)
if(mob_occupant.stat != DEAD)
. += "Current clone cycle is [round(get_completion())]% complete."
diff --git a/code/game/machinery/computer/teleporter.dm b/code/game/machinery/computer/teleporter.dm
index 21fb70c38c..c52cf29660 100644
--- a/code/game/machinery/computer/teleporter.dm
+++ b/code/game/machinery/computer/teleporter.dm
@@ -44,7 +44,7 @@
data += "Current target: [(!target) ? "None" : "[get_area(target)] [(regime_set != "Gate") ? "" : "Teleporter"]"]
"
if(calibrating)
data += "Calibration: In Progress"
- else if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accurate >= 3)
+ else if(power_station.teleporter_hub.calibrated || power_station.efficiency >= 3)
data += "Calibration: Optimal"
else
data += "Calibration: Sub-Optimal"
@@ -84,14 +84,14 @@
if(!target)
say("Error: No target set to calibrate to.")
return
- if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accurate >= 3)
+ if(power_station.teleporter_hub.calibrated || power_station.efficiency >= 3)
say("Hub is already calibrated!")
return
say("Processing hub calibration to target...")
calibrating = 1
power_station.update_icon()
- spawn(50 * (3 - power_station.teleporter_hub.accurate)) //Better parts mean faster calibration
+ spawn(50 * (3 - power_station.efficiency)) //Better parts mean faster calibration
calibrating = 0
if(check_hub_connection())
power_station.teleporter_hub.calibrated = 1
diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index f62dceff6c..cff2e361bd 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -27,6 +27,13 @@
for(var/obj/item/stock_parts/micro_laser/P in component_parts)
damage_coeff = P.rating
+/obj/machinery/dna_scannernew/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Radiation pulse accuracy increased by factor [precision_coeff**2].
Radiation pulse damage decreased by factor [damage_coeff**2]."
+ if(scan_level >= 3)
+ . += "Scanner has been upgraded to support autoprocessing."
+
/obj/machinery/dna_scannernew/update_icon()
//no power or maintenance
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 2e43670624..ad0f372530 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -5,6 +5,7 @@
icon_state = "door1"
opacity = 1
density = TRUE
+ move_resist = MOVE_FORCE_VERY_STRONG
layer = OPEN_DOOR_LAYER
power_channel = ENVIRON
max_integrity = 350
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 0429db5792..f5bf8c8a1b 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -32,7 +32,7 @@
CalculateAffectingAreas()
/obj/machinery/door/firedoor/examine(mob/user)
- ..()
+ . = ..()
if(!density)
. += "It is open, but could be pried closed."
else if(!welded)
diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm
index e1f9824524..40430b37b7 100644
--- a/code/game/machinery/harvester.dm
+++ b/code/game/machinery/harvester.dm
@@ -129,7 +129,7 @@
/obj/machinery/harvester/proc/end_harvesting()
harvesting = FALSE
open_machine()
- say("Subject has been succesfuly harvested.")
+ say("Subject has been successfully harvested.")
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, 0)
/obj/machinery/harvester/screwdriver_act(mob/living/user, obj/item/I)
@@ -191,4 +191,6 @@
if(state_open)
. += "[src] must be closed before harvesting."
else if(!harvesting)
- . += "Alt-click [src] to start harvesting."
\ No newline at end of file
+ . += "Alt-click [src] to start harvesting."
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Harvest speed at [interval*0.1] seconds per organ."
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 40fc52d6a1..f3e446c686 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -143,6 +143,11 @@ GLOBAL_LIST_EMPTY(network_holopads)
holograph_range += 1 * B.rating
holo_range = holograph_range
+/obj/machinery/holopad/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Current projection range: [holo_range] units."
+
/obj/machinery/holopad/attackby(obj/item/P, mob/user, params)
if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P))
return
diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm
index 5418dcdb97..b4a9584368 100644
--- a/code/game/machinery/launch_pad.dm
+++ b/code/game/machinery/launch_pad.dm
@@ -23,6 +23,11 @@
E += M.rating*15
range = E
+/obj/machinery/launchpad/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Maximum range: [range] units."
+
/obj/machinery/launchpad/attackby(obj/item/I, mob/user, params)
if(stationary)
if(default_deconstruction_screwdriver(user, "lpad-idle-o", "lpad-idle", I))
diff --git a/code/game/machinery/limbgrower.dm b/code/game/machinery/limbgrower.dm
index bf9400219b..28afea817b 100644
--- a/code/game/machinery/limbgrower.dm
+++ b/code/game/machinery/limbgrower.dm
@@ -144,7 +144,7 @@
// Set this limb up using the specias name and body zone
limb.icon_state = "[selected_category]_[limb.body_zone]"
limb.name = "\improper synthetic [selected_category] [parse_zone(limb.body_zone)]"
- limb.desc = "A synthetic [selected_category] limb that will morph on its first use in surgery. This one is for the [parse_zone(limb.body_zone)]"
+ limb.desc = "A synthetic [selected_category] limb that will morph on its first use in surgery. This one is for the [parse_zone(limb.body_zone)]."
limb.species_id = selected_category
limb.update_icon_dropped()
@@ -158,6 +158,11 @@
T -= M.rating*0.2
prod_coeff = min(1,max(0,T)) // Coeff going 1 -> 0,8 -> 0,6 -> 0,4
+/obj/machinery/limbgrower/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Storing up to [reagents.maximum_volume]u of synthflesh.
Synthflesh consumption at [prod_coeff*100]%."
+
/obj/machinery/limbgrower/proc/main_win(mob/user)
var/dat = "Limb Grower Menu:
"
dat += "
Chemical Storage"
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index a581981746..2211397f3e 100755
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -23,6 +23,23 @@
for(var/obj/item/stock_parts/capacitor/C in component_parts)
recharge_coeff = C.rating
+/obj/machinery/recharger/examine(mob/user)
+ . = ..()
+ if(!in_range(user, src) && !issilicon(user) && !isobserver(user))
+ . += "
You're too far away to examine [src]'s contents and display!"
+ return
+
+ if(charging)
+ . += {"
\The [src] contains:
+
- \A [charging]."}
+
+ if(!(stat & (NOPOWER|BROKEN)))
+ . += "
The status display reads:"
+ . += "
- Recharging [recharge_coeff*10]% cell charge per cycle."
+ if(charging)
+ var/obj/item/stock_parts/cell/C = charging.get_cell()
+ . += "
- \The [charging]'s cell is at [C.percent()]%."
+
/obj/machinery/recharger/proc/setCharging(new_charging)
charging = new_charging
if (new_charging)
diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm
index cd5f7ad6bf..374c0c71b9 100644
--- a/code/game/machinery/rechargestation.dm
+++ b/code/game/machinery/rechargestation.dm
@@ -50,6 +50,13 @@
for(var/obj/item/stock_parts/cell/C in component_parts)
recharge_speed *= C.maxcharge / 10000
+/obj/machinery/recharge_station/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "
The status display reads: Recharging [recharge_speed]J per cycle."
+ if(repairs)
+ to_chat(user, "
[src] has been upgraded to support automatic repairs.")
+
/obj/machinery/recharge_station/process()
if(!is_operational())
return
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index c879ca73e8..538017eaef 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -41,9 +41,10 @@
/obj/machinery/recycler/examine(mob/user)
. = ..()
- . += "The power light is [(stat & NOPOWER) ? "off" : "on"]."
- . += "The safety-mode light is [safety_mode ? "on" : "off"]."
- . += "The safety-sensors status light is [obj_flags & EMAGGED ? "off" : "on"]."
+ . += "Reclaiming [amount_produced]% of materials salvaged."
+ . += {"The power light is [(stat & NOPOWER) ? "off" : "on"].
+ The safety-mode light is [safety_mode ? "on" : "off"].
+ The safety-sensors status light is [obj_flags & EMAGGED ? "off" : "on"]."}
/obj/machinery/recycler/power_change()
..()
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index fc6577a4f1..16016b8e18 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -4,6 +4,7 @@
icon = 'icons/effects/effects.dmi'
icon_state = "shield-old"
density = TRUE
+ move_resist = INFINITY
opacity = 0
anchored = TRUE
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
@@ -93,6 +94,7 @@
/obj/machinery/shieldgen/proc/shields_up()
active = TRUE
update_icon()
+ move_resist = INFINITY
for(var/turf/target_tile in range(shield_range, src))
if(isspaceturf(target_tile) && !(locate(/obj/structure/emergency_shield) in target_tile))
@@ -101,6 +103,7 @@
/obj/machinery/shieldgen/proc/shields_down()
active = FALSE
+ move_resist = initial(move_resist)
update_icon()
QDEL_LIST(deployed_shields)
diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm
index 984a911d32..6eca52aa0e 100644
--- a/code/game/machinery/spaceheater.dm
+++ b/code/game/machinery/spaceheater.dm
@@ -52,6 +52,8 @@
. += "The charge meter reads [cell ? round(cell.percent(), 1) : 0]%."
else
. += "There is no power cell installed."
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Temperature range at [settableTemperatureRange]°C.
Heating power at [heatingPower*0.001]kJ.
Power consumption at [(efficiency*-0.0025)+150]%." //100%, 75%, 50%, 25%
/obj/machinery/space_heater/update_icon()
if(on)
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index ae71a0b844..3cc71df0f1 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -11,7 +11,7 @@
idle_power_usage = 10
active_power_usage = 2000
circuit = /obj/item/circuitboard/machine/teleporter_hub
- var/accurate = FALSE
+ var/accuracy = 0
var/obj/machinery/teleport/station/power_station
var/calibrated //Calibration prevents mutation
@@ -29,7 +29,12 @@
var/A = 0
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
A += M.rating
- accurate = A
+ accuracy = A
+
+/obj/machinery/teleport/hub/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Probability of malfunction decreased by [(accuracy*25)-25]%."
/obj/machinery/teleport/hub/proc/link_power_station()
if(power_station)
@@ -69,13 +74,13 @@
if(do_teleport(M, com.target, channel = TELEPORT_CHANNEL_BLUESPACE))
use_power(5000)
- if(!calibrated && iscarbon(M) && prob(30 - ((accurate) * 10))) //oh dear a problem
+ if(!calibrated && iscarbon(M) && prob(30 - ((accuracy) * 10))) //oh dear a problem
var/mob/living/carbon/C = M
if(C.dna?.species && C.dna.species.id != "fly" && !HAS_TRAIT(C, TRAIT_RADIMMUNE))
to_chat(C, "You hear a buzzing in your ears.")
C.set_species(/datum/species/fly)
log_game("[C] ([key_name(C)]) was turned into a fly person")
- C.apply_effect((rand(120 - accurate * 40, 180 - accurate * 60)), EFFECT_IRRADIATE, 0)
+ C.apply_effect((rand(120 - accuracy * 40, 180 - accuracy * 60)), EFFECT_IRRADIATE, 0)
calibrated = FALSE
return
@@ -102,7 +107,7 @@
/obj/machinery/teleport/station
- name = "station"
+ name = "teleporter station"
desc = "The power control station for a bluespace teleporter. Used for toggling power, and can activate a test-fire to prevent malfunctions."
icon_state = "controller"
use_power = IDLE_POWER_USE
@@ -125,6 +130,15 @@
E += C.rating
efficiency = E - 1
+/obj/machinery/teleport/station/examine(mob/user)
+ . = ..()
+ if(!panel_open)
+ . += "The panel is screwed in, obstructing the linking device and wiring panel."
+ else
+ . += "The linking device is now able to be scanned with a multitool.
The wiring can be connected to a nearby console and hub with a pair of wirecutters."
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: This station can be linked to [efficiency] other station(s)."
+
/obj/machinery/teleport/station/proc/link_console_and_hub()
for(var/direction in GLOB.cardinals)
teleporter_hub = locate(/obj/machinery/teleport/hub, get_step(src, direction))
diff --git a/code/game/machinery/turnstile.dm b/code/game/machinery/turnstile.dm
index 1fd78056d4..9bc5193bbb 100644
--- a/code/game/machinery/turnstile.dm
+++ b/code/game/machinery/turnstile.dm
@@ -19,7 +19,7 @@
return TRUE
/obj/machinery/turnstile/bullet_act(obj/item/projectile/P, def_zone)
- return -1 //Pass through!
+ return BULLET_ACT_FORCE_PIERCE //Pass through!
/obj/machinery/turnstile/proc/allowed_access(var/mob/B)
if(B.pulledby && ismob(B.pulledby))
diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm
index a8ba9850ff..fdb620cc67 100644
--- a/code/game/mecha/equipment/tools/other_tools.dm
+++ b/code/game/mecha/equipment/tools/other_tools.dm
@@ -84,7 +84,7 @@
switch(mode)
if(1)
if(!locked)
- if(!istype(target) || target.anchored)
+ if(!istype(target) || target.anchored || target.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)
occupant_message("Unable to lock on [target]")
return
locked = target
@@ -110,7 +110,7 @@
else
atoms = orange(3, target)
for(var/atom/movable/A in atoms)
- if(A.anchored)
+ if(A.anchored || A.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)
continue
spawn(0)
var/iter = 5-get_dist(A,target)
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index 95fc96e119..2e93fc3a49 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -436,7 +436,7 @@
throwforce = 35
icon_state = "punching_glove"
-/obj/item/punching_glove/throw_impact(atom/hit_atom)
+/obj/item/punching_glove/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..())
if(ismovableatom(hit_atom))
var/atom/movable/AM = hit_atom
diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm
index bc8a675085..90f037c279 100644
--- a/code/game/mecha/mech_bay.dm
+++ b/code/game/mecha/mech_bay.dm
@@ -36,6 +36,11 @@
MC += C.rating
max_charge = MC * 25
+/obj/machinery/mech_bay_recharge_port/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Base recharge rate at [max_charge]J per cycle."
+
/obj/machinery/mech_bay_recharge_port/process()
if(stat & NOPOWER || !recharge_console)
return
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 61c0a8bd37..98e4eb4258 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -62,6 +62,11 @@
T += Ml.rating
time_coeff = round(initial(time_coeff) - (initial(time_coeff)*(T))/5,0.01)
+/obj/machinery/mecha_part_fabricator/examine(mob/user)
+ . = ..()
+ var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Storing up to [materials.max_amount] material units.
Material consumption at [component_coeff*100]%.
Build time reduced by [100-time_coeff*100]%."
/obj/machinery/mecha_part_fabricator/emag_act()
. = ..()
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index dd335e8b37..e5e578b0e8 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -108,8 +108,8 @@
/obj/mecha/attack_tk()
return
-/obj/mecha/hitby(atom/movable/A as mob|obj) //wrapper
- log_message("Hit by [A].", color="red")
+/obj/mecha/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) //wrapper
+ log_message("Hit by [AM].", color="red")
. = ..()
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index d48013d472..6057d1b418 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -4,6 +4,7 @@
/obj/effect
icon = 'icons/effects/effects.dmi'
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
+ move_resist = INFINITY
obj_flags = 0
/obj/effect/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm
index 953b8b1f00..71c394a404 100644
--- a/code/game/objects/effects/spawners/lootdrop.dm
+++ b/code/game/objects/effects/spawners/lootdrop.dm
@@ -378,3 +378,11 @@
/obj/item/circuitboard/computer/apc_control,
/obj/item/circuitboard/computer/robotics
)
+
+/obj/effect/spawner/lootdrop/keg
+ name = "random keg spawner"
+ lootcount = 1
+ loot = list(/obj/structure/reagent_dispensers/keg/mead = 5,
+ /obj/structure/reagent_dispensers/keg/aphro = 2,
+ /obj/structure/reagent_dispensers/keg/aphro/strong = 2,
+ /obj/structure/reagent_dispensers/keg/gargle = 1)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 2bf039218b..aa4e45dee6 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -10,6 +10,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/item_state = null
var/lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
var/righthand_file = 'icons/mob/inhands/items_righthand.dmi'
+ var/list/alternate_screams = list() //REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
//Dimensions of the icon file used when this item is worn, eg: hats.dmi
//eg: 32x32 sprite, 64x64 sprite, etc.
@@ -567,21 +568,21 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
else
return
-/obj/item/throw_impact(atom/A, datum/thrownthing/throwingdatum)
- if(A && !QDELETED(A))
- SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, A, throwingdatum)
- if(get_temperature() && isliving(A))
- var/mob/living/L = A
+/obj/item/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(hit_atom && !QDELETED(hit_atom))
+ SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum)
+ if(get_temperature() && isliving(hit_atom))
+ var/mob/living/L = hit_atom
L.IgniteMob()
var/itempush = 1
if(w_class < 4)
itempush = 0 //too light to push anything
- return A.hitby(src, 0, itempush)
+ return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum)
-/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, messy_throw = TRUE)
+/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
thrownby = thrower
callback = CALLBACK(src, .proc/after_throw, callback, (spin && messy_throw)) //replace their callback with our own
- . = ..(target, range, speed, thrower, spin, diagonals_first, callback)
+ . = ..(target, range, speed, thrower, spin, diagonals_first, callback, force)
/obj/item/proc/after_throw(datum/callback/callback, messy_throw)
if (callback) //call the original callback
@@ -673,7 +674,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
else
. = ""
-/obj/item/hitby(atom/movable/AM)
+/obj/item/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
/obj/item/attack_hulk(mob/living/carbon/human/user)
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index e151450d8a..3f57fa7cdf 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -677,18 +677,18 @@ RLD
icon_state = "rld"
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
- matter = 500
- max_matter = 500
- sheetmultiplier = 16
+ matter = 200
+ max_matter = 200
+ sheetmultiplier = 5
var/mode = LIGHT_MODE
actions_types = list(/datum/action/item_action/pick_color)
ammo_sections = 5
has_ammobar = TRUE
- var/wallcost = 10
- var/floorcost = 15
- var/launchcost = 5
- var/deconcost = 10
+ var/wallcost = 20
+ var/floorcost = 25
+ var/launchcost = 10
+ var/deconcost = 20
var/walldelay = 10
var/floordelay = 10
diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm
index 141f7e510a..e6e39d3ff1 100644
--- a/code/game/objects/items/RPD.dm
+++ b/code/game/objects/items/RPD.dm
@@ -19,12 +19,14 @@ GLOBAL_LIST_INIT(atmos_pipe_recipes, list(
new /datum/pipe_info/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold),
new /datum/pipe_info/pipe("Manual Valve", /obj/machinery/atmospherics/components/binary/valve),
new /datum/pipe_info/pipe("Digital Valve", /obj/machinery/atmospherics/components/binary/valve/digital),
+ new /datum/pipe_info/pipe("Relief Valve", /obj/machinery/atmospherics/components/binary/relief_valve),
new /datum/pipe_info/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w),
new /datum/pipe_info/pipe("Layer Manifold", /obj/machinery/atmospherics/pipe/layer_manifold),
),
"Devices" = list(
new /datum/pipe_info/pipe("Connector", /obj/machinery/atmospherics/components/unary/portables_connector),
new /datum/pipe_info/pipe("Unary Vent", /obj/machinery/atmospherics/components/unary/vent_pump),
+ new /datum/pipe_info/pipe("Relief Valve", /obj/machinery/atmospherics/components/unary/relief_valve),
new /datum/pipe_info/pipe("Gas Pump", /obj/machinery/atmospherics/components/binary/pump),
new /datum/pipe_info/pipe("Passive Gate", /obj/machinery/atmospherics/components/binary/passive_gate),
new /datum/pipe_info/pipe("Volume Pump", /obj/machinery/atmospherics/components/binary/volume_pump),
@@ -33,6 +35,7 @@ GLOBAL_LIST_INIT(atmos_pipe_recipes, list(
new /datum/pipe_info/meter("Meter"),
new /datum/pipe_info/pipe("Gas Filter", /obj/machinery/atmospherics/components/trinary/filter),
new /datum/pipe_info/pipe("Gas Mixer", /obj/machinery/atmospherics/components/trinary/mixer),
+ new /datum/pipe_info/pipe("Passive Vent", /obj/machinery/atmospherics/components/unary/passive_vent),
),
"Heat Exchange" = list(
new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/heat_exchanging/simple),
diff --git a/modular_citadel/code/game/objects/items/balls.dm b/code/game/objects/items/balls.dm
similarity index 99%
rename from modular_citadel/code/game/objects/items/balls.dm
rename to code/game/objects/items/balls.dm
index 79552bff6d..59b47bacbd 100644
--- a/modular_citadel/code/game/objects/items/balls.dm
+++ b/code/game/objects/items/balls.dm
@@ -89,4 +89,4 @@
resistance_flags = ACID_PROOF
/datum/action/item_action/squeeze
- name = "Squeak!"
\ No newline at end of file
+ name = "Squeak!"
diff --git a/modular_citadel/code/game/objects/items/boombox.dm b/code/game/objects/items/boombox.dm
similarity index 100%
rename from modular_citadel/code/game/objects/items/boombox.dm
rename to code/game/objects/items/boombox.dm
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index f3ed99b132..2daf6f0c0b 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -74,6 +74,7 @@
playsound(src, 'sound/weapons/slice.ogg', 50, 1)
if(prob(P.damage))
push_over()
+ return BULLET_ACT_HIT
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
if(!crayon || !user)
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 911a07c288..2dcb495701 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -242,7 +242,7 @@
if(Pgun && istype(Pgun))
Pgun.field_connect(src)
else
- return 0
+ return BULLET_ACT_HIT
/obj/effect/chrono_field/assume_air()
return 0
diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm
index 32c879e2d2..8400b6fa5c 100644
--- a/code/game/objects/items/circuitboards/computer_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm
@@ -293,6 +293,10 @@
name = "Mining Shuttle (Computer Board)"
build_path = /obj/machinery/computer/shuttle/mining
+/obj/item/circuitboard/computer/mining_shuttle/common
+ name = "Lavaland Shuttle (Computer Board)"
+ build_path = /obj/machinery/computer/shuttle/mining/common
+
/obj/item/circuitboard/computer/white_ship
name = "White Ship (Computer Board)"
build_path = /obj/machinery/computer/shuttle/white_ship
diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm
index dffbb46cbb..c4ffa9f0ff 100644
--- a/code/game/objects/items/devices/chameleonproj.dm
+++ b/code/game/objects/items/devices/chameleonproj.dm
@@ -146,7 +146,7 @@
master.disrupt()
/obj/effect/dummy/chameleon/bullet_act()
- ..()
+ . = ..()
master.disrupt()
/obj/effect/dummy/chameleon/relaymove(mob/user, direction)
diff --git a/code/game/objects/items/devices/instruments.dm b/code/game/objects/items/devices/instruments.dm
index 48ba92962f..dd7c5b15d9 100644
--- a/code/game/objects/items/devices/instruments.dm
+++ b/code/game/objects/items/devices/instruments.dm
@@ -101,13 +101,23 @@
item_state = "synth"
instrumentId = "piano"
instrumentExt = "ogg"
- var/static/list/insTypes = list("accordion" = "mid", "bikehorn" = "ogg", "glockenspiel" = "mid", "guitar" = "ogg", "harmonica" = "mid", "piano" = "ogg", "recorder" = "mid", "saxophone" = "mid", "trombone" = "mid", "violin" = "mid", "xylophone" = "mid") //No eguitar you ear-rapey fuckers.
+ var/static/list/insTypes = list("accordion" = "mid", "bikehorn" = "ogg", "glockenspiel" = "mid", "banjo" = "ogg", "guitar" = "ogg", "harmonica" = "mid", "piano" = "ogg", "recorder" = "mid", "saxophone" = "mid", "trombone" = "mid", "violin" = "mid", "xylophone" = "mid") //No eguitar you ear-rapey fuckers.
actions_types = list(/datum/action/item_action/synthswitch)
/obj/item/instrument/piano_synth/proc/changeInstrument(name = "piano")
song.instrumentDir = name
song.instrumentExt = insTypes[name]
+/obj/item/instrument/banjo
+ name = "banjo"
+ desc = "A 'Mura' brand banjo. It's pretty much just a drum with a neck and strings."
+ icon_state = "banjo"
+ item_state = "banjo"
+ instrumentExt = "ogg"
+ attack_verb = list("scruggs-styled", "hum-diggitied", "shin-digged", "clawhammered")
+ hitsound = 'sound/weapons/banjoslap.ogg'
+ instrumentId = "banjo"
+
/obj/item/instrument/guitar
name = "guitar"
desc = "It's made of wood and has bronze strings."
@@ -263,8 +273,6 @@
throw_range = 15
hitsound = 'sound/items/bikehorn.ogg'
-///
-
/obj/item/musicaltuner
name = "musical tuner"
desc = "A device for tuning musical instruments both manual and electronic alike."
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index cc470466df..1f2f1ddda2 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -56,6 +56,14 @@
else
return ..()
+/obj/item/laser_pointer/examine(mob/user)
+ . = ..()
+ if(in_range(user, src) || isobserver(user))
+ if(!diode)
+ . += "The diode is missing."
+ else
+ . += "A class [diode.rating] laser diode is installed. It is screwed in place."
+
/obj/item/laser_pointer/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
laser_act(target, user, params)
diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm
index 6aee67f2ee..d5cf6daabb 100644
--- a/code/game/objects/items/devices/radio/electropack.dm
+++ b/code/game/objects/items/devices/radio/electropack.dm
@@ -144,3 +144,80 @@ Code:
user << browse(dat, "window=radio")
onclose(user, "radio")
return
+
+/obj/item/electropack/shockcollar
+ name = "shock collar"
+ desc = "A reinforced metal collar. It seems to have some form of wiring near the front. Strange.."
+ icon = 'modular_citadel/icons/obj/clothing/cit_neck.dmi'
+ alternate_worn_icon = 'modular_citadel/icons/mob/citadel/neck.dmi'
+ icon_state = "shockcollar"
+ item_state = "shockcollar"
+ body_parts_covered = NECK
+ slot_flags = ITEM_SLOT_NECK | ITEM_SLOT_DENYPOCKET //no more pocket shockers
+ w_class = WEIGHT_CLASS_SMALL
+ strip_delay = 60
+ equip_delay_other = 60
+ materials = list(MAT_METAL=5000, MAT_GLASS=2000)
+
+ var/tagname = null
+
+/datum/design/electropack/shockcollar
+ name = "Shockcollar"
+ id = "shockcollar"
+ build_type = AUTOLATHE
+ build_path = /obj/item/electropack/shockcollar
+ materials = list(MAT_METAL=5000, MAT_GLASS=2000)
+ category = list("hacked", "Misc")
+
+/obj/item/electropack/shockcollar/attack_hand(mob/user)
+ if(loc == user && user.get_item_by_slot(SLOT_NECK))
+ to_chat(user, "The collar is fastened tight! You'll need help taking this off!")
+ return
+ return ..()
+
+/obj/item/electropack/shockcollar/receive_signal(datum/signal/signal)
+ if(!signal || signal.data["code"] != code)
+ return
+
+ if(isliving(loc) && on)
+ if(shock_cooldown == TRUE)
+ return
+ shock_cooldown = TRUE
+ addtimer(VARSET_CALLBACK(src, shock_cooldown, FALSE), 100)
+ var/mob/living/L = loc
+ step(L, pick(GLOB.cardinals))
+
+ to_chat(L, "You feel a sharp shock from the collar!")
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(3, 1, L)
+ s.start()
+
+ L.Knockdown(100)
+
+ if(master)
+ master.receive_signal()
+ return
+
+/obj/item/electropack/shockcollar/attackby(obj/item/W, mob/user, params) //moves it here because on_click is being bad
+ if(istype(W, /obj/item/pen))
+ var/t = input(user, "Would you like to change the name on the tag?", "Name your new pet", tagname ? tagname : "Spot") as null|text
+ if(t)
+ tagname = copytext(sanitize(t), 1, MAX_NAME_LEN)
+ name = "[initial(name)] - [tagname]"
+ else
+ return ..()
+
+/obj/item/electropack/shockcollar/ui_interact(mob/user) //on_click calls this
+ var/dat = {"
+
+Frequency/Code for shock collar:
+Frequency:
+[format_frequency(src.frequency)]
+Set
+Code:
+[src.code]
+Set
+"}
+ user << browse(dat, "window=radio")
+ onclose(user, "radio")
+ return
diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm
index cc009b5fc2..e26b9dd845 100644
--- a/code/game/objects/items/devices/radio/encryptionkey.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey.dm
@@ -92,7 +92,13 @@
/obj/item/encryptionkey/heads/hop
name = "\proper the head of personnel's encryption key"
icon_state = "hop_cypherkey"
- channels = list(RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_COMMAND = 1)
+ channels = list(RADIO_CHANNEL_SERVICE = 1, RADIO_CHANNEL_COMMAND = 1)
+
+/obj/item/encryptionkey/heads/qm
+ name = "\proper the quartermaster's encryption key"
+ desc = "An encryption key for a radio headset. Channels are as follows: :u - supply, :c - command."
+ icon_state = "hop_cypherkey"
+ channels = list(RADIO_CHANNEL_SUPPLY = 1, RADIO_CHANNEL_COMMAND = 1)
/obj/item/encryptionkey/headset_cargo
name = "supply radio encryption key"
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 13cd30561a..8c6666085e 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -206,6 +206,12 @@ GLOBAL_LIST_INIT(channel_tokens, list(
icon_state = "com_headset"
keyslot = new /obj/item/encryptionkey/heads/hop
+/obj/item/radio/headset/heads/qm
+ name = "\proper the quartermaster's headset"
+ desc = "The headset of the king (or queen) of paperwork."
+ icon_state = "com_headset"
+ keyslot = new /obj/item/encryptionkey/heads/qm
+
/obj/item/radio/headset/headset_cargo
name = "supply radio headset"
desc = "A headset used by the QM and his slaves."
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 3b296e5773..57c5a22de0 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -466,7 +466,7 @@ SLIME SCANNER
msg += "Subject is not addicted to any reagents.\n"
var/datum/reagent/impure/fermiTox/F = M.reagents.has_reagent(/datum/reagent/impure/fermiTox)
- if(istype(F))
+ if(istype(F,/datum/reagent/impure/fermiTox))
switch(F.volume)
if(5 to 10)
msg += "Subject contains a low amount of toxic isomers.\n"
diff --git a/code/game/objects/items/dice.dm b/code/game/objects/items/dice.dm
index f27884d3ae..b1dd9be376 100644
--- a/code/game/objects/items/dice.dm
+++ b/code/game/objects/items/dice.dm
@@ -160,7 +160,7 @@
/obj/item/dice/attack_self(mob/user)
diceroll(user)
-/obj/item/dice/throw_impact(atom/target)
+/obj/item/dice/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
diceroll(thrownby)
. = ..()
diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm
index 4f3dab803d..16a5e6d1d3 100644
--- a/code/game/objects/items/grenades/grenade.dm
+++ b/code/game/objects/items/grenades/grenade.dm
@@ -93,9 +93,8 @@
var/obj/item/I = loc
I.grenade_prime_react(src)
-
-/obj/item/grenade/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/screwdriver))
+/obj/item/grenade/tool_act(mob/living/user, obj/item/I, tool_behaviour)
+ if(tool_behaviour == TOOL_SCREWDRIVER)
switch(det_time)
if ("1")
det_time = 10
@@ -122,3 +121,6 @@
owner.visible_message("[attack_text] hits [owner]'s [src], setting it off! What a shot!")
prime()
return TRUE //It hit the grenade, not them
+
+/obj/item/proc/grenade_prime_react(obj/item/grenade/nade)
+ return
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 849e14b476..f6f14554ed 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -340,7 +340,7 @@
return
playsound(src.loc,'sound/weapons/bolathrow.ogg', 75, 1)
-/obj/item/restraints/legcuffs/bola/throw_impact(atom/hit_atom)
+/obj/item/restraints/legcuffs/bola/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(..() || !iscarbon(hit_atom))//if it gets caught or the target can't be cuffed,
return//abort
var/mob/living/carbon/C = hit_atom
@@ -368,7 +368,7 @@
w_class = WEIGHT_CLASS_SMALL
breakouttime = 60
-/obj/item/restraints/legcuffs/bola/energy/throw_impact(atom/hit_atom)
+/obj/item/restraints/legcuffs/bola/energy/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(iscarbon(hit_atom))
var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(hit_atom))
B.Crossed(hit_atom)
diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm
index 11be6b88e9..ef5b7b6cba 100644
--- a/code/game/objects/items/latexballoon.dm
+++ b/code/game/objects/items/latexballoon.dm
@@ -40,8 +40,10 @@
if (prob(50))
qdel(src)
-/obj/item/latexballon/bullet_act()
- burst()
+/obj/item/latexballon/bullet_act(obj/item/projectile/P)
+ if(!P.nodamage)
+ burst()
+ return ..()
/obj/item/latexballon/temperature_expose(datum/gas_mixture/air, temperature, volume)
if(temperature > T0C+100)
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 4242fb6c4b..4b071d6a34 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -333,13 +333,13 @@
if(proximity_flag)
consume_everything(target)
-/obj/item/melee/supermatter_sword/throw_impact(target)
+/obj/item/melee/supermatter_sword/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
..()
- if(ismob(target))
- var/mob/M
+ if(ismob(hit_atom))
+ var/mob/M = hit_atom
if(src.loc == M)
M.dropItemToGround(src)
- consume_everything(target)
+ consume_everything(hit_atom)
/obj/item/melee/supermatter_sword/pickup(user)
..()
@@ -358,7 +358,8 @@
/obj/item/melee/supermatter_sword/bullet_act(obj/item/projectile/P)
visible_message("[P] smacks into [src] and rapidly flashes to ash.",\
"You hear a loud crack as you are washed with a wave of heat.")
- consume_everything()
+ consume_everything(P)
+ return BULLET_ACT_HIT
/obj/item/melee/supermatter_sword/suicide_act(mob/user)
user.visible_message("[user] touches [src]'s blade. It looks like [user.p_theyre()] tired of waiting for the radiation to kill [user.p_them()]!")
diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm
index 7f7780d3a4..acfc1353b9 100644
--- a/code/game/objects/items/robot/ai_upgrades.dm
+++ b/code/game/objects/items/robot/ai_upgrades.dm
@@ -9,8 +9,10 @@
icon_state = "datadisk3"
-/obj/item/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user)
+/obj/item/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user, proximity)
. = ..()
+ if(!proximity)
+ return
if(!istype(AI))
return
if(AI.malf_picker)
@@ -18,7 +20,11 @@
to_chat(AI, "[user] has attempted to upgrade you with combat software that you already possess. You gain 50 points to spend on Malfunction Modules instead.")
else
to_chat(AI, "[user] has upgraded you with combat software!")
+ to_chat(AI, "Your current laws and objectives remain unchanged.") //this unlocks malf powers, but does not give the license to plasma flood
AI.add_malf_picker()
+ AI.hack_software = TRUE
+ log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].")
to_chat(user, "You upgrade [AI]. [src] is consumed in the process.")
qdel(src)
@@ -26,12 +32,14 @@
//Lipreading
/obj/item/surveillance_upgrade
name = "surveillance software upgrade"
- desc = "A software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading."
+ desc = "An illegal software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading and hidden microphones."
icon = 'icons/obj/module.dmi'
icon_state = "datadisk3"
-/obj/item/surveillance_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user)
+/obj/item/surveillance_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user, proximity)
. = ..()
+ if(!proximity)
+ return
if(!istype(AI))
return
if(AI.eyeobj)
@@ -39,4 +47,6 @@
to_chat(AI, "[user] has upgraded you with surveillance software!")
to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.")
to_chat(user, "You upgrade [AI]. [src] is consumed in the process.")
+ log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].")
+ message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].")
qdel(src)
diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm
index 256e84973d..2f40604719 100644
--- a/code/game/objects/items/shooting_range.dm
+++ b/code/game/objects/items/shooting_range.dm
@@ -60,7 +60,7 @@
#define DECALTYPE_BULLET 2
/obj/item/target/clown/bullet_act(obj/item/projectile/P)
- ..()
+ . = ..()
playsound(src.loc, 'sound/items/bikehorn.ogg', 50, 1)
/obj/item/target/bullet_act(obj/item/projectile/P)
@@ -89,8 +89,8 @@
else
bullet_hole.icon_state = "dent"
add_overlay(bullet_hole)
- return
- return -1
+ return BULLET_ACT_HIT
+ return BULLET_ACT_FORCE_PIERCE
#undef DECALTYPE_SCORCH
#undef DECALTYPE_BULLET
diff --git a/code/game/objects/items/singularityhammer.dm b/code/game/objects/items/singularityhammer.dm
index f55dae67db..86f0ad4936 100644
--- a/code/game/objects/items/singularityhammer.dm
+++ b/code/game/objects/items/singularityhammer.dm
@@ -105,10 +105,10 @@
playsound(src.loc, "sparks", 50, 1)
shock(M)
-/obj/item/twohanded/mjollnir/throw_impact(atom/target)
+/obj/item/twohanded/mjollnir/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
- if(isliving(target))
- shock(target)
+ if(isliving(hit_atom))
+ shock(hit_atom)
/obj/item/twohanded/mjollnir/update_icon() //Currently only here to fuck with the on-mob icons.
icon_state = "mjollnir[wielded]"
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index bb1a475f1f..e2357e8f6d 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -35,7 +35,7 @@
/obj/item/stack/ore/bluespace_crystal/proc/blink_mob(mob/living/L)
do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
-/obj/item/stack/ore/bluespace_crystal/throw_impact(atom/hit_atom)
+/obj/item/stack/ore/bluespace_crystal/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..()) // not caught in mid-air
visible_message("[src] fizzles and disappears upon impact!")
var/turf/T = get_turf(hit_atom)
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 4180681754..324b40ac7f 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -202,6 +202,7 @@
if(O)
O.setDir(usr.dir)
use(R.req_amount * multiplier)
+ log_craft("[O] crafted by [usr] at [loc_name(O.loc)]")
//START: oh fuck i'm so sorry
if(istype(O, /obj/structure/windoor_assembly))
@@ -341,7 +342,7 @@
merge(o)
. = ..()
-/obj/item/stack/hitby(atom/movable/AM, skip, hitpush)
+/obj/item/stack/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(istype(AM, merge_type))
merge(AM)
. = ..()
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index 3ae0a4bd17..946eb1eb7b 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -41,7 +41,7 @@
cell = new preload_cell_type(src)
update_icon()
-/obj/item/melee/baton/throw_impact(atom/hit_atom)
+/obj/item/melee/baton/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
..()
//Only mob/living types have stun handling
if(status && prob(throw_hit_chance) && iscarbon(hit_atom))
@@ -223,6 +223,46 @@
if(!iscyborg(loc))
deductcharge(1000 / severity, TRUE, FALSE)
+/obj/item/melee/baton/stunsword
+ name = "stunsword"
+ desc = "not actually sharp, this sword is functionally identical to a stunbaton"
+ icon = 'modular_citadel/icons/obj/stunsword.dmi'
+ icon_state = "stunsword"
+ item_state = "sword"
+ lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
+ righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
+
+/obj/item/melee/baton/stunsword/get_belt_overlay()
+ if(istype(loc, /obj/item/storage/belt/sabre))
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "stunsword")
+ return ..()
+
+/obj/item/melee/baton/stunsword/get_worn_belt_overlay(icon_file)
+ return mutable_appearance(icon_file, "-stunsword")
+
+/obj/item/ssword_kit
+ name = "stunsword kit"
+ desc = "a modkit for making a stunbaton into a stunsword"
+ icon = 'icons/obj/vending_restock.dmi'
+ icon_state = "refill_donksoft"
+ var/product = /obj/item/melee/baton/stunsword //what it makes
+ var/list/fromitem = list(/obj/item/melee/baton, /obj/item/melee/baton/loaded) //what it needs
+ afterattack(obj/O, mob/user as mob)
+ if(istype(O, product))
+ to_chat(user,"[O] is already modified!")
+ else if(O.type in fromitem) //makes sure O is the right thing
+ var/obj/item/melee/baton/B = O
+ if(!B.cell) //checks for a powercell in the baton. If there isn't one, continue. If there is, warn the user to take it out
+ new product(usr.loc) //spawns the product
+ user.visible_message("[user] modifies [O]!","You modify the [O]!")
+ qdel(O) //Gets rid of the baton
+ qdel(src) //gets rid of the kit
+
+ else
+ to_chat(user,"Remove the powercell first!") //We make this check because the stunsword starts without a battery.
+ else
+ to_chat(user, " You can't modify [O] with this kit!")
+
//Makeshift stun baton. Replacement for stun gloves.
/obj/item/melee/baton/cattleprod
name = "stunprod"
@@ -249,5 +289,6 @@
sparkler?.activate()
. = ..()
+
#undef STUNBATON_CHARGE_LENIENCY
#undef STUNBATON_DEPLETION_RATE
diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm
index d52c280f1b..9b9fae7c8f 100644
--- a/code/game/objects/items/theft_tools.dm
+++ b/code/game/objects/items/theft_tools.dm
@@ -259,7 +259,7 @@
if(proximity && ismovableatom(O) && O != sliver)
Consume(O, user)
-/obj/item/hemostat/supermatter/throw_impact(atom/hit_atom) // no instakill supermatter javelins
+/obj/item/hemostat/supermatter/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) // no instakill supermatter javelins
if(sliver)
sliver.forceMove(loc)
to_chat(usr, "\The [sliver] falls out of \the [src] as you throw them.")
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index cf891f5a47..92798528ae 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -84,7 +84,7 @@
else
return ..()
-/obj/item/toy/balloon/throw_impact(atom/hit_atom)
+/obj/item/toy/balloon/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..()) //was it caught by a mob?
balloon_burst(hit_atom)
@@ -531,7 +531,7 @@
/obj/item/toy/snappop/fire_act(exposed_temperature, exposed_volume)
pop_burst()
-/obj/item/toy/snappop/throw_impact(atom/hit_atom)
+/obj/item/toy/snappop/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..())
pop_burst()
@@ -1152,7 +1152,7 @@
icon_state = "minimeteor"
w_class = WEIGHT_CLASS_SMALL
-/obj/item/toy/minimeteor/throw_impact(atom/hit_atom)
+/obj/item/toy/minimeteor/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..())
playsound(src, 'sound/effects/meteorimpact.ogg', 40, 1)
for(var/mob/M in urange(10, src))
@@ -1201,7 +1201,7 @@
if(user.dropItemToGround(src))
throw_at(target, throw_range, throw_speed)
-/obj/item/toy/snowball/throw_impact(atom/hit_atom)
+/obj/item/toy/snowball/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
if(!..())
playsound(src, 'sound/effects/pop.ogg', 20, 1)
qdel(src)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 70a05a8d40..2d99f0e073 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -46,7 +46,7 @@
if(BURN)
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
-/obj/hitby(atom/movable/AM)
+/obj/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
..()
var/throwdamage = AM.throwforce
if(isobj(AM))
@@ -126,6 +126,17 @@
if(. && !play_soundeffect)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
+/obj/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ return TRUE
+
+/obj/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ collision_damage(pusher, force, direction)
+ return TRUE
+
+/obj/proc/collision_damage(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10)
+ take_damage(amt, BRUTE)
+
/obj/attack_slime(mob/living/simple_animal/slime/user)
if(!user.is_adult)
return
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 8899f2f79f..5f3fc48eb7 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -80,7 +80,7 @@
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
anchored = anchorvalue
-/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, messy_throw)
+/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE)
. = ..()
if(obj_flags & FROZEN)
visible_message("[src] shatters into a million pieces!")
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
index 9ed148b4e3..c3a23cb171 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
@@ -66,6 +66,14 @@
req_access = null
locked = FALSE
+/obj/structure/closet/secure_closet/freezer/gulag_fridge
+ name = "refrigerator"
+
+/obj/structure/closet/secure_closet/freezer/gulag_fridge/PopulateContents()
+ ..()
+ for(var/i in 1 to 3)
+ new /obj/item/reagent_containers/food/drinks/beer/light(src)
+
/obj/structure/closet/secure_closet/freezer/fridge
name = "refrigerator"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index ad482b68af..1517b30d9c 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -29,7 +29,6 @@
new /obj/item/radio/headset/heads/captain(src)
new /obj/item/clothing/glasses/sunglasses/gar/supergar(src)
new /obj/item/clothing/gloves/color/captain(src)
- new /obj/item/restraints/handcuffs/cable/zipties(src)
new /obj/item/storage/belt/sabre(src)
new /obj/item/gun/energy/e_gun(src)
new /obj/item/door_remote/captain(src)
@@ -291,3 +290,17 @@
..()
for(var/i in 1 to 3)
new /obj/item/storage/box/lethalshot(src)
+
+/obj/structure/closet/secure_closet/labor_camp_security
+ name = "labor camp security locker"
+ req_access = list(ACCESS_SECURITY)
+ icon_state = "sec"
+
+/obj/structure/closet/secure_closet/labor_camp_security/PopulateContents()
+ ..()
+ new /obj/item/clothing/suit/armor/vest(src)
+ new /obj/item/clothing/head/helmet/sec(src)
+ new /obj/item/clothing/under/rank/security(src)
+ new /obj/item/clothing/under/rank/security/skirt(src)
+ new /obj/item/clothing/glasses/hud/security/sunglasses(src)
+ new /obj/item/flashlight/seclite(src)
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 0cce1de41b..92fb13c947 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -46,6 +46,7 @@
roundstart = FALSE
death = FALSE
anchored = FALSE
+ move_resist = MOVE_FORCE_NORMAL
density = FALSE
flavour_text = "You are an ash walker. Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. You would never leave its beautiful expanse. \
You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest."
@@ -120,6 +121,7 @@
roundstart = FALSE
death = FALSE
anchored = FALSE
+ move_resist = MOVE_FORCE_NORMAL
density = FALSE
var/has_owner = FALSE
var/can_transfer = TRUE //if golems can switch bodies to this new shell
@@ -645,6 +647,7 @@
SSjob.equip_loadout(null, new_spawn, FALSE)
SSquirks.AssignQuirks(new_spawn, new_spawn.client, TRUE, TRUE, null, FALSE, new_spawn)
new_spawn.AddElement(/datum/element/ghost_role_eligibility)
+ new_spawn.AddElement(/datum/element/dusts_on_catatonia)
ADD_TRAIT(new_spawn, TRAIT_SIXTHSENSE, GHOSTROLE_TRAIT)
ADD_TRAIT(new_spawn,TRAIT_EXEMPT_HEALTH_EVENTS,GHOSTROLE_TRAIT)
ADD_TRAIT(new_spawn,TRAIT_PACIFISM,GHOSTROLE_TRAIT)
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 205e87329b..0d4444303e 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -258,7 +258,7 @@
take_damage(1, BURN, 0, 0)
..()
-/obj/structure/grille/hitby(AM as mob|obj)
+/obj/structure/grille/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(isobj(AM))
if(prob(50) && anchored && !broken)
var/obj/O = AM
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index 69ad9f1567..617f42ed29 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -106,6 +106,7 @@
take_damage(10, BRUTE, "melee", 1) //Tasers aren't harmful.
if(istype(P, /obj/item/projectile/beam/disabler))
take_damage(5, BRUTE, "melee", 1) //Disablers aren't harmful.
+ return BULLET_ACT_HIT
/obj/structure/holosign/barrier/medical
name = "\improper PENLITE holobarrier"
@@ -152,6 +153,7 @@
/obj/structure/holosign/barrier/cyborg/hacked/bullet_act(obj/item/projectile/P)
take_damage(P.damage, BRUTE, "melee", 1) //Yeah no this doesn't get projectile resistance.
+ return BULLET_ACT_HIT
/obj/structure/holosign/barrier/cyborg/hacked/proc/cooldown()
shockcd = FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm
similarity index 71%
rename from code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm
rename to code/game/objects/structures/lavaland/necropolis_tendril.dm
index 27ebb71c0e..6ce0228f54 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/necropolis_tendril.dm
+++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm
@@ -1,39 +1,32 @@
//Necropolis Tendrils, which spawn lavaland monsters and break into a chasm when killed
-/obj/effect/light_emitter/tendril
- set_luminosity = 4
- set_cap = 2.5
- light_color = LIGHT_COLOR_LAVA
-
-/mob/living/simple_animal/hostile/spawner/lavaland
+/obj/structure/spawner/lavaland
name = "necropolis tendril"
desc = "A vile tendril of corruption, originating deep underground. Terrible monsters are pouring out of it."
+
icon = 'icons/mob/nest.dmi'
icon_state = "tendril"
- icon_living = "tendril"
- icon_dead = "tendril"
+
faction = list("mining")
- weather_immunities = list("lava","ash")
- health = 250
- maxHealth = 250
max_mobs = 3
- spawn_time = 300 //30 seconds default
+ max_integrity = 250
mob_types = list(/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/tendril)
- spawn_text = "emerges from"
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
- maxbodytemp = INFINITY
- loot = list(/obj/effect/collapse, /obj/structure/closet/crate/necropolis/tendril)
- del_on_death = 1
+
+ move_resist=INFINITY // just killing it tears a massive hole in the ground, let's not move it
+ anchored = TRUE
+ resistance_flags = FIRE_PROOF | LAVA_PROOF
+
var/gps = null
var/obj/effect/light_emitter/tendril/emitted_light
-/mob/living/simple_animal/hostile/spawner/lavaland/goliath
+
+/obj/structure/spawner/lavaland/goliath
mob_types = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/tendril)
-/mob/living/simple_animal/hostile/spawner/lavaland/legion
+/obj/structure/spawner/lavaland/legion
mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril)
-/mob/living/simple_animal/hostile/spawner/lavaland/Initialize()
+GLOBAL_LIST_INIT(tendrils, list())
+/obj/structure/spawner/lavaland/Initialize()
. = ..()
emitted_light = new(loc)
for(var/F in RANGE_TURFS(1, src))
@@ -41,18 +34,19 @@
var/turf/closed/mineral/M = F
M.ScrapeAway(null, CHANGETURF_IGNORE_AIR)
gps = new /obj/item/gps/internal(src)
+ GLOB.tendrils += src
-/mob/living/simple_animal/hostile/spawner/lavaland/Destroy()
- QDEL_NULL(emitted_light)
- QDEL_NULL(gps)
+/obj/structure/spawner/lavaland/deconstruct(disassembled)
+ new /obj/effect/collapse(loc)
+ new /obj/structure/closet/crate/necropolis/tendril(loc)
return ..()
-/mob/living/simple_animal/hostile/spawner/lavaland/death()
+
+/obj/structure/spawner/lavaland/Destroy()
var/last_tendril = TRUE
- for(var/mob/living/simple_animal/hostile/spawner/lavaland/other in GLOB.mob_living_list)
- if(other != src)
- last_tendril = FALSE
- break
+ if(GLOB.tendrils.len>1)
+ last_tendril = FALSE
+
if(last_tendril && !(flags_1 & ADMIN_SPAWNED_1))
if(SSmedals.hub_enabled)
for(var/mob/living/L in view(7,src))
@@ -60,7 +54,15 @@
continue
SSmedals.UnlockMedal("[BOSS_MEDAL_TENDRIL] [ALL_KILL_MEDAL]", L.client)
SSmedals.SetScore(TENDRIL_CLEAR_SCORE, L.client, 1)
- ..()
+ GLOB.tendrils -= src
+ QDEL_NULL(emitted_light)
+ QDEL_NULL(gps)
+ return ..()
+
+/obj/effect/light_emitter/tendril
+ set_luminosity = 4
+ set_cap = 2.5
+ light_color = LIGHT_COLOR_LAVA
/obj/effect/collapse
name = "collapsing necropolis tendril"
@@ -92,4 +94,4 @@
for(var/turf/T in range(2,src))
if(!T.density)
T.TerraformTurf(/turf/open/chasm/lavaland, /turf/open/chasm/lavaland, flags = CHANGETURF_INHERIT_AIR)
- qdel(src)
+ qdel(src)
\ No newline at end of file
diff --git a/code/game/objects/structures/reflector.dm b/code/game/objects/structures/reflector.dm
index cde60e15c1..5cc2315352 100644
--- a/code/game/objects/structures/reflector.dm
+++ b/code/game/objects/structures/reflector.dm
@@ -64,15 +64,15 @@
var/ploc = get_turf(P)
if(!finished || !allowed_projectile_typecache[P.type] || !(P.dir in GLOB.cardinals))
return ..()
- if(auto_reflect(P, pdir, ploc, pangle) != -1)
+ if(auto_reflect(P, pdir, ploc, pangle) != BULLET_ACT_FORCE_PIERCE)
return ..()
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/reflector/proc/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
P.ignore_source_check = TRUE
P.range = P.decayedRange
P.decayedRange = max(P.decayedRange--, 0)
- return -1
+ return BULLET_ACT_FORCE_PIERCE
/obj/structure/reflector/attackby(obj/item/W, mob/user, params)
if(admin)
diff --git a/code/game/objects/structures/spawner.dm b/code/game/objects/structures/spawner.dm
new file mode 100644
index 0000000000..e67ef7af60
--- /dev/null
+++ b/code/game/objects/structures/spawner.dm
@@ -0,0 +1,75 @@
+/obj/structure/spawner
+ name = "monster nest"
+ icon = 'icons/mob/animal.dmi'
+ icon_state = "hole"
+ max_integrity = 100
+
+ move_resist = MOVE_FORCE_EXTREMELY_STRONG
+ anchored = TRUE
+ density = TRUE
+
+ var/max_mobs = 5
+ var/spawn_time = 300 //30 seconds default
+ var/mob_types = list(/mob/living/simple_animal/hostile/carp)
+ var/spawn_text = "emerges from"
+ var/faction = list("hostile")
+
+/obj/structure/spawner/Initialize()
+ . = ..()
+ AddComponent(/datum/component/spawner, mob_types, spawn_time, faction, spawn_text, max_mobs)
+
+/obj/structure/spawner/syndicate
+ name = "warp beacon"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "syndbeacon"
+ spawn_text = "warps in from"
+ mob_types = list(/mob/living/simple_animal/hostile/syndicate/ranged)
+ faction = list(ROLE_SYNDICATE)
+
+/obj/structure/spawner/skeleton
+ name = "bone pit"
+ desc = "A pit full of bones, and some still seem to be moving..."
+ icon_state = "hole"
+ icon = 'icons/mob/nest.dmi'
+ max_integrity = 150
+ max_mobs = 15
+ spawn_time = 150
+ mob_types = list(/mob/living/simple_animal/hostile/skeleton)
+ spawn_text = "climbs out of"
+ faction = list("skeleton")
+
+/obj/structure/spawner/mining
+ name = "monster den"
+ desc = "A hole dug into the ground, harboring all kinds of monsters found within most caves or mining asteroids."
+ icon_state = "hole"
+ max_integrity = 200
+ max_mobs = 3
+ icon = 'icons/mob/nest.dmi'
+ spawn_text = "crawls out of"
+ mob_types = list(/mob/living/simple_animal/hostile/asteroid/goldgrub, /mob/living/simple_animal/hostile/asteroid/goliath, /mob/living/simple_animal/hostile/asteroid/hivelord, /mob/living/simple_animal/hostile/asteroid/basilisk, /mob/living/simple_animal/hostile/asteroid/fugu)
+ faction = list("mining")
+
+/obj/structure/spawner/mining/goldgrub
+ name = "goldgrub den"
+ desc = "A den housing a nest of goldgrubs, annoying but arguably much better than anything else you'll find in a nest."
+ mob_types = list(/mob/living/simple_animal/hostile/asteroid/goldgrub)
+
+/obj/structure/spawner/mining/goliath
+ name = "goliath den"
+ desc = "A den housing a nest of goliaths, oh god why?"
+ mob_types = list(/mob/living/simple_animal/hostile/asteroid/goliath)
+
+/obj/structure/spawner/mining/hivelord
+ name = "hivelord den"
+ desc = "A den housing a nest of hivelords."
+ mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord)
+
+/obj/structure/spawner/mining/basilisk
+ name = "basilisk den"
+ desc = "A den housing a nest of basilisks, bring a coat."
+ mob_types = list(/mob/living/simple_animal/hostile/asteroid/basilisk)
+
+/obj/structure/spawner/mining/wumborian
+ name = "wumborian fugu den"
+ desc = "A den housing a nest of wumborian fugus, how do they all even fit in there?"
+ mob_types = list(/mob/living/simple_animal/hostile/asteroid/fugu)
\ No newline at end of file
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index 5e6b35ba4f..9a6b24b472 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -124,7 +124,7 @@
message_admins("Plasma statue ignited by [Proj]. No known firer, in [ADMIN_VERBOSEJMP(T)]")
log_game("Plasma statue ignited by [Proj] in [AREACOORD(T)]. No known firer.")
PlasmaBurn(2500)
- ..()
+ return ..()
/obj/structure/statue/plasma/attackby(obj/item/W, mob/user, params)
if(W.get_temperature() > 300 && !QDELETED(src))//If the temperature of the object is over 300, then ignite
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index b69b98ceaa..9dcfec43bf 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -71,6 +71,5 @@
/obj/structure/target_stake/bullet_act(obj/item/projectile/P)
if(pinned_target)
- pinned_target.bullet_act(P)
- else
- ..()
+ return pinned_target.bullet_act(P)
+ return ..()
diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm
index ecc8ee5e8d..053b18d8d2 100644
--- a/code/game/turfs/simulated/floor/plating/asteroid.dm
+++ b/code/game/turfs/simulated/floor/plating/asteroid.dm
@@ -151,9 +151,9 @@
has_data = TRUE
/turf/open/floor/plating/asteroid/airless/cave/volcanic
- mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/random = 50, /mob/living/simple_animal/hostile/spawner/lavaland/goliath = 3, \
- /mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random = 40, /mob/living/simple_animal/hostile/spawner/lavaland = 2, \
- /mob/living/simple_animal/hostile/asteroid/hivelord/legion/random = 30, /mob/living/simple_animal/hostile/spawner/lavaland/legion = 3, \
+ mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/random = 50, /obj/structure/spawner/lavaland/goliath = 3, \
+ /mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random = 40, /obj/structure/spawner/lavaland = 2, \
+ /mob/living/simple_animal/hostile/asteroid/hivelord/legion/random = 30, /obj/structure/spawner/lavaland/legion = 3, \
SPAWN_MEGAFAUNA = 6, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10)
data_having_type = /turf/open/floor/plating/asteroid/airless/cave/volcanic/has_data
@@ -274,7 +274,7 @@
return //if there's a megafauna within standard view don't spawn anything at all
if(ispath(randumb, /mob/living/simple_animal/hostile/asteroid) || istype(H, /mob/living/simple_animal/hostile/asteroid))
return //if the random is a standard mob, avoid spawning if there's another one within 12 tiles
- if((ispath(randumb, /mob/living/simple_animal/hostile/spawner/lavaland) || istype(H, /mob/living/simple_animal/hostile/spawner/lavaland)) && get_dist(src, H) <= 2)
+ if((ispath(randumb, /obj/structure/spawner/lavaland) || istype(H, /obj/structure/spawner/lavaland)) && get_dist(src, H) <= 2)
return //prevents tendrils spawning in each other's collapse range
new randumb(T)
diff --git a/code/game/turfs/simulated/lava.dm b/code/game/turfs/simulated/lava.dm
index 2f8ae0cb93..3a474f339c 100644
--- a/code/game/turfs/simulated/lava.dm
+++ b/code/game/turfs/simulated/lava.dm
@@ -36,7 +36,7 @@
if(burn_stuff(AM))
START_PROCESSING(SSobj, src)
-/turf/open/lava/hitby(atom/movable/AM)
+/turf/open/lava/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(burn_stuff(AM))
START_PROCESSING(SSobj, src)
diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm
index 73c1c465cd..d0e941e69f 100644
--- a/code/game/turfs/simulated/minerals.dm
+++ b/code/game/turfs/simulated/minerals.dm
@@ -65,13 +65,16 @@
if(I.use_tool(src, user, 40, volume=50))
var/range = I.digrange //Store the current digrange so people don't cheese digspeed swapping for faster mining
+ var/list/dug_tiles = list()
if(ismineralturf(src))
if(I.digrange > 0)
for(var/turf/closed/mineral/M in range(user,range))
if(get_dir(user,M)&stored_dir)
- M.gets_drilled()
+ M.gets_drilled(user)
+ dug_tiles += M
to_chat(user, "You finish cutting into the rock.")
- gets_drilled(user)
+ if(!(src in dug_tiles))
+ gets_drilled(user)
SSblackbox.record_feedback("tally", "pick_used_mining", 1, I.type)
else
return attack_hand(user)
@@ -615,4 +618,4 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
- defer_change = 1
\ No newline at end of file
+ defer_change = 1
diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm
index 9962f72d4a..be46d124ea 100644
--- a/code/game/turfs/simulated/wall/mineral_walls.dm
+++ b/code/game/turfs/simulated/wall/mineral_walls.dm
@@ -120,7 +120,7 @@
PlasmaBurn(2500)
else if(istype(Proj, /obj/item/projectile/ion))
PlasmaBurn(500)
- ..()
+ return ..()
/turf/closed/wall/mineral/wood
diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm
index 8b63d60939..d445be91cb 100644
--- a/code/game/turfs/simulated/wall/misc_walls.dm
+++ b/code/game/turfs/simulated/wall/misc_walls.dm
@@ -25,7 +25,7 @@
if(stored_pulling)
stored_pulling.setDir(get_dir(stored_pulling.loc, newloc))
stored_pulling.forceMove(src)
- H.start_pulling(stored_pulling, TRUE)
+ H.start_pulling(stored_pulling, supress_message = TRUE)
/turf/closed/wall/mineral/cult/ratvar_act()
. = ..()
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index e81b3d1062..d8434f986c 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -224,14 +224,20 @@
for(var/i in contents)
if(i == mover || i == mover.loc) // Multi tile objects and moving out of other objects
continue
+ if(QDELETED(mover))
+ break
var/atom/movable/thing = i
- if(thing.Cross(mover))
- continue
- if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1)))
- firstbump = thing
+ if(!thing.Cross(mover))
+ if(CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
+ mover.Bump(thing)
+ continue
+ else
+ if(!firstbump || ((thing.layer > firstbump.layer || thing.flags_1 & ON_BORDER_1) && !(firstbump.flags_1 & ON_BORDER_1)))
+ firstbump = thing
if(firstbump)
- mover.Bump(firstbump)
- return FALSE
+ if(!QDELETED(mover))
+ mover.Bump(firstbump)
+ return CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE)
return TRUE
/turf/Exit(atom/movable/mover, atom/newloc)
@@ -239,13 +245,16 @@
if(!.)
return FALSE
for(var/i in contents)
+ if(QDELETED(mover))
+ break
if(i == mover)
continue
var/atom/movable/thing = i
if(!thing.Uncross(mover, newloc))
if(thing.flags_1 & ON_BORDER_1)
mover.Bump(thing)
- return FALSE
+ if(!CHECK_BITFIELD(mover.movement_type, UNSTOPPABLE))
+ return FALSE
/turf/Entered(atom/movable/AM)
..()
@@ -563,3 +572,8 @@
//Should return new turf
/turf/proc/Melt()
return ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
+
+/turf/bullet_act(obj/item/projectile/P)
+ . = ..()
+ if(. != BULLET_ACT_FORCE_PIERCE)
+ . = BULLET_ACT_TURF
diff --git a/code/game/world.dm b/code/game/world.dm
index 5e7629fbb4..7afaf62bb8 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -34,10 +34,12 @@ GLOBAL_LIST(topic_status_cache)
#endif
load_admins()
+ load_mentors()
LoadVerbs(/datum/verbs/menu)
if(CONFIG_GET(flag/usewhitelist))
load_whitelist()
LoadBans()
+ initialize_global_loadout_items()
reload_custom_roundstart_items_list()//Cit change - loads donator items. Remind me to remove when I port over bay's loadout system
GLOB.timezoneOffset = text2num(time2text(0,"hh")) * 36000
@@ -49,8 +51,6 @@ GLOBAL_LIST(topic_status_cache)
if(NO_INIT_PARAMETER in params)
return
- cit_initialize()
-
Master.Initialize(10, FALSE, TRUE)
if(TEST_RUN_PARAMETER in params)
@@ -116,6 +116,7 @@ GLOBAL_LIST(topic_status_cache)
GLOB.query_debug_log = "[GLOB.log_directory]/query_debug.log"
GLOB.world_job_debug_log = "[GLOB.log_directory]/job_debug.log"
GLOB.subsystem_log = "[GLOB.log_directory]/subsystem.log"
+ GLOB.world_crafting_log = "[GLOB.log_directory]/crafting.log"
#ifdef UNIT_TESTS
GLOB.test_log = file("[GLOB.log_directory]/tests.log")
@@ -131,6 +132,7 @@ GLOBAL_LIST(topic_status_cache)
start_log(GLOB.world_runtime_log)
start_log(GLOB.world_job_debug_log)
start_log(GLOB.subsystem_log)
+ start_log(GLOB.world_crafting_log)
GLOB.changelog_hash = md5('html/changelog.html') //for telling if the changelog has changed recently
if(fexists(GLOB.config_error_log))
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index b0152e85f2..bbb12b6692 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -7,22 +7,33 @@
#define STICKYBAN_MAX_ADMIN_MATCHES 2
/world/IsBanned(key,address,computer_id,type,real_bans_only=FALSE)
+ var/static/key_cache = list()
+ if(!real_bans_only)
+ if(key_cache[key])
+ return list("reason"="concurrent connection attempts", "desc"="You are attempting to connect too fast. Try again.")
+ key_cache[key] = 1
+
if (!key || !address || !computer_id)
if(real_bans_only)
+ key_cache[key] = 0
return FALSE
log_access("Failed Login (invalid data): [key] [address]-[computer_id]")
+ key_cache[key] = 0
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]'. (If you continue to get this error, please restart byond or contact byond support.)")
if (text2num(computer_id) == 2147483647) //this cid causes stickybans to go haywire
log_access("Failed Login (invalid cid): [key] [address]-[computer_id]")
+ key_cache[key] = 0
return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided an invalid Computer ID.)")
if (type == "world")
+ key_cache[key] = 0
return ..() //shunt world topic banchecks to purely to byond's internal ban system
var/ckey = ckey(key)
var/client/C = GLOB.directory[ckey]
if (C && ckey == C.ckey && computer_id == C.computer_id && address == C.address)
+ key_cache[key] = 0
return //don't recheck connected clients.
var/admin = FALSE
@@ -38,21 +49,25 @@
addclientmessage(ckey,"You have been allowed to bypass the whitelist")
else
log_access("Failed Login: [key] - Not on whitelist")
+ key_cache[key] = 0
return list("reason"="whitelist", "desc" = "\nReason: You are not on the white list for this server")
//Guest Checking
if(!real_bans_only && IsGuestKey(key))
if (CONFIG_GET(flag/guest_ban))
log_access("Failed Login: [key] - Guests not allowed")
+ key_cache[key] = 0
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.")
if (CONFIG_GET(flag/panic_bunker) && SSdbcore.Connect())
log_access("Failed Login: [key] - Guests not allowed during panic bunker")
+ key_cache[key] = 0
return list("reason"="guest", "desc"="\nReason: Sorry but the server is currently not accepting connections from never before seen players or guests. If you have played on this server with a byond account before, please log in to the byond account you have played from.")
//Population Cap Checking
var/extreme_popcap = CONFIG_GET(number/extreme_popcap)
if(!real_bans_only && extreme_popcap && living_player_count() >= extreme_popcap && !admin)
log_access("Failed Login: [key] - Population cap reached")
+ key_cache[key] = 0
return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]")
if(CONFIG_GET(flag/ban_legacy_system))
@@ -66,6 +81,7 @@
addclientmessage(ckey,"You have been allowed to bypass a matching ban on [.["key"]]")
else
log_access("Failed Login: [key] [computer_id] [address] - Banned [.["reason"]]")
+ key_cache[key] = 0
return .
else
@@ -73,6 +89,7 @@
var/msg = "Ban database connection failure. Key [ckey] not checked"
log_world(msg)
message_admins(msg)
+ key_cache[key] = 0
return
var/ipquery = ""
@@ -86,6 +103,7 @@
var/datum/DBQuery/query_ban_check = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].ckey), ckey), IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("ban")].a_ckey), a_ckey), reason, expiration_time, duration, bantime, bantype, id, round_id FROM [format_table_name("ban")] WHERE (ckey = '[ckey]' [ipquery] [cidquery]) AND (bantype = 'PERMABAN' OR bantype = 'ADMIN_PERMABAN' OR ((bantype = 'TEMPBAN' OR bantype = 'ADMIN_TEMPBAN') AND expiration_time > Now())) AND isnull(unbanned)")
if(!query_ban_check.Execute(async = TRUE))
qdel(query_ban_check)
+ key_cache[key] = 0
return
while(query_ban_check.NextRow())
var/pkey = query_ban_check.item[1]
@@ -124,6 +142,7 @@
log_access("Failed Login: [key] [computer_id] [address] - Banned (#[banid]) [.["reason"]]")
qdel(query_ban_check)
+ key_cache[key] = 0
return .
qdel(query_ban_check)
@@ -138,6 +157,7 @@
//rogue ban in the process of being reverted.
if (cachedban && cachedban["reverting"])
+ key_cache[key] = 0
return null
if (cachedban && ckey != bannedckey)
@@ -165,6 +185,7 @@
newmatches_admin.len > STICKYBAN_MAX_ADMIN_MATCHES \
)
if (cachedban["reverting"])
+ key_cache[key] = 0
return null
cachedban["reverting"] = TRUE
@@ -182,6 +203,7 @@
cachedban["admin_matches_this_round"] = list()
cachedban -= "reverting"
world.SetConfig("ban", bannedckey, list2stickyban(cachedban))
+ key_cache[key] = 0
return null
//byond will not trigger isbanned() for "global" host bans,
@@ -191,6 +213,7 @@
log_admin("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]")
message_admins("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]")
addclientmessage(ckey,"You have been allowed to bypass a matching host/sticky ban on [bannedckey]")
+ key_cache[key] = 0
return null
if (C) //user is already connected!.
@@ -200,6 +223,7 @@
. = list("reason" = "Stickyban", "desc" = desc)
log_access("Failed Login: [key] [computer_id] [address] - StickyBanned [ban["message"]] Target Username: [bannedckey] Placed by [ban["admin"]]")
+ key_cache[key] = 0
return .
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 88e68158ed..372902e8d6 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -185,7 +185,6 @@
body += "Shade"
body += "
"
- if (M.client)
body += "
"
body += "Other actions:"
body += "
"
@@ -194,9 +193,9 @@
body += "Thunderdome 2 | "
body += "Thunderdome Admin | "
body += "Thunderdome Observer | "
-
- body += usr.client.citaPPoptions(M) // CITADEL
-
+ body += "Make mentor | "
+ body += "Remove mentor"
+ body += "Allow reentering round"
body += "
"
body += "