diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index aa3e1741b5..f4dc7d5d0d 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -125,6 +125,8 @@
#define FLASH_PROTECTION_NONE 0
#define FLASH_PROTECTION_MODERATE 1
#define FLASH_PROTECTION_MAJOR 2
+#define ANIMAL_SPAWN_DELAY round(config.respawn_delay / 6)
+#define DRONE_SPAWN_DELAY round(config.respawn_delay / 3)
#define ANIMAL_SPAWN_DELAY round(config.respawn_delay / 6)
#define DRONE_SPAWN_DELAY round(config.respawn_delay / 3)
@@ -171,4 +173,9 @@
#define BP_ALL list(BP_GROIN, BP_TORSO, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_FOOT, BP_R_FOOT, BP_L_LEG, BP_R_LEG)
#define SYNTH_BLOOD_COLOUR "#030303"
-#define SYNTH_FLESH_COLOUR "#575757"
\ No newline at end of file
+#define SYNTH_FLESH_COLOUR "#575757"
+
+#define MOB_PULL_NONE 0
+#define MOB_PULL_SMALLER 1
+#define MOB_PULL_SAME 2
+#define MOB_PULL_LARGER 3
\ No newline at end of file
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 73da615720..3b33e40a9e 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -5,6 +5,7 @@
density = 1
var/health = 100.0
flags = CONDUCT
+ w_class = 5
var/valve_open = 0
var/release_pressure = ONE_ATMOSPHERE
diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm
index ad664049fc..a5bdac7421 100644
--- a/code/game/machinery/atmoalter/pump.dm
+++ b/code/game/machinery/atmoalter/pump.dm
@@ -4,6 +4,7 @@
icon = 'icons/obj/atmos.dmi'
icon_state = "psiphon:0"
density = 1
+ w_class = 3
var/on = 0
var/direction_out = 0 //0 = siphoning, 1 = releasing
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index 457792c9e2..87997d32c8 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -4,6 +4,7 @@
icon = 'icons/obj/atmos.dmi'
icon_state = "pscrubber:0"
density = 1
+ w_class = 3
var/on = 0
var/volume_rate = 800
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 455c6256a4..6798f2b736 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -96,6 +96,8 @@ Class Procs:
/obj/machinery
name = "machinery"
icon = 'icons/obj/stationobjs.dmi'
+ w_class = 10
+
var/stat = 0
var/emagged = 0
var/use_power = 1
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 3aa221400b..055176246c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1,6 +1,8 @@
/obj/item
name = "item"
icon = 'icons/obj/items.dmi'
+ w_class = 3.0
+
var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
var/abstract = 0
var/r_speed = 1.0
@@ -8,7 +10,6 @@
var/burn_point = null
var/burning = null
var/hitsound = null
- var/w_class = 3.0
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
var/no_attack_log = 0 //If it's an item we don't want to log attack_logs with, set this to 1
pass_flags = PASSTABLE
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index f94f2d5313..b8bd8d95e1 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -1,7 +1,7 @@
/obj
//Used to store information about the contents of the object.
var/list/matter
-
+ var/w_class // Size of the object.
var/list/origin_tech = null //Used by R&D to determine what research bonuses it grants.
var/unacidable = 0 //universal "unacidabliness" var, here so you can use it in any obj.
animate_movement = 2
@@ -10,7 +10,6 @@
var/sharp = 0 // whether this object cuts
var/edge = 0 // whether this object is more likely to dismember
var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
-
var/damtype = "brute"
var/force = 0
var/armor_penetration = 0
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 886ccc2cae..5dea37ef51 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -1,5 +1,6 @@
/obj/structure
icon = 'icons/obj/structures.dmi'
+ w_class = 10
var/climbable
var/breakable
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 105f2987df..d7d4c1f36c 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -4,6 +4,7 @@
icon = 'icons/obj/closet.dmi'
icon_state = "closed"
density = 1
+ w_class = 5
var/icon_closed = "closed"
var/icon_opened = "open"
var/opened = 0
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 4ca726af22..cd859b1489 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -4,6 +4,7 @@
icon_state = "door_as_0"
anchored = 0
density = 1
+ w_class = 5
var/state = 0
var/base_icon_state = ""
var/base_name = "Airlock"
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 0e2efb1c9e..867dada6d9 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -3,6 +3,7 @@
anchored = 1
density = 1
layer = 2
+ w_class = 5
var/state = 0
var/health = 200
var/cover = 50 //how much cover the girder provides against projectiles.
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index b8048a93c0..2b8396c554 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -5,6 +5,7 @@
icon_state = "latticefull"
density = 0
anchored = 1.0
+ w_class = 3
layer = 2.3 //under pipes
// flags = CONDUCT
diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm
index 2fb8566dc9..1624a4bbde 100644
--- a/code/game/objects/structures/mop_bucket.dm
+++ b/code/game/objects/structures/mop_bucket.dm
@@ -4,6 +4,7 @@
icon = 'icons/obj/janitor.dmi'
icon_state = "mopbucket"
density = 1
+ w_class = 3
pressure_resistance = 5
flags = OPENCONTAINER
var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index 8c0b7aaa25..5d5fc2d943 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -4,6 +4,7 @@
opacity = 0
density = 0
layer = 3.5
+ w_class = 3
/obj/structure/sign/ex_act(severity)
switch(severity)
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index 4cea8bffc1..0e7546f271 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -5,6 +5,7 @@
icon_state = "dispenser"
density = 1
anchored = 1.0
+ w_class = 5
var/oxygentanks = 10
var/phorontanks = 10
var/list/oxytanks = list() //sorry for the similar var names
diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm
index fa45f65736..68b10ccf7a 100644
--- a/code/game/objects/structures/target_stake.dm
+++ b/code/game/objects/structures/target_stake.dm
@@ -5,6 +5,7 @@
icon = 'icons/obj/objects.dmi'
icon_state = "target_stake"
density = 1
+ w_class = 5
flags = CONDUCT
var/obj/item/target/pinned_target // the current pinned target
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index 81b094cac4..fb48f6249d 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -16,6 +16,7 @@ obj/structure/windoor_assembly
anchored = 0
density = 0
dir = NORTH
+ w_class = 3
var/obj/item/weapon/airlock_electronics/electronics = null
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index c2d6c57617..1d8686a678 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -3,6 +3,8 @@
desc = "A window."
icon = 'icons/obj/structures.dmi'
density = 1
+ w_class = 3
+
layer = 3.2//Just above doors
pressure_resistance = 4*ONE_ATMOSPHERE
anchored = 1.0
diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm
index d5f65385bf..15931f44d3 100644
--- a/code/modules/mob/holder.dm
+++ b/code/modules/mob/holder.dm
@@ -6,6 +6,7 @@ var/list/holder_mob_icon_cache = list()
desc = "You shouldn't ever see this."
icon = 'icons/obj/objects.dmi'
slot_flags = SLOT_HEAD | SLOT_HOLSTER
+ show_messages = 1
sprite_sheets = list(
"Vox" = 'icons/mob/species/vox/head.dmi'
@@ -43,6 +44,17 @@ var/list/holder_mob_icon_cache = list()
M.reset_view()
qdel(src)
+/obj/item/weapon/holder/GetID()
+ for(var/mob/M in contents)
+ var/obj/item/I = M.GetIdCard()
+ if(I)
+ return I
+ return null
+
+/obj/item/weapon/holder/GetAccess()
+ var/obj/item/I = GetID()
+ return I ? I.GetAccess() : ..()
+
/obj/item/weapon/holder/proc/sync(var/mob/living/M)
dir = 2
overlays.Cut()
@@ -83,6 +95,13 @@ var/list/holder_mob_icon_cache = list()
//Mob procs and vars for scooping up
/mob/living/var/holder_type
+/mob/living/MouseDrop(var/atom/over_object)
+ var/mob/living/carbon/human/H = over_object
+ if(holder_type && istype(H) && !H.lying && !issmall(H) && Adjacent(H))
+ get_scooped(H, (usr == src))
+ return
+ return ..()
+
/mob/living/proc/get_scooped(var/mob/living/carbon/grabber, var/self_grab)
if(!holder_type || buckled || pinned.len)
diff --git a/code/modules/mob/living/carbon/alien/diona/diona.dm b/code/modules/mob/living/carbon/alien/diona/diona.dm
index 498f78c94e..8a487d57b3 100644
--- a/code/modules/mob/living/carbon/alien/diona/diona.dm
+++ b/code/modules/mob/living/carbon/alien/diona/diona.dm
@@ -9,6 +9,10 @@
death_msg = "expires with a pitiful chirrup..."
universal_understand = 1
universal_speak = 0 // Dionaea do not need to speak to people other than other dionaea.
+
+ can_pull_size = 2
+ can_pull_mobs = MOB_PULL_SMALLER
+
holder_type = /obj/item/weapon/holder/diona
var/obj/item/hat
@@ -18,19 +22,6 @@
species = all_species["Diona"]
verbs += /mob/living/carbon/alien/diona/proc/merge
-/mob/living/carbon/alien/diona/start_pulling(var/atom/movable/AM)
- //TODO: Collapse these checks into one proc (see pai and drone)
- if(istype(AM,/obj/item))
- var/obj/item/O = AM
- if(O.w_class > 2)
- src << "You are too small to pull that."
- return
- else
- ..()
- else
- src << "You are too small to pull that."
- return
-
/mob/living/carbon/alien/diona/put_in_hands(var/obj/item/W) // No hands.
W.loc = get_turf(src)
return 1
diff --git a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm
index 45d1f6fe46..b9338f361f 100644
--- a/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm
+++ b/code/modules/mob/living/carbon/alien/diona/diona_attacks.dm
@@ -1,17 +1,13 @@
-/mob/living/carbon/alien/diona/MouseDrop(atom/over_object)
- var/mob/living/carbon/H = over_object
- if(!istype(H) || !Adjacent(H)) return ..()
- if(H.a_intent == "help")
- if(H.species && H.species.name == "Diona" && do_merge(H))
- return
- get_scooped(H)
- return
- else if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
+/mob/living/carbon/alien/diona/MouseDrop(var/atom/over_object)
+ var/mob/living/carbon/human/H = over_object
+ if(!istype(H) || !Adjacent(H))
+ return ..()
+ if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
hat.loc = get_turf(src)
H.put_in_hands(hat)
H.visible_message("\The [H] removes \the [src]'s [hat].")
hat = null
- update_icons()
+ updateicon()
else
return ..()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 17fe2df713..f77be45d56 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1370,13 +1370,6 @@
return 1
return 0
-/mob/living/carbon/human/MouseDrop(var/atom/over_object)
- var/mob/living/carbon/human/H = over_object
- if(holder_type && istype(H) && !H.lying && !issmall(H) && Adjacent(H))
- get_scooped(H, (usr == src))
- return
- return ..()
-
/mob/living/carbon/human/verb/pull_punches()
set name = "Pull Punches"
set desc = "Try not to hurt them."
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index f2974d8a16..d049e12d75 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -127,9 +127,6 @@
return 0
..()
-/mob/living/silicon/pai/MouseDrop(atom/over_object)
- return
-
/mob/living/silicon/pai/emp_act(severity)
// Silence for 2 minutes
// 20% chance to kill
@@ -396,18 +393,6 @@
resting = 0
icon_state = "[chassis]"
-/mob/living/silicon/pai/start_pulling(var/atom/movable/AM)
-
- if(istype(AM,/obj/item))
- var/obj/item/O = AM
- if(O.w_class == 1)
- ..()
- else
- src << "You are too small to pull that."
- else
- src << "You are too small to pull that."
- return
-
// No binary for pAIs.
/mob/living/silicon/pai/binarycheck()
return 0
@@ -421,12 +406,3 @@
grabber.update_inv_l_hand()
grabber.update_inv_r_hand()
return H
-
-/mob/living/silicon/pai/MouseDrop(atom/over_object)
- var/mob/living/carbon/H = over_object
- if(!istype(H) || !Adjacent(H)) return ..()
- if(H.a_intent == "help")
- get_scooped(H)
- return
- else
- return ..()
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 14434bfe6e..5356ca9b21 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -37,6 +37,9 @@ var/list/mob_hat_cache = list()
integrated_light_power = 3
local_transmit = 1
+ can_pull_size = 3
+ can_pull_mobs = MOB_PULL_SMALLER
+
mob_bump_flag = SIMPLE_ANIMAL
mob_swap_flags = SIMPLE_ANIMAL
mob_push_flags = SIMPLE_ANIMAL
@@ -49,8 +52,6 @@ var/list/mob_hat_cache = list()
var/obj/machinery/drone_fabricator/master_fabricator
var/law_type = /datum/ai_laws/drone
var/module_type = /obj/item/weapon/robot_module/drone
- var/can_pull_size = 2
- var/can_pull_mobs
var/obj/item/hat
var/hat_x_offset = 0
var/hat_y_offset = -13
@@ -66,10 +67,10 @@ var/list/mob_hat_cache = list()
icon_state = "constructiondrone"
law_type = /datum/ai_laws/construction_drone
module_type = /obj/item/weapon/robot_module/drone/construction
- can_pull_size = 5
- can_pull_mobs = 1
hat_x_offset = 1
hat_y_offset = -12
+ can_pull_size = 5
+ can_pull_mobs = MOB_PULL_SAME
/mob/living/silicon/robot/drone/New()
@@ -315,20 +316,6 @@ var/list/mob_hat_cache = list()
src << "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI."
src << "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows."
-/mob/living/silicon/robot/drone/start_pulling(var/atom/movable/AM)
-
- if(!(istype(AM,/obj/item/pipe) || istype(AM,/obj/structure/disposalconstruct)))
- if(istype(AM,/obj/item))
- var/obj/item/O = AM
- if(O.w_class > can_pull_size)
- src << "You are too small to pull that."
- return
- else
- if(!can_pull_mobs)
- src << "You are too small to pull that."
- return
- ..()
-
/mob/living/silicon/robot/drone/add_robot_verbs()
src.verbs |= silicon_subsystems
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm
index e5aa936a08..2f688a9008 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm
@@ -21,13 +21,11 @@
return
-/mob/living/silicon/robot/drone/MouseDrop(atom/over_object)
- var/mob/living/carbon/H = over_object
- if(!istype(H) || !Adjacent(H)) return ..()
- if(H.a_intent == "help")
- get_scooped(H)
- return
- else if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
+/mob/living/silicon/robot/drone/MouseDrop(var/atom/over_object)
+ var/mob/living/carbon/human/H = over_object
+ if(!istype(H) || !Adjacent(H))
+ return ..()
+ if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
hat.loc = get_turf(src)
H.put_in_hands(hat)
H.visible_message("\The [H] removes \the [src]'s [hat].")
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index c55939e6ae..c4a238f870 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -124,17 +124,6 @@
. = ..()
set_flee_target(AM.thrower? AM.thrower : src.loc)
-/mob/living/simple_animal/cat/MouseDrop(atom/over_object)
-
- var/mob/living/carbon/H = over_object
- if(!istype(H) || !Adjacent(H)) return ..()
-
- if(H.a_intent == "help")
- get_scooped(H)
- return
- else
- return ..()
-
//Basic friend AI
/mob/living/simple_animal/cat/fluff
var/mob/living/carbon/human/friend
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 37630abdb6..2b776671fe 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -31,6 +31,9 @@
holder_type = /obj/item/weapon/holder/mouse
mob_size = MOB_MINISCULE
+ can_pull_size = 1
+ can_pull_mobs = MOB_PULL_NONE
+
/mob/living/simple_animal/mouse/Life()
..()
if(!stat && prob(speak_chance))
@@ -78,20 +81,6 @@
if(client)
client.time_died_as_mouse = world.time
-/mob/living/simple_animal/mouse/MouseDrop(atom/over_object)
-
- var/mob/living/carbon/H = over_object
- if(!istype(H) || !Adjacent(H)) return ..()
-
- if(H.a_intent == "help")
- get_scooped(H)
- return
- else
- return ..()
-
-/mob/living/simple_animal/mouse/start_pulling(var/atom/movable/AM)//Prevents mouse from pulling things
- src << "You are too small to pull anything."
- return
/mob/living/simple_animal/mouse/Crossed(AM as mob|obj)
if( ishuman(AM) )
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 2b64078149..22f481e9f1 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -603,20 +603,44 @@
pullin.icon_state = "pull0"
/mob/proc/start_pulling(var/atom/movable/AM)
+
if ( !AM || !usr || src==AM || !isturf(src.loc) ) //if there's no person pulling OR the person is pulling themself OR the object being pulled is inside something: abort!
return
if (AM.anchored)
- usr << "It won't budge!"
+ src << "It won't budge!"
return
var/mob/M = AM
if(ismob(AM))
+
+ if(!can_pull_mobs || !can_pull_size)
+ src << "It won't budge!"
+ return
+
+ if((mob_size < M.mob_size) && (can_pull_mobs != MOB_PULL_LARGER))
+ src << "It won't budge!"
+ return
+
+ if((mob_size == M.mob_size) && (can_pull_mobs == MOB_PULL_SMALLER))
+ src << "It won't budge!"
+ return
+
+ // If your size is larger than theirs and you have some
+ // kind of mob pull value AT ALL, you will be able to pull
+ // them, so don't bother checking that explicitly.
+
if(!iscarbon(src))
M.LAssailant = null
else
M.LAssailant = usr
+ else if(isobj(AM))
+ var/obj/I = AM
+ if(!can_pull_size || can_pull_size < I.w_class)
+ src << "It won't budge!"
+ return
+
if(pulling)
var/pulling_old = pulling
stop_pulling()
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 9503800189..dfbde26b65 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -149,6 +149,8 @@
var/const/deafness = 2//Carbon
var/const/muteness = 4//Carbon
+ var/can_pull_size = 10 // Maximum w_class the mob can pull.
+ var/can_pull_mobs = MOB_PULL_LARGER // Whether or not the mob can pull other mobs.
var/datum/dna/dna = null//Carbon
var/radiation = 0.0//Carbon
diff --git a/html/changelogs/Zuhayr-dronepulling.yml b/html/changelogs/Zuhayr-dronepulling.yml
new file mode 100644
index 0000000000..059c756328
--- /dev/null
+++ b/html/changelogs/Zuhayr-dronepulling.yml
@@ -0,0 +1,5 @@
+author: Zuhayr
+delete-after: True
+changes:
+ - rscadd: Drones can now pull a variety of things (such as scrubbers). This came with a pulling refactor so please report any strangeness with pulling in general.
+ - rscadd: Drones (and any mob that can be picked up) can be bashed against airlocks and such to use their internal access, so long as the person using them does not have an ID card equipped.
\ No newline at end of file