Adds Boats, Ports /TG/ Buckling (#4527)

* Adds Boats, Ports /TG/ Buckling

* Travis Appeasement

* Changelog
This commit is contained in:
Neerti
2018-01-14 15:58:15 -05:00
committed by Anewbe
parent 3715fa1f12
commit 96d3d361d0
52 changed files with 888 additions and 327 deletions

View File

@@ -71,20 +71,23 @@
else if(istype(loc, /turf/space/))
parent.radiate_heat_to_space(surface, 1)
if(buckled_mob)
if(has_buckled_mobs())
for(var/M in buckled_mobs)
var/mob/living/L = M
var/hc = pipe_air.heat_capacity()
var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500)
var/avg_temp = (pipe_air.temperature * hc + L.bodytemperature * 3500) / (hc + 3500)
pipe_air.temperature = avg_temp
buckled_mob.bodytemperature = avg_temp
L.bodytemperature = avg_temp
var/heat_limit = 1000
var/mob/living/carbon/human/H = buckled_mob
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)
buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_TORSO, used_weapon = "Excessive Heat")
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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -5,7 +5,7 @@
return occupant
/obj/vehicle/train/get_mob()
return buckled_mob
return buckled_mobs
/mob/get_mob()
return src

224
code/datums/riding.dm Normal file
View File

@@ -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, "<span class='warning'>\The [ridden] can only be controlled by one person at a time, and is currently being controlled by \the [driver].</span>")
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, "<span class='warning'>You'll need [key_name] in one of your hands to move \the [ridden].</span>")
/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, "<span class='warning'>Boats don't go on land!</span>")
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))

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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("<span class='warning'>You can't load living things into the cargo compartment.</span>")

View File

@@ -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 << "<span class='notice'>\The [src] already has someone buckled to it.</span>"
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, "<span class='notice'>\The [src] can't buckle anymore people.</span>")
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 << "<span class='warning'>You can't buckle anyone in before the game starts.</span>"
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, "<span class='warning'>\The [M] is already buckled to \the [src].</span>")
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 @@
"<span class='danger'>You are buckled to [src] by [user.name]!</span>",\
"<span class='notice'>You hear metal clanking.</span>")
/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
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
buckled_mob.set_dir(dir)
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

View File

@@ -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.

View File

@@ -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(
"<span class='notice'>[user] begins freeing [buckled_mob] from \the [src].</span>",
"<span class='notice'>You carefully begin to free [buckled_mob] from \the [src].</span>",
"<span class='notice'>[user] begins freeing [victim] from \the [src].</span>",
"<span class='notice'>You carefully begin to free [victim] from \the [src].</span>",
)
if(do_after(user, 60))
user.visible_message("<span class='notice'>[buckled_mob] has been freed from \the [src] by [user].</span>")
unbuckle_mob()
user.visible_message("<span class='notice'>[victim] has been freed from \the [src] by [user].</span>")
for(var/A in buckled_mobs)
unbuckle_mob(A)
anchored = 0
else if(deployed && can_use(user))
user.visible_message(
@@ -109,7 +111,7 @@
"<b>You hear a loud metallic snap!</b>"
)
attack_mob(L)
if(!buckled_mob)
if(!has_buckled_mobs())
anchored = 0
deployed = 0
update_icon()

View File

@@ -111,39 +111,41 @@
processing_objects |= src
/obj/effect/energy_net/Destroy()
if(buckled_mob)
to_chat(buckled_mob,"<span class='notice'>You are free of the net!</span>")
unbuckle_mob()
if(has_buckled_mobs())
for(var/A in buckled_mobs)
to_chat(A,"<span class='notice'>You are free of the net!</span>")
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
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()
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("<span class='danger'>[user] begins to tear at \the [src]!</span>")
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("<span class='danger'>[user] manages to tear \the [src] apart!</span>")
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

View File

@@ -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

View File

@@ -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++

View File

@@ -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 << "<span class='danger'>You feel a deep shock course through your body!</span>"
if(has_buckled_mobs())
for(var/a in buckled_mobs)
var/mob/living/L = a
L.burn_skin(85)
to_chat(L, "<span class='danger'>You feel a deep shock course through your body!</span>")
sleep(1)
buckled_mob.burn_skin(85)
buckled_mob.Stun(600)
L.burn_skin(85)
L.Stun(600)
visible_message("<span class='danger'>The electric chair went off!</span>", "<span class='danger'>You hear a deep sharp shock!</span>")
A.power_light = light

View File

@@ -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)
if(has_buckled_mobs())
for(var/A in buckled_mobs)
var/mob/living/L = A
L.set_dir(dir)
switch(dir)
if(SOUTH)
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 7
L.pixel_x = 0
L.pixel_y = 7
if(WEST)
buckled_mob.pixel_x = 13
buckled_mob.pixel_y = 7
L.pixel_x = 13
L.pixel_y = 7
if(NORTH)
buckled_mob.pixel_x = 0
buckled_mob.pixel_y = 4
L.pixel_x = 0
L.pixel_y = 4
if(EAST)
buckled_mob.pixel_x = -13
buckled_mob.pixel_y = 7
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("<span class='warning'>[Proj] ricochets off the [callme]!</span>")

