diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/he_pipes.dm
index 58c2ee3a2d..aa474a8572 100644
--- a/code/ATMOSPHERICS/he_pipes.dm
+++ b/code/ATMOSPHERICS/he_pipes.dm
@@ -71,20 +71,23 @@
else if(istype(loc, /turf/space/))
parent.radiate_heat_to_space(surface, 1)
- if(buckled_mob)
- var/hc = pipe_air.heat_capacity()
- var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500)
- pipe_air.temperature = avg_temp
- buckled_mob.bodytemperature = avg_temp
+ if(has_buckled_mobs())
+ for(var/M in buckled_mobs)
+ var/mob/living/L = M
- var/heat_limit = 1000
+ var/hc = pipe_air.heat_capacity()
+ var/avg_temp = (pipe_air.temperature * hc + L.bodytemperature * 3500) / (hc + 3500)
+ pipe_air.temperature = avg_temp
+ L.bodytemperature = avg_temp
- var/mob/living/carbon/human/H = buckled_mob
- if(istype(H) && H.species)
- heat_limit = H.species.heat_level_3
+ var/heat_limit = 1000
- if(pipe_air.temperature > heat_limit + 1)
- buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_TORSO, used_weapon = "Excessive Heat")
+ var/mob/living/carbon/human/H = L
+ if(istype(H) && H.species)
+ heat_limit = H.species.heat_level_3
+
+ if(pipe_air.temperature > heat_limit + 1)
+ L.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_TORSO, used_weapon = "Excessive Heat")
//fancy radiation glowing
if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K
diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index 129236125c..b58a50c05a 100644
--- a/code/__defines/_planes+layers.dm
+++ b/code/__defines/_planes+layers.dm
@@ -52,3 +52,21 @@ What is the naming convention for planes or layers?
#define OPENSPACE_PLANE -25 // /turf/simulated/open will use OPENSPACE_PLANE + z (Valid z's being 2 thru 17)
#define OVER_OPENSPACE_PLANE -7
+
+
+// Now for the regular layers. Try to keep these in order, from lowest to highest numbers, please.
+
+//#define TURF_LAYER 2 //For easy recordkeeping; this is a byond define
+#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
+//#define OBJ_LAYER 3 //For easy recordkeeping; this is a byond define
+#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed
+
+#define BELOW_MOB_LAYER 3.9
+//#define MOB_LAYER 4 //For easy recordkeeping; this is a byond define
+#define ABOVE_MOB_LAYER 4.1
+
+//#define FLY_LAYER 5 //For easy recordkeeping; this is a byond define
+#define LIGHTING_LAYER 11
+#define HUD_LAYER 20 //Above lighting, but below obfuscation. For in-game HUD effects (whereas SCREEN_LAYER is for abstract/OOC things like inventory slots)
+#define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put
+#define SCREEN_LAYER 22 //Mob HUD/effects layer
\ No newline at end of file
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
index 30f2dac84d..6b05896b8d 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -9,7 +9,7 @@
#define LIGHTING_LAMBERTIAN 0 // use lambertian shading for light sources
#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
-#define LIGHTING_LAYER 10 // drawing layer for lighting overlays
+//#define LIGHTING_LAYER 10 // drawing layer for lighting overlays
#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
#define LIGHTING_ICON_STATE_DARK "soft_dark" // Change between "soft_dark" and "dark" to swap soft darkvision
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 9b9bc8cb14..3a8ee870e5 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -121,14 +121,6 @@
//Area flags, possibly more to come
#define RAD_SHIELDED 1 //shielded from radiation, clearly
-// Custom layer definitions, supplementing the default TURF_LAYER, MOB_LAYER, etc.
-#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6
-#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed
-#define LIGHTING_LAYER 11
-#define HUD_LAYER 20 //Above lighting, but below obfuscation. For in-game HUD effects (whereas SCREEN_LAYER is for abstract/OOC things like inventory slots)
-#define OBFUSCATION_LAYER 21 //Where images covering the view for eyes are put
-#define SCREEN_LAYER 22 //Mob HUD/effects layer
-
// Convoluted setup so defines can be supplied by Bay12 main server compile script.
// Should still work fine for people jamming the icons into their repo.
#ifndef CUSTOM_ITEM_OBJ
@@ -155,6 +147,10 @@
#define MAT_PHORON "phoron"
#define MAT_DIAMOND "diamond"
#define MAT_SNOW "snow"
+#define MAT_WOOD "wood"
+#define MAT_LOG "log"
+#define MAT_SIFWOOD "alien wood"
+#define MAT_SIFLOG "alien log"
#define SHARD_SHARD "shard"
#define SHARD_SHRAPNEL "shrapnel"
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index 1dffebf607..a9939b0ecb 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -5,7 +5,7 @@
return occupant
/obj/vehicle/train/get_mob()
- return buckled_mob
+ return buckled_mobs
/mob/get_mob()
return src
diff --git a/code/datums/riding.dm b/code/datums/riding.dm
new file mode 100644
index 0000000000..746cc6dcf7
--- /dev/null
+++ b/code/datums/riding.dm
@@ -0,0 +1,224 @@
+// This is used to make things that are supposed to move while buckled more consistant and easier to handle code-wise.
+
+/datum/riding
+ var/next_vehicle_move = 0 // Used for move delays
+ var/vehicle_move_delay = 2 // Tick delay between movements, lower = faster, higher = slower
+ var/keytype = null // Can give this a type to require the rider to hold the item type inhand to move the ridden atom.
+ var/nonhuman_key_exemption = FALSE // If true, nonhumans who can't hold keys don't need them, like borgs and simplemobs.
+ var/key_name = "the keys" // What the 'keys' for the thing being rided on would be called.
+ var/atom/movable/ridden = null // The thing that the datum is attached to.
+ var/only_one_driver = FALSE // If true, only the person in 'front' (first on list of riding mobs) can drive.
+
+/datum/riding/New(atom/movable/_ridden)
+ ridden = _ridden
+
+/datum/riding/Destroy()
+ ridden = null
+ return ..()
+
+/datum/riding/proc/handle_vehicle_layer()
+ if(ridden.dir != NORTH)
+ ridden.layer = ABOVE_MOB_LAYER
+ else
+ ridden.layer = OBJ_LAYER
+
+/datum/riding/proc/on_vehicle_move()
+ for(var/mob/living/M in ridden.buckled_mobs)
+ ride_check(M)
+ handle_vehicle_offsets()
+ handle_vehicle_layer()
+
+/datum/riding/proc/ride_check(mob/living/M)
+ return TRUE
+
+/datum/riding/proc/force_dismount(mob/living/M)
+ ridden.unbuckle_mob(M)
+
+/datum/riding/proc/handle_vehicle_offsets()
+ var/ridden_dir = "[ridden.dir]"
+ var/passindex = 0
+ if(ridden.has_buckled_mobs())
+ for(var/m in ridden.buckled_mobs)
+ passindex++
+ var/mob/living/buckled_mob = m
+ var/list/offsets = get_offsets(passindex)
+ var/rider_dir = get_rider_dir(passindex)
+ buckled_mob.set_dir(rider_dir)
+ dir_loop:
+ for(var/offsetdir in offsets)
+ if(offsetdir == ridden_dir)
+ var/list/diroffsets = offsets[offsetdir]
+ buckled_mob.pixel_x = diroffsets[1]
+ if(diroffsets.len >= 2)
+ buckled_mob.pixel_y = diroffsets[2]
+ if(diroffsets.len == 3)
+ buckled_mob.layer = diroffsets[3]
+ break dir_loop
+
+// Override this to set your vehicle's various pixel offsets
+/datum/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
+ return list("[NORTH]" = list(0, 0), "[SOUTH]" = list(0, 0), "[EAST]" = list(0, 0), "[WEST]" = list(0, 0))
+
+// Override this to set the passengers/riders dir based on which passenger they are.
+// ie: rider facing the vehicle's dir, but passenger 2 facing backwards, etc.
+/datum/riding/proc/get_rider_dir(pass_index)
+ return ridden.dir
+
+// KEYS
+/datum/riding/proc/keycheck(mob/user)
+ if(keytype)
+ if(nonhuman_key_exemption && !ishuman(user))
+ return TRUE
+
+ if(user.is_holding_item_of_type(keytype))
+ return TRUE
+ else
+ return TRUE
+ return FALSE
+
+// BUCKLE HOOKS
+/datum/riding/proc/restore_position(mob/living/buckled_mob)
+ if(istype(buckled_mob))
+ buckled_mob.pixel_x = 0
+ buckled_mob.pixel_y = 0
+ buckled_mob.layer = initial(buckled_mob.layer)
+
+// MOVEMENT
+/datum/riding/proc/handle_ride(mob/user, direction)
+ if(user.incapacitated())
+ Unbuckle(user)
+ return
+
+ if(only_one_driver && ridden.buckled_mobs.len)
+ var/mob/living/driver = ridden.buckled_mobs[1]
+ if(driver != user)
+ to_chat(user, "\The [ridden] can only be controlled by one person at a time, and is currently being controlled by \the [driver].")
+ return
+
+ if(world.time < next_vehicle_move)
+ return
+ next_vehicle_move = world.time + vehicle_move_delay
+ if(keycheck(user))
+ if(!Process_Spacemove(direction) || !isturf(ridden.loc))
+ return
+ step(ridden, direction)
+
+ handle_vehicle_layer()
+ handle_vehicle_offsets()
+ else
+ to_chat(user, "You'll need [key_name] in one of your hands to move \the [ridden].")
+
+/datum/riding/proc/Unbuckle(atom/movable/M)
+// addtimer(CALLBACK(ridden, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
+ spawn(0)
+ // On /tg/ this uses the fancy CALLBACK system. Not entirely sure why they needed to do so with a duration of 0,
+ // so if there is a reason, this should replicate it close enough. Hopefully.
+ ridden.unbuckle_mob(M)
+
+/datum/riding/proc/Process_Spacemove(direction)
+ if(ridden.has_gravity())
+ return TRUE
+
+ return FALSE
+
+/datum/riding/space/Process_Spacemove(direction)
+ return TRUE
+
+
+
+// SUBTYPES
+
+// I'm on a
+/datum/riding/boat
+ keytype = /obj/item/weapon/oar
+ key_name = "an oar"
+ nonhuman_key_exemption = TRUE // Borgs can't hold oars.
+ only_one_driver = TRUE // Would be pretty crazy if five people try to move at the same time.
+
+/datum/riding/boat/handle_ride(mob/user, direction)
+ var/turf/next = get_step(ridden, direction)
+ var/turf/current = get_turf(ridden)
+
+ if(istype(next, /turf/simulated/floor/water) || istype(current, /turf/simulated/floor/water)) //We can move from land to water, or water to land, but not from land to land
+ ..()
+ else
+ to_chat(user, "Boats don't go on land!")
+ return FALSE
+
+/datum/riding/boat/small // 'Small' boats can hold up to two people.
+
+/datum/riding/boat/small/get_offsets(pass_index) // list(dir = x, y, layer)
+ var/H = 7 // Horizontal seperation.
+ var/V = 5 // Vertical seperation.
+ var/O = 2 // Vertical offset.
+ switch(pass_index)
+ if(1) // Person in front.
+ return list(
+ "[NORTH]" = list( 0, O+V, MOB_LAYER),
+ "[SOUTH]" = list( 0, O, ABOVE_MOB_LAYER),
+ "[EAST]" = list( H, O, MOB_LAYER),
+ "[WEST]" = list(-H, O, MOB_LAYER)
+ )
+ if(2) // Person in back.
+ return list(
+ "[NORTH]" = list( 0, O, ABOVE_MOB_LAYER),
+ "[SOUTH]" = list( 0, O+V, MOB_LAYER),
+ "[EAST]" = list(-H, O, MOB_LAYER),
+ "[WEST]" = list( H, O, MOB_LAYER)
+ )
+ else
+ return null // This will runtime, but we want that since this is out of bounds.
+
+/datum/riding/boat/small/handle_vehicle_layer()
+ ridden.layer = ABOVE_MOB_LAYER
+
+/datum/riding/boat/big // 'Big' boats can hold up to five people.
+
+/datum/riding/boat/big/get_offsets(pass_index) // list(dir = x, y, layer)
+ var/H = 12 // Horizontal seperation. Halved when facing up-down.
+ var/V = 4 // Vertical seperation.
+ var/O = 7 // Vertical offset.
+ switch(pass_index)
+ if(1) // Person in center front, first row.
+ return list(
+ "[NORTH]" = list( 0, O+V, MOB_LAYER+0.1),
+ "[SOUTH]" = list( 0, O-V, MOB_LAYER+0.3),
+ "[EAST]" = list( H, O, MOB_LAYER+0.1),
+ "[WEST]" = list(-H, O, MOB_LAYER+0.1)
+ )
+ if(2) // Person in left, second row.
+ return list(
+ "[NORTH]" = list( H/2, O, MOB_LAYER+0.2),
+ "[SOUTH]" = list(-H/2, O, MOB_LAYER+0.2),
+ "[EAST]" = list( 0, O-V, MOB_LAYER+0.2),
+ "[WEST]" = list( 0, O+V, MOB_LAYER)
+ )
+ if(3) // Person in right, second row.
+ return list(
+ "[NORTH]" = list(-H/2, O, MOB_LAYER+0.2),
+ "[SOUTH]" = list( H/2, O, MOB_LAYER+0.2),
+ "[EAST]" = list( 0, O+V, MOB_LAYER),
+ "[WEST]" = list( 0, O-V, MOB_LAYER+0.2)
+ )
+ if(4) // Person in left, third row.
+ return list(
+ "[NORTH]" = list( H/2, O-V, MOB_LAYER+0.3),
+ "[SOUTH]" = list(-H/2, O+V, MOB_LAYER+0.1),
+ "[EAST]" = list(-H, O-V, MOB_LAYER+0.2),
+ "[WEST]" = list( H, O+V, MOB_LAYER)
+ )
+ if(5) // Person in right, third row.
+ return list(
+ "[NORTH]" = list(-H/2, O-V, MOB_LAYER+0.3),
+ "[SOUTH]" = list( H/2, O+V, MOB_LAYER+0.1),
+ "[EAST]" = list(-H, O+V, MOB_LAYER),
+ "[WEST]" = list( H, O-V, MOB_LAYER+0.2)
+ )
+ else
+ return null // This will runtime, but we want that since this is out of bounds.
+
+/datum/riding/boat/big/handle_vehicle_layer()
+ ridden.layer = MOB_LAYER+0.4
+
+/datum/riding/boat/get_offsets(pass_index) // list(dir = x, y, layer)
+ return list("[NORTH]" = list(1, 2), "[SOUTH]" = list(1, 2), "[EAST]" = list(1, 2), "[WEST]" = list(1, 2))
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 0eb0321f13..0c5fe0e7de 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -294,7 +294,7 @@ var/list/mob/living/forced_ambiance_list = new
for(var/obj/machinery/door/window/temp_windoor in src)
temp_windoor.open()
-/area/proc/has_gravity()
+/area/has_gravity()
return has_gravity
/area/space/has_gravity()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index dec7ab1ccf..7a027d207b 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -519,3 +519,13 @@ its easier to just keep the beam vertical.
/atom/proc/InsertedContents()
return contents
+
+/atom/proc/has_gravity(turf/T)
+ if(!T || !isturf(T))
+ T = get_turf(src)
+ if(istype(T, /turf/space)) // Turf never has gravity
+ return FALSE
+ var/area/A = get_area(T)
+ if(A && A.has_gravity())
+ return TRUE
+ return FALSE
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index e0648f8c95..2dba31d578 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -93,6 +93,8 @@
AM.Crossed(src)
if(is_new_area && is_destination_turf)
destination.loc.Entered(src, origin)
+
+ Moved(origin)
return 1
//called when src is thrown into hit_atom
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index a0ac2f646c..c413bfccd4 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -470,7 +470,7 @@ var/global/datum/controller/occupations/job_master
H.buckled = W
H.update_canmove()
W.set_dir(H.dir)
- W.buckled_mob = H
+ W.buckled_mobs |= H
W.add_fingerprint(H)
if(R)
W.color = R.color
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index cc41d779dc..164140583f 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -19,7 +19,7 @@
//loading
if(istype(target,/obj))
var/obj/O = target
- if(O.buckled_mob)
+ if(O.has_buckled_mobs())
return
if(locate(/mob/living) in O)
occupant_message("You can't load living things into the cargo compartment.")
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index dce392e8f7..9b27cdecbd 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -6,26 +6,44 @@
var/buckle_dir = 0
var/buckle_lying = -1 //bed-like behavior, forces mob.lying = buckle_lying if != -1
var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes
- var/mob/living/buckled_mob = null
+// var/mob/living/buckled_mob = null
+ var/list/mob/living/buckled_mobs = null //list()
+ var/max_buckled_mobs = 1
/atom/movable/attack_hand(mob/living/user)
. = ..()
- if(can_buckle && buckled_mob)
- user_unbuckle_mob(user)
+// if(can_buckle && buckled_mob)
+// user_unbuckle_mob(user)
+
+ if(can_buckle && has_buckled_mobs())
+ if(buckled_mobs.len > 1)
+ var/unbuckled = input(user, "Who do you wish to unbuckle?","Unbuckle Who?") as null|mob in buckled_mobs
+ if(user_unbuckle_mob(unbuckled, user))
+ return TRUE
+ else
+ if(user_unbuckle_mob(buckled_mobs[1], user))
+ return TRUE
/obj/proc/attack_alien(mob/user as mob) //For calling in the event of Xenomorph or other alien checks.
return
/obj/attack_robot(mob/living/user)
- if(Adjacent(user) && buckled_mob) //Checks if what we're touching is adjacent to us and has someone buckled to it. This should prevent interacting with anti-robot manual valves among other things.
+ if(Adjacent(user) && has_buckled_mobs()) //Checks if what we're touching is adjacent to us and has someone buckled to it. This should prevent interacting with anti-robot manual valves among other things.
return attack_hand(user) //Process as if we're a normal person touching the object.
return ..() //Otherwise, treat this as an AI click like usual.
/atom/movable/MouseDrop_T(mob/living/M, mob/living/user)
. = ..()
if(can_buckle && istype(M))
- user_buckle_mob(M, user)
+ if(user_buckle_mob(M, user))
+ return TRUE
+
+/atom/movable/proc/has_buckled_mobs()
+ if(!buckled_mobs)
+ return FALSE
+ if(buckled_mobs.len)
+ return TRUE
/atom/movable/Destroy()
unbuckle_mob()
@@ -33,52 +51,81 @@
/atom/movable/proc/buckle_mob(mob/living/M, forced = FALSE, check_loc = TRUE)
- if((!can_buckle && !forced) || !istype(M) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained()))
- return 0
+ if(!buckled_mobs)
+ buckled_mobs = list()
+
+ if(!istype(M))
+ return FALSE
+
if(check_loc && M.loc != loc)
- return 0
- if(buckled_mob) //Handles trying to buckle yourself to the chair when someone is on it
- M << "\The [src] already has someone buckled to it."
- return 0
+ return FALSE
+
+ if((!can_buckle && !forced) || M.buckled || M.pinned.len || (buckled_mobs.len >= max_buckled_mobs) || (buckle_require_restraints && !M.restrained()))
+ return FALSE
+
+ if(has_buckled_mobs() && buckled_mobs.len >= max_buckled_mobs) //Handles trying to buckle yourself to the chair when someone is on it
+ to_chat(M, "\The [src] can't buckle anymore people.")
+ return FALSE
M.buckled = src
M.facing_dir = null
M.set_dir(buckle_dir ? buckle_dir : dir)
M.update_canmove()
M.update_floating( M.Check_Dense_Object() )
- buckled_mob = M
+// buckled_mob = M
+ buckled_mobs |= M
post_buckle_mob(M)
- return 1
+ return TRUE
+
+/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force = FALSE)
+ if(!buckled_mob) // If we didn't get told which mob needs to get unbuckled, just assume its the first one on the list.
+ if(has_buckled_mobs())
+ buckled_mob = buckled_mobs[1]
+ else
+ return
-/atom/movable/proc/unbuckle_mob()
if(buckled_mob && buckled_mob.buckled == src)
. = buckled_mob
buckled_mob.buckled = null
buckled_mob.anchored = initial(buckled_mob.anchored)
buckled_mob.update_canmove()
buckled_mob.update_floating( buckled_mob.Check_Dense_Object() )
- buckled_mob = null
+ // buckled_mob = null
+ buckled_mobs -= buckled_mob
post_buckle_mob(.)
+/atom/movable/proc/unbuckle_all_mobs(force = FALSE)
+ if(!has_buckled_mobs())
+ return
+ for(var/m in buckled_mobs)
+ unbuckle_mob(m, force)
+
+//Handle any extras after buckling/unbuckling
+//Called on buckle_mob() and unbuckle_mob()
/atom/movable/proc/post_buckle_mob(mob/living/M)
return
+//Wrapper procs that handle sanity and user feedback
/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, var/forced = FALSE, var/silent = FALSE)
if(!ticker)
user << "You can't buckle anyone in before the game starts."
+ return FALSE // Is this really needed?
if(!user.Adjacent(M) || user.restrained() || user.stat || istype(user, /mob/living/silicon/pai))
- return
- if(M == buckled_mob)
- return
+ return FALSE
+ if(M in buckled_mobs)
+ to_chat(user, "\The [M] is already buckled to \the [src].")
+ return FALSE
add_fingerprint(user)
- unbuckle_mob()
+// unbuckle_mob()
//can't buckle unless you share locs so try to move M to the obj.
if(M.loc != src.loc)
- step_towards(M, src)
+ if(M.Adjacent(src) && user.Adjacent(src))
+ M.forceMove(get_turf(src))
+ // step_towards(M, src)
. = buckle_mob(M, forced)
if(.)
@@ -94,8 +141,8 @@
"You are buckled to [src] by [user.name]!",\
"You hear metal clanking.")
-/atom/movable/proc/user_unbuckle_mob(mob/user)
- var/mob/living/M = unbuckle_mob()
+/atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
+ var/mob/living/M = unbuckle_mob(buckled_mob)
if(M)
if(M != user)
M.visible_message(\
@@ -111,18 +158,20 @@
return M
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
- if(buckled_mob)
-// if(!buckled_mob.Move(newloc, direct))
- if(!buckled_mob.forceMove(newloc, direct))
- loc = buckled_mob.loc
- last_move = buckled_mob.last_move
- buckled_mob.inertia_dir = last_move
- return FALSE
- else
- buckled_mob.set_dir(dir)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+// if(!L.Move(newloc, direct))
+ if(!L.forceMove(newloc, direct))
+ loc = L.loc
+ last_move = L.last_move
+ L.inertia_dir = last_move
+ return FALSE
+ else
+ L.set_dir(dir)
return TRUE
/atom/movable/Move(atom/newloc, direct = 0)
. = ..()
- if(. && buckled_mob && !handle_buckled_mob_movement(newloc, direct)) //movement failed due to buckled mob(s)
+ if(. && has_buckled_mobs() && !handle_buckled_mob_movement(newloc, direct)) //movement failed due to buckled mob(s)
. = 0
diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm
index 1fee7b1b85..83f6f0bd89 100644
--- a/code/game/objects/items/weapons/material/knives.dm
+++ b/code/game/objects/items/weapons/material/knives.dm
@@ -113,3 +113,4 @@
icon_state = "survivalknife"
item_state = "knife"
applies_material_colour = FALSE
+ toolspeed = 2 // Use a real axe if you want to chop logs.
diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm
index 748d7df06d..317dba9ba9 100644
--- a/code/game/objects/items/weapons/traps.dm
+++ b/code/game/objects/items/weapons/traps.dm
@@ -42,14 +42,16 @@
anchored = 1
/obj/item/weapon/beartrap/attack_hand(mob/user as mob)
- if(buckled_mob && can_use(user))
+ if(has_buckled_mobs() && can_use(user))
+ var/victim = english_list(buckled_mobs)
user.visible_message(
- "[user] begins freeing [buckled_mob] from \the [src].",
- "You carefully begin to free [buckled_mob] from \the [src].",
+ "[user] begins freeing [victim] from \the [src].",
+ "You carefully begin to free [victim] from \the [src].",
)
if(do_after(user, 60))
- user.visible_message("[buckled_mob] has been freed from \the [src] by [user].")
- unbuckle_mob()
+ user.visible_message("[victim] has been freed from \the [src] by [user].")
+ for(var/A in buckled_mobs)
+ unbuckle_mob(A)
anchored = 0
else if(deployed && can_use(user))
user.visible_message(
@@ -109,7 +111,7 @@
"You hear a loud metallic snap!"
)
attack_mob(L)
- if(!buckled_mob)
+ if(!has_buckled_mobs())
anchored = 0
deployed = 0
update_icon()
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index c077668bbd..50434de460 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -111,39 +111,41 @@
processing_objects |= src
/obj/effect/energy_net/Destroy()
- if(buckled_mob)
- to_chat(buckled_mob,"You are free of the net!")
- unbuckle_mob()
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ to_chat(A,"You are free of the net!")
+ unbuckle_mob(A)
processing_objects -= src
return ..()
/obj/effect/energy_net/process()
- if(isnull(buckled_mob) || buckled_mob.loc != loc)
+ if(!has_buckled_mobs())
qdel(src)
/obj/effect/energy_net/Move()
..()
- if(buckled_mob)
- var/mob/living/occupant = buckled_mob
- occupant.buckled = null
- occupant.forceMove(src.loc)
- occupant.buckled = src
- if (occupant && (src.loc != occupant.loc))
- unbuckle_mob()
- qdel(src)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/occupant = A
+ occupant.buckled = null
+ occupant.forceMove(src.loc)
+ occupant.buckled = src
+ if (occupant && (src.loc != occupant.loc))
+ unbuckle_mob(occupant)
+ qdel(src)
-/obj/effect/energy_net/user_unbuckle_mob(mob/user)
+/obj/effect/energy_net/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
user.setClickCooldown(user.get_attack_speed())
visible_message("[user] begins to tear at \the [src]!")
if(do_after(usr, escape_time, src, incapacitation_flags = INCAPACITATION_DEFAULT & ~(INCAPACITATION_RESTRAINED | INCAPACITATION_BUCKLED_FULLY)))
- if(!buckled_mob)
+ if(!has_buckled_mobs())
return
visible_message("[user] manages to tear \the [src] apart!")
- unbuckle_mob()
+ unbuckle_mob(buckled_mob)
/obj/effect/energy_net/post_buckle_mob(mob/living/M)
- if(buckled_mob) //Just buckled someone
+ if(M.buckled == src) //Just buckled someone
..()
layer = M.layer+1
M.can_pull_size = 0
diff --git a/code/game/objects/structures/bonfire.dm b/code/game/objects/structures/bonfire.dm
index 339c93385d..1952ddea4f 100644
--- a/code/game/objects/structures/bonfire.dm
+++ b/code/game/objects/structures/bonfire.dm
@@ -14,7 +14,7 @@
/obj/structure/bonfire/New(newloc, material_name)
..(newloc)
if(!material_name)
- material_name = "wood"
+ material_name = MAT_WOOD
material = get_material_by_name("[material_name]")
if(!material)
qdel(src)
@@ -23,14 +23,14 @@
// Blue wood.
/obj/structure/bonfire/sifwood/New(newloc, material_name)
- ..(newloc, "alien wood")
+ ..(newloc, MAT_SIFWOOD)
/obj/structure/bonfire/permanent/New(newloc, material_name)
..()
ignite()
/obj/structure/bonfire/permanent/sifwood/New(newloc, material_name)
- ..(newloc, "alien wood")
+ ..(newloc, MAT_SIFWOOD)
/obj/structure/bonfire/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/stack/rods) && !can_buckle && !grill)
@@ -63,7 +63,7 @@
return ..()
/obj/structure/bonfire/attack_hand(mob/user)
- if(buckled_mob)
+ if(has_buckled_mobs())
return ..()
if(get_fuel_amount())
@@ -194,7 +194,7 @@
I.appearance_flags = RESET_COLOR
overlays += I
- if(buckled_mob && get_fuel_amount() >= 5)
+ if(has_buckled_mobs() && get_fuel_amount() >= 5)
I = image(icon, "bonfire_intense")
I.pixel_y = 13
I.layer = MOB_LAYER + 0.1
@@ -231,7 +231,7 @@
extinguish()
/obj/structure/bonfire/post_buckle_mob(mob/living/M)
- if(buckled_mob) // Just buckled someone
+ if(M.buckled == src) // Just buckled someone
M.pixel_y += 13
else // Just unbuckled someone
M.pixel_y -= 13
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index da8c5f04cb..97dd747845 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -59,7 +59,7 @@
continue
if(istype(O, /obj/structure/bed)) //This is only necessary because of rollerbeds and swivel chairs.
var/obj/structure/bed/B = O
- if(B.buckled_mob)
+ if(B.has_buckled_mobs())
continue
O.forceMove(src)
itemcount++
diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm
index 53b2ad224f..e9483386cf 100644
--- a/code/game/objects/structures/electricchair.dm
+++ b/code/game/objects/structures/electricchair.dm
@@ -64,12 +64,14 @@
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(12, 1, src)
s.start()
- if(buckled_mob)
- buckled_mob.burn_skin(85)
- buckled_mob << "You feel a deep shock course through your body!"
- sleep(1)
- buckled_mob.burn_skin(85)
- buckled_mob.Stun(600)
+ if(has_buckled_mobs())
+ for(var/a in buckled_mobs)
+ var/mob/living/L = a
+ L.burn_skin(85)
+ to_chat(L, "You feel a deep shock course through your body!")
+ sleep(1)
+ L.burn_skin(85)
+ L.Stun(600)
visible_message("The electric chair went off!", "You hear a deep sharp shock!")
A.power_light = light
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index bd23290e30..1b5a95373b 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/janitor.dmi'
icon_state = "cart"
anchored = 0
- density = 1
+ density = 1
climbable = 1
flags = OPENCONTAINER
//copypaste sorry
@@ -229,9 +229,11 @@
/obj/structure/bed/chair/janicart/Move()
..()
- if(buckled_mob)
- if(buckled_mob.buckled == src)
- buckled_mob.loc = loc
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ if(L.buckled == src)
+ L.loc = loc
/obj/structure/bed/chair/janicart/post_buckle_mob(mob/living/M)
@@ -257,36 +259,41 @@
/obj/structure/bed/chair/janicart/set_dir()
..()
update_layer()
- if(buckled_mob)
- if(buckled_mob.loc != loc)
- buckled_mob.buckled = null //Temporary, so Move() succeeds.
- buckled_mob.buckled = src //Restoring
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ if(L.loc != loc)
+ L.buckled = null //Temporary, so Move() succeeds.
+ L.buckled = src //Restoring
update_mob()
/obj/structure/bed/chair/janicart/proc/update_mob()
- if(buckled_mob)
- buckled_mob.set_dir(dir)
- switch(dir)
- if(SOUTH)
- buckled_mob.pixel_x = 0
- buckled_mob.pixel_y = 7
- if(WEST)
- buckled_mob.pixel_x = 13
- buckled_mob.pixel_y = 7
- if(NORTH)
- buckled_mob.pixel_x = 0
- buckled_mob.pixel_y = 4
- if(EAST)
- buckled_mob.pixel_x = -13
- buckled_mob.pixel_y = 7
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ L.set_dir(dir)
+ switch(dir)
+ if(SOUTH)
+ L.pixel_x = 0
+ L.pixel_y = 7
+ if(WEST)
+ L.pixel_x = 13
+ L.pixel_y = 7
+ if(NORTH)
+ L.pixel_x = 0
+ L.pixel_y = 4
+ if(EAST)
+ L.pixel_x = -13
+ L.pixel_y = 7
/obj/structure/bed/chair/janicart/bullet_act(var/obj/item/projectile/Proj)
- if(buckled_mob)
+ if(has_buckled_mobs())
if(prob(85))
- return buckled_mob.bullet_act(Proj)
+ var/mob/living/L = pick(buckled_mobs)
+ return L.bullet_act(Proj)
visible_message("[Proj] ricochets off the [callme]!")
diff --git a/code/game/objects/structures/simple_doors.dm b/code/game/objects/structures/simple_doors.dm
index 7312c1ebf9..2aa58488b6 100644
--- a/code/game/objects/structures/simple_doors.dm
+++ b/code/game/objects/structures/simple_doors.dm
@@ -192,10 +192,10 @@
..(newloc, "diamond")
/obj/structure/simple_door/wood/New(var/newloc,var/material_name)
- ..(newloc, "wood")
+ ..(newloc, MAT_WOOD)
/obj/structure/simple_door/sifwood/New(var/newloc,var/material_name)
- ..(newloc, "alien wood")
+ ..(newloc, MAT_SIFWOOD)
/obj/structure/simple_door/resin/New(var/newloc,var/material_name)
..(newloc, "resin")
\ No newline at end of file
diff --git a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm
index 9d79ad45a1..270583011d 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm
@@ -10,7 +10,7 @@
/obj/structure/bed/nest/update_icon()
return
-/obj/structure/bed/nest/user_unbuckle_mob(mob/user as mob)
+/obj/structure/bed/nest/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
if(buckled_mob)
if(buckled_mob.buckled == src)
if(buckled_mob != user)
@@ -20,7 +20,7 @@
"You hear squelching...")
buckled_mob.pixel_y = 0
buckled_mob.old_y = 0
- unbuckle_mob()
+ unbuckle_mob(buckled_mob)
else
if(world.time <= buckled_mob.last_special+NEST_RESIST_TIME)
return
@@ -34,7 +34,7 @@
buckled_mob.last_special = world.time
buckled_mob.pixel_y = 0
buckled_mob.old_y = 0
- unbuckle_mob()
+ unbuckle_mob(buckled_mob)
src.add_fingerprint(user)
return
@@ -66,7 +66,7 @@
M.update_canmove()
M.pixel_y = 6
M.old_y = 6
- src.buckled_mob = M
+ src.buckled_mobs |= M
src.add_fingerprint(user)
return
diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
index 1af4fd82c0..219854f15f 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -131,7 +131,7 @@
else if(istype(W, /obj/item/weapon/grab))
var/obj/item/weapon/grab/G = W
var/mob/living/affecting = G.affecting
- if(buckled_mob) //Handles trying to buckle someone else to a chair when someone else is on it
+ if(has_buckled_mobs()) //Handles trying to buckle someone else to a chair when someone else is on it
to_chat(user, "\The [src] already has someone buckled to it.")
return
user.visible_message("[user] attempts to buckle [affecting] into \the [src]!")
@@ -183,7 +183,7 @@
..(newloc,"wood","cotton")
/obj/structure/bed/double/post_buckle_mob(mob/living/M as mob)
- if(M == buckled_mob)
+ if(M.buckled == src)
M.pixel_y = 13
M.old_y = 13
else
@@ -216,8 +216,9 @@
if(istype(W, /obj/item/weapon/wrench) || istype(W,/obj/item/stack) || istype(W, /obj/item/weapon/wirecutters))
return
else if(istype(W,/obj/item/roller_holder))
- if(buckled_mob)
- user_unbuckle_mob(user)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ user_unbuckle_mob(A, user)
else
visible_message("[user] collapses \the [src.name].")
new rollertype(get_turf(src))
@@ -287,14 +288,15 @@
/obj/structure/bed/roller/Move()
..()
- if(buckled_mob)
- if(buckled_mob.buckled == src)
- buckled_mob.loc = src.loc
- else
- buckled_mob = null
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+
+ if(L.buckled == src)
+ L.loc = src.loc
/obj/structure/bed/roller/post_buckle_mob(mob/living/M as mob)
- if(M == buckled_mob)
+ if(M.buckled == src)
M.pixel_y = 6
M.old_y = 6
density = 1
@@ -311,7 +313,7 @@
..()
if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src))))
if(!ishuman(usr)) return
- if(buckled_mob) return 0
+ if(has_buckled_mobs()) return 0
visible_message("[usr] collapses \the [src.name].")
new rollertype(get_turf(src))
spawn(0)
diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
index d1f2753e52..ed9c4e0301 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
@@ -31,7 +31,7 @@
qdel(src)
/obj/structure/bed/chair/attack_tk(mob/user as mob)
- if(buckled_mob)
+ if(has_buckled_mobs())
..()
else
rotate()
@@ -42,7 +42,7 @@
/obj/structure/bed/chair/update_icon()
..()
- if(buckled_mob && padding_material)
+ if(has_buckled_mobs() && padding_material)
var/cache_key = "[base_icon]-armrest-[padding_material.name]"
if(isnull(stool_cache[cache_key]))
var/image/I = image(icon, "[base_icon]_armrest")
@@ -60,8 +60,10 @@
/obj/structure/bed/chair/set_dir()
..()
update_layer()
- if(buckled_mob)
- buckled_mob.set_dir(dir)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ L.set_dir(dir)
/obj/structure/bed/chair/verb/rotate()
set name = "Rotate Chair"
@@ -136,45 +138,47 @@
/obj/structure/bed/chair/office/Move()
..()
- if(buckled_mob)
- var/mob/living/occupant = buckled_mob
- occupant.buckled = null
- occupant.Move(src.loc)
- occupant.buckled = src
- if (occupant && (src.loc != occupant.loc))
- if (propelled)
- for (var/mob/O in src.loc)
- if (O != occupant)
- Bump(O)
- else
- unbuckle_mob()
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/occupant = A
+ occupant.buckled = null
+ occupant.Move(src.loc)
+ occupant.buckled = src
+ if (occupant && (src.loc != occupant.loc))
+ if (propelled)
+ for (var/mob/O in src.loc)
+ if (O != occupant)
+ Bump(O)
+ else
+ unbuckle_mob()
/obj/structure/bed/chair/office/Bump(atom/A)
..()
- if(!buckled_mob) return
+ if(!has_buckled_mobs()) return
if(propelled)
- var/mob/living/occupant = unbuckle_mob()
+ for(var/a in buckled_mobs)
+ var/mob/living/occupant = unbuckle_mob(a)
- var/def_zone = ran_zone()
- var/blocked = occupant.run_armor_check(def_zone, "melee")
- var/soaked = occupant.get_armor_soak(def_zone, "melee")
- occupant.throw_at(A, 3, propelled)
- occupant.apply_effect(6, STUN, blocked)
- occupant.apply_effect(6, WEAKEN, blocked)
- occupant.apply_effect(6, STUTTER, blocked)
- occupant.apply_damage(10, BRUTE, def_zone, blocked, soaked)
- playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
- if(istype(A, /mob/living))
- var/mob/living/victim = A
- def_zone = ran_zone()
- blocked = victim.run_armor_check(def_zone, "melee")
- soaked = victim.get_armor_soak(def_zone, "melee")
- victim.apply_effect(6, STUN, blocked)
- victim.apply_effect(6, WEAKEN, blocked)
- victim.apply_effect(6, STUTTER, blocked)
- victim.apply_damage(10, BRUTE, def_zone, blocked, soaked)
- occupant.visible_message("[occupant] crashed into \the [A]!")
+ var/def_zone = ran_zone()
+ var/blocked = occupant.run_armor_check(def_zone, "melee")
+ var/soaked = occupant.get_armor_soak(def_zone, "melee")
+ occupant.throw_at(A, 3, propelled)
+ occupant.apply_effect(6, STUN, blocked)
+ occupant.apply_effect(6, WEAKEN, blocked)
+ occupant.apply_effect(6, STUTTER, blocked)
+ occupant.apply_damage(10, BRUTE, def_zone, blocked, soaked)
+ playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1)
+ if(istype(A, /mob/living))
+ var/mob/living/victim = A
+ def_zone = ran_zone()
+ blocked = victim.run_armor_check(def_zone, "melee")
+ soaked = victim.get_armor_soak(def_zone, "melee")
+ victim.apply_effect(6, STUN, blocked)
+ victim.apply_effect(6, WEAKEN, blocked)
+ victim.apply_effect(6, STUTTER, blocked)
+ victim.apply_damage(10, BRUTE, def_zone, blocked, soaked)
+ occupant.visible_message("[occupant] crashed into \the [A]!")
/obj/structure/bed/chair/office/light
icon_state = "officechair_white"
diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
index bdd4b87b0e..550b59d112 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
@@ -17,8 +17,10 @@
overlays = null
var/image/O = image(icon = 'icons/obj/furniture.dmi', icon_state = "w_overlay", layer = FLY_LAYER, dir = src.dir)
overlays += O
- if(buckled_mob)
- buckled_mob.set_dir(dir)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ L.set_dir(dir)
/obj/structure/bed/chair/wheelchair/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/wrench) || istype(W,/obj/item/stack) || istype(W, /obj/item/weapon/wirecutters))
@@ -33,7 +35,7 @@
user.pulledby = null
user << "You lost your grip!"
return
- if(buckled_mob && pulling && user == buckled_mob)
+ if(has_buckled_mobs() && pulling && user in buckled_mobs)
if(pulling.stat || pulling.stunned || pulling.weakened || pulling.paralysis || pulling.lying || pulling.restrained())
pulling.pulledby = null
pulling = null
@@ -51,7 +53,7 @@
if(pulling && (get_dir(src.loc, pulling.loc) == direction))
user << "You cannot go there."
return
- if(pulling && buckled_mob && (buckled_mob == user))
+ if(pulling && has_buckled_mobs() && (user in buckled_mobs))
user << "You cannot drive while being pushed."
return
@@ -59,10 +61,12 @@
driving = 1
var/turf/T = null
//--1---Move occupant---1--//
- if(buckled_mob)
- buckled_mob.buckled = null
- step(buckled_mob, direction)
- buckled_mob.buckled = src
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ L.buckled = null
+ step(L, direction)
+ L.buckled = src
//--2----Move driver----2--//
if(pulling)
T = pulling.loc
@@ -70,8 +74,9 @@
step(pulling, get_dir(pulling.loc, src.loc))
//--3--Move wheelchair--3--//
step(src, direction)
- if(buckled_mob) // Make sure it stays beneath the occupant
- Move(buckled_mob.loc)
+ if(has_buckled_mobs()) // Make sure it stays beneath the occupant
+ var/mob/living/L = buckled_mobs[1]
+ Move(L.loc)
set_dir(direction)
if(pulling) // Driver
if(pulling.loc == src.loc) // We moved onto the wheelchair? Revert!
@@ -88,38 +93,41 @@
/obj/structure/bed/chair/wheelchair/Move()
..()
- if(buckled_mob)
- var/mob/living/occupant = buckled_mob
- if(!driving)
- occupant.buckled = null
- occupant.Move(src.loc)
- occupant.buckled = src
- if (occupant && (src.loc != occupant.loc))
- if (propelled)
- for (var/mob/O in src.loc)
- if (O != occupant)
- Bump(O)
- else
- unbuckle_mob()
- if (pulling && (get_dist(src, pulling) > 1))
- pulling.pulledby = null
- pulling << "You lost your grip!"
- pulling = null
- else
- if (occupant && (src.loc != occupant.loc))
- src.forceMove(occupant.loc) // Failsafe to make sure the wheelchair stays beneath the occupant after driving
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/occupant = A
+ if(!driving)
+ occupant.buckled = null
+ occupant.Move(src.loc)
+ occupant.buckled = src
+ if (occupant && (src.loc != occupant.loc))
+ if (propelled)
+ for (var/mob/O in src.loc)
+ if (O != occupant)
+ Bump(O)
+ else
+ unbuckle_mob()
+ if (pulling && (get_dist(src, pulling) > 1))
+ pulling.pulledby = null
+ pulling << "You lost your grip!"
+ pulling = null
+ else
+ if (occupant && (src.loc != occupant.loc))
+ src.forceMove(occupant.loc) // Failsafe to make sure the wheelchair stays beneath the occupant after driving
/obj/structure/bed/chair/wheelchair/attack_hand(mob/living/user as mob)
if (pulling)
MouseDrop(usr)
else
- user_unbuckle_mob(user)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ user_unbuckle_mob(A, user)
return
/obj/structure/bed/chair/wheelchair/CtrlClick(var/mob/user)
if(in_range(src, user))
if(!ishuman(user)) return
- if(user == buckled_mob)
+ if(has_buckled_mobs() && user in buckled_mobs)
user << "You realize you are unable to push the wheelchair you sit in."
return
if(!pulling)
@@ -137,7 +145,7 @@
/obj/structure/bed/chair/wheelchair/Bump(atom/A)
..()
- if(!buckled_mob) return
+ if(!has_buckled_mobs()) return
if(propelled || (pulling && (pulling.a_intent == I_HURT)))
var/mob/living/occupant = unbuckle_mob()
@@ -213,7 +221,7 @@
..()
if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src))))
if(!ishuman(usr)) return
- if(buckled_mob) return 0
+ if(has_buckled_mobs()) return 0
visible_message("[usr] collapses \the [src.name].")
var/obj/item/wheelchair/R = new/obj/item/wheelchair(get_turf(src))
R.name = src.name
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index 2d07f0ffbd..f9331eac1d 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -73,7 +73,7 @@ var/list/mechtoys = list(
return prob(60)
var/obj/structure/bed/B = A
- if (istype(A, /obj/structure/bed) && B.buckled_mob)//if it's a bed/chair and someone is buckled, it will not pass
+ if (istype(A, /obj/structure/bed) && B.has_buckled_mobs())//if it's a bed/chair and someone is buckled, it will not pass
return 0
if(istype(A, /obj/vehicle)) //no vehicles
diff --git a/code/game/turfs/simulated/wall_types.dm b/code/game/turfs/simulated/wall_types.dm
index 19264e23ba..c137822860 100644
--- a/code/game/turfs/simulated/wall_types.dm
+++ b/code/game/turfs/simulated/wall_types.dm
@@ -48,16 +48,16 @@
..(newloc,"durasteel", "durasteel")
/turf/simulated/wall/wood/New(var/newloc)
- ..(newloc,"wood")
+ ..(newloc, MAT_WOOD)
/turf/simulated/wall/sifwood/New(var/newloc)
- ..(newloc,"alien wood")
+ ..(newloc, MAT_SIFWOOD)
/turf/simulated/wall/log/New(var/newloc)
- ..(newloc,"log")
+ ..(newloc, MAT_LOG)
/turf/simulated/wall/log_sif/New(var/newloc)
- ..(newloc,"alien log")
+ ..(newloc, MAT_SIFLOG)
// Shuttle Walls
/turf/simulated/shuttle/wall
diff --git a/code/game/turfs/simulated/water.dm b/code/game/turfs/simulated/water.dm
index 6f2c606c0d..e766b1bba3 100644
--- a/code/game/turfs/simulated/water.dm
+++ b/code/game/turfs/simulated/water.dm
@@ -55,6 +55,8 @@
if(istype(AM, /mob/living))
var/mob/living/L = AM
L.update_water()
+ if(L.check_submerged() <= 0)
+ return
if(!istype(oldloc, /turf/simulated/floor/water))
to_chat(L, "You get drenched in water from entering \the [src]!")
AM.water_act(5)
@@ -64,6 +66,8 @@
if(istype(AM, /mob/living))
var/mob/living/L = AM
L.update_water()
+ if(L.check_submerged() <= 0)
+ return
if(!istype(newloc, /turf/simulated/floor/water))
to_chat(L, "You climb out of \the [src].")
..()
@@ -97,6 +101,8 @@
return ..()
/mob/living/proc/check_submerged()
+ if(buckled)
+ return 0
var/turf/simulated/floor/water/T = loc
if(istype(T))
return T.depth
diff --git a/code/modules/hydroponics/spreading/spreading_growth.dm b/code/modules/hydroponics/spreading/spreading_growth.dm
index 0dbe4c9eea..bd4b48893f 100644
--- a/code/modules/hydroponics/spreading/spreading_growth.dm
+++ b/code/modules/hydroponics/spreading/spreading_growth.dm
@@ -73,10 +73,12 @@
else
plant.layer = layer + 0.1
- if(buckled_mob)
- seed.do_sting(buckled_mob,src)
- if(seed.get_trait(TRAIT_CARNIVOROUS))
- seed.do_thorns(buckled_mob,src)
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ seed.do_sting(L,src)
+ if(seed.get_trait(TRAIT_CARNIVOROUS))
+ seed.do_thorns(L,src)
if(world.time >= last_tick+NEIGHBOR_REFRESH_TIME)
last_tick = world.time
@@ -88,7 +90,7 @@
if(prob(chance))
sampled = 0
- if(is_mature() && !buckled_mob)
+ if(is_mature() && !has_buckled_mobs())
for(var/turf/neighbor in neighbors)
for(var/mob/living/M in neighbor)
if(seed.get_trait(TRAIT_SPREAD) >= 2 && (M.lying || prob(round(seed.get_trait(TRAIT_POTENCY)))))
@@ -107,7 +109,7 @@
// We shouldn't have spawned if the controller doesn't exist.
check_health()
- if(buckled_mob || neighbors.len)
+ if(has_buckled_mobs() || neighbors.len)
plant_controller.add_plant(src)
//spreading vines aren't created on their final turf.
diff --git a/code/modules/hydroponics/spreading/spreading_response.dm b/code/modules/hydroponics/spreading/spreading_response.dm
index 12747666c4..8a8ceabfeb 100644
--- a/code/modules/hydroponics/spreading/spreading_response.dm
+++ b/code/modules/hydroponics/spreading/spreading_response.dm
@@ -7,7 +7,7 @@
if(!istype(M))
return
- if(!buckled_mob && !M.buckled && !M.anchored && (issmall(M) || prob(round(seed.get_trait(TRAIT_POTENCY)/3))))
+ if(!has_buckled_mobs() && !M.buckled && !M.anchored && (issmall(M) || prob(round(seed.get_trait(TRAIT_POTENCY)/3))))
//wait a tick for the Entered() proc that called HasProximity() to finish (and thus the moving animation),
//so we don't appear to teleport from two tiles away when moving into a turf adjacent to vines.
spawn(1)
@@ -35,31 +35,35 @@
seed.do_sting(victim,src,pick("r_foot","l_foot","r_leg","l_leg"))
/obj/effect/plant/proc/unbuckle()
- if(buckled_mob)
- if(buckled_mob.buckled == src)
- buckled_mob.buckled = null
- buckled_mob.anchored = initial(buckled_mob.anchored)
- buckled_mob.update_canmove()
- buckled_mob = null
+ if(has_buckled_mobs())
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ if(L.buckled == src)
+ L.buckled = null
+ L.anchored = initial(L.anchored)
+ L.update_canmove()
+ buckled_mobs = list()
return
/obj/effect/plant/proc/manual_unbuckle(mob/user as mob)
- if(buckled_mob)
+ if(has_buckled_mobs())
var/chance = 20
if(seed)
chance = round(100/(20*seed.get_trait(TRAIT_POTENCY)/100))
if(prob(chance))
- if(buckled_mob != user)
- buckled_mob.visible_message(\
- "\The [user] frees \the [buckled_mob] from \the [src].",\
- "\The [user] frees you from \the [src].",\
- "You hear shredding and ripping.")
- else
- buckled_mob.visible_message(\
- "\The [buckled_mob] struggles free of \the [src].",\
- "You untangle \the [src] from around yourself.",\
- "You hear shredding and ripping.")
- unbuckle()
+ for(var/A in buckled_mobs)
+ var/mob/living/L = A
+ if(!(user in buckled_mobs))
+ L.visible_message(\
+ "\The [user] frees \the [L] from \the [src].",\
+ "\The [user] frees you from \the [src].",\
+ "You hear shredding and ripping.")
+ else
+ L.visible_message(\
+ "\The [L] struggles free of \the [src].",\
+ "You untangle \the [src] from around yourself.",\
+ "You hear shredding and ripping.")
+ unbuckle()
else
user.setClickCooldown(user.get_attack_speed())
health -= rand(1,5)
@@ -73,7 +77,7 @@
/obj/effect/plant/proc/entangle(var/mob/living/victim)
- if(buckled_mob)
+ if(has_buckled_mobs())
return
if(victim.buckled || victim.anchored)
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index 7b8a4d4647..a52d66a0fa 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -125,6 +125,9 @@
/material/wood/generate_recipes()
..()
+ recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]")
+ recipes += new/datum/stack_recipe("dragon boat", /obj/vehicle/boat/dragon, 50, time = 30 SECONDS, supplied_material = "[name]")
recipes += new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1)
recipes += new/datum/stack_recipe("wood circlet", /obj/item/clothing/head/woodcirclet, 1)
recipes += new/datum/stack_recipe("clipboard", /obj/item/weapon/clipboard, 1)
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index c662141fbd..0f76f6172e 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -201,33 +201,48 @@
/obj/item/stack/material/wood
name = "wooden plank"
icon_state = "sheet-wood"
- default_type = "wood"
+ default_type = MAT_WOOD
+
+/obj/item/stack/material/wood/sif
+ name = "alien wooden plank"
+ color = "#0099cc"
+ default_type = MAT_SIFWOOD
/obj/item/stack/material/log
name = "log"
icon_state = "sheet-log"
- default_type = "log"
+ default_type = MAT_LOG
no_variants = FALSE
color = "#824B28"
max_amount = 25
w_class = ITEMSIZE_HUGE
+ description_info = "Use inhand to craft things, or use a sharp and edged object on this to convert it into two wooden planks."
+ var/plank_type = /obj/item/stack/material/wood
/obj/item/stack/material/log/sif
name = "alien log"
- default_type = "alien log"
+ default_type = MAT_SIFLOG
color = "#0099cc"
+ plank_type = /obj/item/stack/material/wood/sif
/obj/item/stack/material/log/attackby(var/obj/item/W, var/mob/user)
- if(!istype(W))
+ if(!istype(W) || W.force <= 0)
return ..()
- if(W.sharp && W.edge && use(1))
- to_chat(user, "You cut up a log into planks.")
- playsound(get_turf(src), 'sound/effects/woodcutting.ogg', 50, 1)
- var/obj/item/stack/material/wood/existing_wood = locate() in user.loc
- var/obj/item/stack/material/wood/new_wood = new(user.loc)
- new_wood.amount = 2
- if(existing_wood)
- if(new_wood.transfer_to(existing_wood))
+ if(W.sharp && W.edge)
+ var/time = (3 SECONDS / max(W.force / 10, 1)) * W.toolspeed
+ user.setClickCooldown(time)
+ if(do_after(user, time, src) && use(1))
+ to_chat(user, "You cut up a log into planks.")
+ playsound(get_turf(src), 'sound/effects/woodcutting.ogg', 50, 1)
+ var/obj/item/stack/material/wood/existing_wood = null
+ for(var/obj/item/stack/material/wood/M in user.loc)
+ if(M.material.name == src.material.name)
+ existing_wood = M
+ break
+
+ var/obj/item/stack/material/wood/new_wood = new plank_type(user.loc)
+ new_wood.amount = 2
+ if(existing_wood && new_wood.transfer_to(existing_wood))
to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.")
else
return ..()
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index 6ad4a6487d..54a890074a 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -672,9 +672,9 @@ var/list/name_to_material
/material/wood
- name = "wood"
+ name = MAT_WOOD
stack_type = /obj/item/stack/material/wood
- icon_colour = "#824B28"
+ icon_colour = "#9c5930"
integrity = 50
icon_base = "wood"
explosion_resistance = 2
@@ -694,14 +694,14 @@ var/list/name_to_material
sheet_plural_name = "planks"
/material/wood/log
- name = "log"
+ name = MAT_LOG
icon_base = "log"
stack_type = /obj/item/stack/material/log
sheet_singular_name = null
sheet_plural_name = "pile"
/material/wood/log/sif
- name = "alien log"
+ name = MAT_SIFLOG
icon_colour = "#0099cc" // Cyan-ish
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
stack_type = /obj/item/stack/material/log/sif
@@ -713,7 +713,7 @@ var/list/name_to_material
shard_type = SHARD_NONE
/material/wood/sif
- name = "alien wood"
+ name = MAT_SIFWOOD
// stack_type = /obj/item/stack/material/wood/sif
icon_colour = "#0099cc" // Cyan-ish
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index bc75344484..b6c0376aef 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -95,6 +95,10 @@ var/list/slot_equipment_priority = list( \
//Returns the thing in our inactive hand
/mob/proc/get_inactive_hand()
+// Override for your specific mob's hands or lack thereof.
+/mob/proc/is_holding_item_of_type(typepath)
+ return FALSE
+
//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success.
/mob/proc/put_in_l_hand(var/obj/item/W)
if(lying || !istype(W))
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 149c1831f6..3f4a66476b 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -352,3 +352,10 @@ This saves us from having to call add_fingerprint() any time something is put in
if(slot_l_ear) return l_ear
if(slot_r_ear) return r_ear
return ..()
+
+
+/mob/living/carbon/human/is_holding_item_of_type(typepath)
+ for(var/obj/item/I in list(l_hand, r_hand))
+ if(istype(I, typepath))
+ return I
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/resist.dm b/code/modules/mob/living/carbon/resist.dm
index 86597afba6..5c72bd224b 100644
--- a/code/modules/mob/living/carbon/resist.dm
+++ b/code/modules/mob/living/carbon/resist.dm
@@ -175,4 +175,4 @@
return
visible_message("[usr] manages to unbuckle themself!",
"You successfully unbuckle yourself.")
- buckled.user_unbuckle_mob(src)
+ buckled.user_unbuckle_mob(src, src)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 15de0b93d9..90ef8ff3cc 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -822,7 +822,7 @@ default behaviour is:
/mob/living/proc/escape_buckle()
if(buckled)
- buckled.user_unbuckle_mob(src)
+ buckled.user_unbuckle_mob(src, src)
/mob/living/proc/resist_grab()
var/resisting = 0
@@ -951,11 +951,14 @@ default behaviour is:
if(is_physically_disabled())
lying = 0
canmove = 1
- pixel_y = V.mob_offset_y - 5
+ if(!V.riding_datum) // If it has a riding datum, the datum handles moving the pixel_ vars.
+ pixel_y = V.mob_offset_y - 5
else
- if(buckled.buckle_lying != -1) lying = buckled.buckle_lying
+ if(buckled.buckle_lying != -1)
+ lying = buckled.buckle_lying
canmove = 1
- pixel_y = V.mob_offset_y
+ if(!V.riding_datum) // If it has a riding datum, the datum handles moving the pixel_ vars.
+ pixel_y = V.mob_offset_y
else if(buckled)
anchored = 1
canmove = 0
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 4b492a9498..6d44a4907a 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -338,8 +338,9 @@
weaponlock_time = 120
/mob/living/silicon/robot/update_canmove()
- if(paralysis || stunned || weakened || buckled || lockdown || !is_component_functioning("actuator")) canmove = 0
- else canmove = 1
+ ..() // Let's not reinvent the wheel.
+ if(lockdown || !is_component_functioning("actuator"))
+ canmove = FALSE
return canmove
/mob/living/silicon/robot/update_fire()
diff --git a/code/modules/mob/living/simple_animal/slime/combat.dm b/code/modules/mob/living/simple_animal/slime/combat.dm
index 8554a27e5f..5aee0a7a3a 100644
--- a/code/modules/mob/living/simple_animal/slime/combat.dm
+++ b/code/modules/mob/living/simple_animal/slime/combat.dm
@@ -44,11 +44,12 @@
if(istype(L, /mob/living/carbon) && L.getCloneLoss() >= L.getMaxHealth() * 1.5 || istype(L, /mob/living/simple_animal) && L.stat == DEAD)
to_chat(src, "This subject does not have an edible life energy...")
return FALSE
- if(L.buckled_mob)
- if(istype(L.buckled_mob, /mob/living/simple_animal/slime))
- if(L.buckled_mob != src)
- to_chat(src, "\The [L.buckled_mob] is already feeding on this subject...")
- return FALSE
+ if(L.has_buckled_mobs())
+ for(var/A in L.buckled_mobs)
+ if(istype(A, /mob/living/simple_animal/slime))
+ if(A != src)
+ to_chat(src, "\The [A] is already feeding on this subject...")
+ return FALSE
return TRUE
/mob/living/simple_animal/slime/proc/start_consuming(var/mob/living/L)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index e73d316433..af72ba4dd4 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -167,6 +167,12 @@
src.m_flag = 1
if ((A != src.loc && A && A.z == src.z))
src.last_move = get_dir(A, src.loc)
+ if(.)
+ Moved(A, direct)
+ return
+
+// Called on a successful Move().
+/atom/movable/proc/Moved(atom/oldloc)
return
/client/proc/Move_object(direct)
@@ -533,23 +539,23 @@
/mob/proc/update_gravity()
return
-
+/*
// The real Move() proc is above, but touching that massive block just to put this in isn't worth it.
/mob/Move(var/newloc, var/direct)
. = ..(newloc, direct)
if(.)
post_move(newloc, direct)
-
+*/
// Called when a mob successfully moves.
// Would've been an /atom/movable proc but it caused issues.
-/mob/proc/post_move(var/newloc, var/direct)
+/mob/Moved(atom/oldloc)
for(var/obj/O in contents)
- O.on_loc_moved(newloc, direct)
+ O.on_loc_moved(oldloc)
-// Received from post_move(), useful for items that need to know that their loc just moved.
-/obj/proc/on_loc_moved(var/newloc, var/direct)
+// Received from Moved(), useful for items that need to know that their loc just moved.
+/obj/proc/on_loc_moved(atom/oldloc)
return
-/obj/item/weapon/storage/on_loc_moved(var/newloc, var/direct)
+/obj/item/weapon/storage/on_loc_moved(atom/oldloc)
for(var/obj/O in contents)
- O.on_loc_moved(newloc, direct)
\ No newline at end of file
+ O.on_loc_moved(oldloc)
\ No newline at end of file
diff --git a/code/modules/shieldgen/directional_shield.dm b/code/modules/shieldgen/directional_shield.dm
index 41bcda3ceb..1892a3f3ad 100644
--- a/code/modules/shieldgen/directional_shield.dm
+++ b/code/modules/shieldgen/directional_shield.dm
@@ -208,7 +208,7 @@
..(newloc, direct)
update_shield_positions()
-/obj/item/shield_projector/on_loc_moved(var/newloc, var/direct)
+/obj/item/shield_projector/on_loc_moved(atom/oldloc)
update_shield_positions()
diff --git a/code/modules/vehicles/bike.dm b/code/modules/vehicles/bike.dm
index 8136b06353..f455be67a5 100644
--- a/code/modules/vehicles/bike.dm
+++ b/code/modules/vehicles/bike.dm
@@ -118,8 +118,9 @@
..()
/obj/vehicle/bike/bullet_act(var/obj/item/projectile/Proj)
- if(buckled_mob && prob(protection_percent))
- buckled_mob.bullet_act(Proj)
+ if(has_buckled_mobs() && prob(protection_percent))
+ var/mob/living/L = pick(buckled_mobs)
+ L.bullet_act(Proj)
return
..()
diff --git a/code/modules/vehicles/boat.dm b/code/modules/vehicles/boat.dm
new file mode 100644
index 0000000000..ea17e29678
--- /dev/null
+++ b/code/modules/vehicles/boat.dm
@@ -0,0 +1,82 @@
+/obj/vehicle/boat
+ name = "boat"
+ desc = "It's a wooden boat. Looks like it'll hold two people. Oars not included."
+ icon = 'icons/obj/vehicles_36x32.dmi'
+ icon_state = "boat"
+ health = 100
+ maxhealth = 100
+ charge_use = 0 // Boats use oars.
+ pixel_x = -2
+ move_delay = 3 // Rather slow, but still faster than swimming, and won't get you wet.
+ max_buckled_mobs = 2
+ anchored = FALSE
+ var/material/material = null
+ var/riding_datum_type = /datum/riding/boat/small
+
+/obj/vehicle/boat/sifwood/New(newloc, material_name)
+ ..(newloc, MAT_SIFWOOD)
+
+/obj/vehicle/boat/dragon
+ name = "dragon boat"
+ desc = "It's a large wooden boat, carved to have a nordic-looking dragon on the front. Looks like it'll hold five people. Oars not included."
+ icon = 'icons/obj/64x32.dmi'
+ icon_state = "dragon_boat"
+ health = 250
+ maxhealth = 250
+ pixel_x = -16
+ max_buckled_mobs = 5
+ riding_datum_type = /datum/riding/boat/big
+
+/obj/vehicle/boat/dragon/New(newloc, material_name)
+ ..(newloc, material_name)
+ var/image/I = image(icon, src, "dragon_boat_underlay", BELOW_MOB_LAYER)
+ underlays += I
+
+/obj/vehicle/boat/dragon/sifwood/New(newloc, material_name)
+ ..(newloc, MAT_SIFWOOD)
+
+// Oars, which must be held inhand while in a boat to move it.
+/obj/item/weapon/oar
+ name = "oar"
+ icon = 'icons/obj/vehicles.dmi'
+ desc = "Used to provide propulsion to a boat."
+ icon_state = "oar"
+ item_state = "oar"
+ force = 12
+ var/material/material = null
+
+/obj/item/weapon/oar/sifwood/New(newloc, material_name)
+ ..(newloc, MAT_SIFWOOD)
+
+/obj/item/weapon/oar/New(newloc, material_name)
+ ..(newloc)
+ if(!material_name)
+ material_name = "wood"
+ material = get_material_by_name("[material_name]")
+ if(!material)
+ qdel(src)
+ return
+ color = material.icon_colour
+
+/obj/vehicle/boat/New(newloc, material_name)
+ ..(newloc)
+ if(!material_name)
+ material_name = "wood"
+ material = get_material_by_name("[material_name]")
+ if(!material)
+ qdel(src)
+ return
+ color = material.icon_colour
+ riding_datum = new riding_datum_type(src)
+
+// Boarding.
+/obj/vehicle/boat/MouseDrop_T(var/atom/movable/C, mob/user)
+ if(ismob(C))
+ user_buckle_mob(C, user)
+ else
+ ..(C, user)
+
+/obj/vehicle/boat/load(mob/living/L, mob/living/user)
+ if(!istype(L)) // Only mobs on boats.
+ return FALSE
+ ..(L, user)
diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm
index 7d6acc5fae..e1c643b776 100644
--- a/code/modules/vehicles/cargo_train.dm
+++ b/code/modules/vehicles/cargo_train.dm
@@ -81,8 +81,9 @@
//cargo trains are open topped, so there is a chance the projectile will hit the mob ridding the train instead
/obj/vehicle/train/cargo/bullet_act(var/obj/item/projectile/Proj)
- if(buckled_mob && prob(70))
- buckled_mob.bullet_act(Proj)
+ if(has_buckled_mobs() && prob(70))
+ var/mob/living/L = pick(buckled_mobs)
+ L.bullet_act(Proj)
return
..()
@@ -256,7 +257,7 @@
//-------------------------------------------
// Loading/unloading procs
//-------------------------------------------
-/obj/vehicle/train/cargo/trolley/load(var/atom/movable/C)
+/obj/vehicle/train/cargo/trolley/load(var/atom/movable/C, var/mob/user)
if(ismob(C) && !passenger_allowed)
return 0
if(!istype(C,/obj/machinery) && !istype(C,/obj/structure/closet) && !istype(C,/obj/structure/largecrate) && !istype(C,/obj/structure/reagent_dispensers) && !istype(C,/obj/structure/ore_box) && !istype(C, /mob/living/carbon/human))
@@ -267,12 +268,12 @@
if(istype(C, /obj/machinery))
load_object(C)
else
- ..()
+ ..(C, user)
if(load)
return 1
-/obj/vehicle/train/cargo/engine/load(var/atom/movable/C)
+/obj/vehicle/train/cargo/engine/load(var/atom/movable/C, var/mob/user)
if(!istype(C, /mob/living/carbon/human))
return 0
diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm
index 59396f9daa..c59ffe7e64 100644
--- a/code/modules/vehicles/train.dm
+++ b/code/modules/vehicles/train.dm
@@ -95,7 +95,7 @@
if(istype(C,/obj/vehicle/train))
latch(C, user)
else
- if(!load(C))
+ if(!load(C, user))
user << "You were unable to load [C] on [src]."
/obj/vehicle/train/attack_hand(mob/user as mob)
@@ -107,7 +107,7 @@
else if(load)
unload(user) //unload if loaded
else if(!load && !user.buckled)
- load(user) //else try climbing on board
+ load(user, user) //else try climbing on board
else
return 0
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index f725508c88..7bd11955e3 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -17,6 +17,7 @@
buckle_movable = 1
buckle_lying = 0
+ var/mechanical = TRUE // If false, doesn't care for things like cells, engines, EMP, keys, etc.
var/attack_log = null
var/on = 0
var/health = 0 //do not forget to set health for your vehicle!
@@ -39,6 +40,8 @@
var/load_offset_y = 0 //pixel_y offset for item overlay
var/mob_offset_y = 0 //pixel_y offset for mob overlay
+ var/datum/riding/riding_datum = null
+
//-------------------------------------------
// Standard procs
//-------------------------------------------
@@ -46,10 +49,47 @@
..()
//spawn the cell you want in each vehicle
+/obj/vehicle/Destroy()
+ qdel_null(riding_datum)
+ return ..()
+
+//BUCKLE HOOKS
+
+/obj/vehicle/buckle_mob(mob/living/M, forced = FALSE, check_loc = TRUE)
+ . = ..()
+ M.update_water()
+ if(riding_datum)
+ riding_datum.ridden = src
+ riding_datum.handle_vehicle_offsets()
+
+/obj/vehicle/unbuckle_mob(mob/living/buckled_mob, force = FALSE)
+ . = ..(buckled_mob, force)
+ buckled_mob.update_water()
+ if(riding_datum)
+ riding_datum.restore_position(buckled_mob)
+ riding_datum.handle_vehicle_offsets() // So the person in back goes to the front.
+
+/obj/vehicle/set_dir(newdir)
+ ..(newdir)
+ if(riding_datum)
+ riding_datum.handle_vehicle_offsets()
+
+//MOVEMENT
+/obj/vehicle/relaymove(mob/user, direction)
+ if(riding_datum)
+ riding_datum.handle_ride(user, direction)
+
+
+/obj/vehicle/Moved()
+ . = ..()
+ if(riding_datum)
+ riding_datum.handle_vehicle_layer()
+ riding_datum.handle_vehicle_offsets()
+
/obj/vehicle/Move()
if(world.time > l_move_time + move_delay)
var/old_loc = get_turf(src)
- if(on && powered && cell.charge < charge_use)
+ if(mechanical && on && powered && cell.charge < charge_use)
turn_off()
var/init_anc = anchored
@@ -61,7 +101,7 @@
set_dir(get_dir(old_loc, loc))
anchored = init_anc
- if(on && powered)
+ if(mechanical && on && powered)
cell.use(charge_use)
//Dummy loads do not have to be moved as they are just an overlay
@@ -77,32 +117,34 @@
/obj/vehicle/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/hand_labeler))
return
- if(istype(W, /obj/item/weapon/screwdriver))
- if(!locked)
- open = !open
- update_icon()
- user << "Maintenance panel is now [open ? "opened" : "closed"]."
- playsound(src, W.usesound, 50, 1)
- else if(istype(W, /obj/item/weapon/crowbar) && cell && open)
- remove_cell(user)
+ if(mechanical)
+ if(istype(W, /obj/item/weapon/screwdriver))
+ if(!locked)
+ open = !open
+ update_icon()
+ user << "Maintenance panel is now [open ? "opened" : "closed"]."
+ playsound(src, W.usesound, 50, 1)
+ else if(istype(W, /obj/item/weapon/crowbar) && cell && open)
+ remove_cell(user)
- else if(istype(W, /obj/item/weapon/cell) && !cell && open)
- insert_cell(W, user)
- else if(istype(W, /obj/item/weapon/weldingtool))
- var/obj/item/weapon/weldingtool/T = W
- if(T.welding)
- if(health < maxhealth)
- if(open)
- health = min(maxhealth, health+10)
- user.setClickCooldown(user.get_attack_speed(W))
- playsound(src, T.usesound, 50, 1)
- user.visible_message("[user] repairs [src]!"," You repair [src]!")
+ else if(istype(W, /obj/item/weapon/cell) && !cell && open)
+ insert_cell(W, user)
+ else if(istype(W, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/T = W
+ if(T.welding)
+ if(health < maxhealth)
+ if(open)
+ health = min(maxhealth, health+10)
+ user.setClickCooldown(user.get_attack_speed(W))
+ playsound(src, T.usesound, 50, 1)
+ user.visible_message("[user] repairs [src]!"," You repair [src]!")
+ else
+ user << "Unable to repair with the maintenance panel closed."
else
- user << "Unable to repair with the maintenance panel closed."
+ user << "[src] does not need a repair."
else
- user << "[src] does not need a repair."
- else
- user << "Unable to repair while [src] is off."
+ user << "Unable to repair while [src] is off."
+
else if(hasvar(W,"force") && hasvar(W,"damtype"))
user.setClickCooldown(user.get_attack_speed(W))
switch(W.damtype)
@@ -139,6 +181,9 @@
return
/obj/vehicle/emp_act(severity)
+ if(!mechanical)
+ return
+
var/was_on = on
stat |= EMPED
var/obj/effect/overlay/pulse2 = new /obj/effect/overlay(src.loc)
@@ -168,41 +213,37 @@
// Vehicle procs
//-------------------------------------------
/obj/vehicle/proc/turn_on()
- if(stat)
- return 0
+ if(!mechanical || stat)
+ return FALSE
if(powered && cell.charge < charge_use)
- return 0
+ return FALSE
on = 1
set_light(initial(light_range))
update_icon()
- return 1
+ return TRUE
/obj/vehicle/proc/turn_off()
+ if(!mechanical)
+ return FALSE
on = 0
set_light(0)
update_icon()
/obj/vehicle/emag_act(var/remaining_charges, mob/user as mob)
+ if(!mechanical)
+ return FALSE
+
if(!emagged)
emagged = 1
if(locked)
locked = 0
user << "You bypass [src]'s controls."
- return 1
+ return TRUE
/obj/vehicle/proc/explode()
src.visible_message("[src] blows apart!", 1)
var/turf/Tsec = get_turf(src)
- new /obj/item/stack/rods(Tsec)
- new /obj/item/stack/rods(Tsec)
- new /obj/item/stack/cable_coil/cut(Tsec)
-
- if(cell)
- cell.forceMove(Tsec)
- cell.update_icon()
- cell = null
-
//stuns people who are thrown off a train that has been blown up
if(istype(load, /mob/living))
var/mob/living/M = load
@@ -210,8 +251,17 @@
unload()
- new /obj/effect/gibspawner/robot(Tsec)
- new /obj/effect/decal/cleanable/blood/oil(src.loc)
+ if(mechanical)
+ new /obj/item/stack/rods(Tsec)
+ new /obj/item/stack/rods(Tsec)
+ new /obj/item/stack/cable_coil/cut(Tsec)
+ new /obj/effect/gibspawner/robot(Tsec)
+ new /obj/effect/decal/cleanable/blood/oil(src.loc)
+
+ if(cell)
+ cell.forceMove(Tsec)
+ cell.update_icon()
+ cell = null
qdel(src)
@@ -220,6 +270,9 @@
explode()
/obj/vehicle/proc/powercheck()
+ if(!mechanical)
+ return
+
if(!cell && !powered)
return
@@ -236,6 +289,8 @@
return
/obj/vehicle/proc/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H)
+ if(!mechanical)
+ return
if(cell)
return
if(!istype(C))
@@ -248,6 +303,8 @@
usr << "You install [C] in [src]."
/obj/vehicle/proc/remove_cell(var/mob/living/carbon/human/H)
+ if(mechanical)
+ return
if(!cell)
return
@@ -267,7 +324,7 @@
// the vehicle load() definition before
// calling this parent proc.
//-------------------------------------------
-/obj/vehicle/proc/load(var/atom/movable/C)
+/obj/vehicle/proc/load(var/atom/movable/C, var/mob/living/user)
//This loads objects onto the vehicle so they can still be interacted with.
//Define allowed items for loading in specific vehicle definitions.
if(!isturf(C.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly.
@@ -292,10 +349,10 @@
C.pixel_y += mob_offset_y
else
C.pixel_y += load_offset_y
- C.layer = layer + 0.1 //so it sits above the vehicle
+ C.layer = layer + 0.1
if(ismob(C))
- buckle_mob(C)
+ user_buckle_mob(C, user)
return 1
@@ -358,7 +415,7 @@
user.attack_log += text("\[[time_stamp()]\] attacked [src.name]")
user.do_attack_animation(src)
src.health -= damage
- if(prob(10))
+ if(mechanical && prob(10))
new /obj/effect/decal/cleanable/blood/oil(src.loc)
spawn(1) healthcheck()
return 1
diff --git a/html/changelogs/Neerti - Boats.yml b/html/changelogs/Neerti - Boats.yml
new file mode 100644
index 0000000000..855b8eb69b
--- /dev/null
+++ b/html/changelogs/Neerti - Boats.yml
@@ -0,0 +1,36 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Neerti
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Adds boats that can be ridden by multiple people, which use oars. Can be crafted with large amounts of wooden planks."
diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi
index 5bda3bc7a3..3f2e4217f4 100644
Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ
diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi
index d44cff61fd..5c4521e6e6 100644
Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ
diff --git a/icons/obj/64x32.dmi b/icons/obj/64x32.dmi
new file mode 100644
index 0000000000..84cabfc551
Binary files /dev/null and b/icons/obj/64x32.dmi differ
diff --git a/icons/obj/vehicles.dmi b/icons/obj/vehicles.dmi
index e70275591f..85e245ce9f 100644
Binary files a/icons/obj/vehicles.dmi and b/icons/obj/vehicles.dmi differ
diff --git a/icons/obj/vehicles_36x32.dmi b/icons/obj/vehicles_36x32.dmi
new file mode 100644
index 0000000000..f32d433916
Binary files /dev/null and b/icons/obj/vehicles_36x32.dmi differ
diff --git a/polaris.dme b/polaris.dme
index c22e8d991b..c5b957df64 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -193,6 +193,7 @@
#include "code\datums\organs.dm"
#include "code\datums\progressbar.dm"
#include "code\datums\recipe.dm"
+#include "code\datums\riding.dm"
#include "code\datums\sun.dm"
#include "code\datums\weakref.dm"
#include "code\datums\autolathe\arms.dm"
@@ -2272,6 +2273,7 @@
#include "code\modules\turbolift\turbolift_map.dm"
#include "code\modules\turbolift\turbolift_process.dm"
#include "code\modules\turbolift\turbolift_turfs.dm"
+#include "code\modules\vehicles\boat.dm"
#include "code\modules\vehicles\cargo_train.dm"
#include "code\modules\vehicles\train.dm"
#include "code\modules\vehicles\vehicle.dm"