View File

@@ -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")

View File

@@ -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 @@
"<span class='notice'>You hear squelching...</span>")
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

View File

@@ -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, "<span class='notice'>\The [src] already has someone buckled to it.</span>")
return
user.visible_message("<span class='notice'>[user] attempts to buckle [affecting] into \the [src]!</span>")
@@ -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)

View File

@@ -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,8 +138,9 @@
/obj/structure/bed/chair/office/Move()
..()
if(buckled_mob)
var/mob/living/occupant = buckled_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
@@ -151,10 +154,11 @@
/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")

View File

@@ -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 << "<span class='warning'>You lost your grip!</span>"
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 << "<span class='warning'>You cannot go there.</span>"
return
if(pulling && buckled_mob && (buckled_mob == user))
if(pulling && has_buckled_mobs() && (user in buckled_mobs))
user << "<span class='warning'>You cannot drive while being pushed.</span>"
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,8 +93,9 @@
/obj/structure/bed/chair/wheelchair/Move()
..()
if(buckled_mob)
var/mob/living/occupant = buckled_mob
if(has_buckled_mobs())
for(var/A in buckled_mobs)
var/mob/living/occupant = A
if(!driving)
occupant.buckled = null
occupant.Move(src.loc)
@@ -113,13 +119,15 @@
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 << "<span class='warning'>You realize you are unable to push the wheelchair you sit in.</span>"
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

View File

@@ -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

View File

@@ -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

View File

@@ -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, "<span class='warning'>You get drenched in water from entering \the [src]!</span>")
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, "<span class='warning'>You climb out of \the [src].</span>")
..()
@@ -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

View File

@@ -73,10 +73,12 @@
else
plant.layer = layer + 0.1
if(buckled_mob)
seed.do_sting(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(buckled_mob,src)
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.

View File

@@ -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,28 +35,32 @@
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(\
"<span class='notice'>\The [user] frees \the [buckled_mob] from \the [src].</span>",\
for(var/A in buckled_mobs)
var/mob/living/L = A
if(!(user in buckled_mobs))
L.visible_message(\
"<span class='notice'>\The [user] frees \the [L] from \the [src].</span>",\
"<span class='notice'>\The [user] frees you from \the [src].</span>",\
"<span class='warning'>You hear shredding and ripping.</span>")
else
buckled_mob.visible_message(\
"<span class='notice'>\The [buckled_mob] struggles free of \the [src].</span>",\
L.visible_message(\
"<span class='notice'>\The [L] struggles free of \the [src].</span>",\
"<span class='notice'>You untangle \the [src] from around yourself.</span>",\
"<span class='warning'>You hear shredding and ripping.</span>")
unbuckle()
@@ -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)

View File

@@ -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)

View File

@@ -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))
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, "<span class='notice'>You cut up a log into planks.</span>")
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)
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)
if(new_wood.transfer_to(existing_wood))
if(existing_wood && new_wood.transfer_to(existing_wood))
to_chat(user, "<span class='notice'>You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.</span>")
else
return ..()

View File

@@ -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.

View File

@@ -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))

View File

@@ -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

View File

@@ -175,4 +175,4 @@
return
visible_message("<span class='danger'>[usr] manages to unbuckle themself!</span>",
"<span class='notice'>You successfully unbuckle yourself.</span>")
buckled.user_unbuckle_mob(src)
buckled.user_unbuckle_mob(src, src)

View File

@@ -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,10 +951,13 @@ default behaviour is:
if(is_physically_disabled())
lying = 0
canmove = 1
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
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

View File

@@ -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()

View File

@@ -44,10 +44,11 @@
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...")
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

View File

@@ -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)
O.on_loc_moved(oldloc)

View File

@@ -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()

View File

@@ -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
..()

View File

@@ -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)

View File

@@ -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

View File

@@ -95,7 +95,7 @@
if(istype(C,/obj/vehicle/train))
latch(C, user)
else
if(!load(C))
if(!load(C, user))
user << "<font color='red'>You were unable to load [C] on [src].</font>"
/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

View File

@@ -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,6 +117,7 @@
/obj/vehicle/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/hand_labeler))
return
if(mechanical)
if(istype(W, /obj/item/weapon/screwdriver))
if(!locked)
open = !open
@@ -103,6 +144,7 @@
user << "<span class='notice'>[src] does not need a repair.</span>"
else
user << "<span class='notice'>Unable to repair while [src] is off.</span>"
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 << "<span class='warning'>You bypass [src]'s controls.</span>"
return 1
return TRUE
/obj/vehicle/proc/explode()
src.visible_message("<font color='red'><B>[src] blows apart!</B></font>", 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,9 +251,18 @@
unload()
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)
/obj/vehicle/proc/healthcheck()
@@ -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 << "<span class='notice'>You install [C] in [src].</span>"
/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()]\] <font color='red'>attacked [src.name]</font>")
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

View File

@@ -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."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

BIN
icons/obj/64x32.dmi Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -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"