mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
453 lines
12 KiB
Plaintext
453 lines
12 KiB
Plaintext
//Dummy object for holding items in vehicles.
|
|
//Prevents items from being interacted with.
|
|
/datum/vehicle_dummy_load
|
|
var/name = "dummy load"
|
|
var/actual_load
|
|
|
|
/obj/vehicle
|
|
name = "vehicle"
|
|
icon = 'icons/obj/vehicles.dmi'
|
|
layer = MOB_LAYER + 0.1 //so it sits above objects including mobs
|
|
density = TRUE
|
|
anchored = TRUE
|
|
animate_movement=1
|
|
light_range = 3
|
|
|
|
can_buckle = TRUE
|
|
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!
|
|
var/maxhealth = 0
|
|
var/fire_dam_coeff = 1.0
|
|
var/brute_dam_coeff = 1.0
|
|
var/open = 0 //Maint panel
|
|
var/locked = 1
|
|
var/stat = 0
|
|
var/emagged = 0
|
|
var/powered = 0 //set if vehicle is powered and should use fuel when moving
|
|
var/move_delay = 1 //set this to limit the speed of the vehicle
|
|
|
|
var/obj/item/cell/cell
|
|
var/charge_use = 5 //set this to adjust the amount of power the vehicle uses per move
|
|
|
|
var/paint_color = "#666666" //For vehicles with special paint overlays.
|
|
|
|
var/atom/movable/load //all vehicles can take a load, since they should all be a least drivable
|
|
var/load_item_visible = 1 //set if the loaded item should be overlayed on the vehicle sprite
|
|
var/load_offset_x = 0 //pixel_x offset for item overlay
|
|
var/load_offset_y = 0 //pixel_y offset for item overlay
|
|
var/mob_offset_y = 0 //pixel_y offset for mob overlay
|
|
|
|
var/datum/looping_sound/idle_carengine/soundloop //CHOMPedit: Looping engine audio.
|
|
|
|
//-------------------------------------------
|
|
// Standard procs
|
|
//-------------------------------------------
|
|
//ChompADD START
|
|
/obj/vehicle/Initialize(mapload)
|
|
. = ..()
|
|
soundloop = new(list(src), FALSE)
|
|
//ChompADD END
|
|
|
|
///obj/vehicle/New()
|
|
// ..()
|
|
// //spawn the cell you want in each vehicle // CHOMPedit: Commented out in favour of initialize.
|
|
|
|
/obj/vehicle/Destroy()
|
|
QDEL_NULL(riding_datum)
|
|
QDEL_NULL(soundloop) //ChompADD
|
|
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/Move(var/newloc, var/direction, var/movetime)
|
|
// VOREstation edit - Zmoving for falling
|
|
var/turf/newturf = newloc
|
|
var/zmove = (newturf && z != newturf.z)
|
|
|
|
if(!zmove && world.time < l_move_time + move_delay) //This AND the riding datum move speed limit? // VOREstation edit end
|
|
return
|
|
|
|
if(!zmove && mechanical && on && powered && cell.charge < charge_use) // VOREstation edit - zmove doesn't run this
|
|
turn_off()
|
|
return
|
|
|
|
. = ..()
|
|
|
|
if(!zmove && mechanical && on && powered) // VOREstation edit - zmove doesn't run this
|
|
cell.use(charge_use)
|
|
|
|
//Dummy loads do not have to be moved as they are just an overlay
|
|
//See load_object() proc in cargo_trains.dm for an example
|
|
//Also mobs are buckled to the vehicle and get moved in atom/movable/Move's call to take care of that
|
|
if(load && !(load in buckled_mobs) && !istype(load, /datum/vehicle_dummy_load))
|
|
load.forceMove(loc)
|
|
|
|
/obj/vehicle/attackby(obj/item/W as obj, mob/user as mob)
|
|
if(istype(W, /obj/item/hand_labeler))
|
|
return
|
|
if(mechanical)
|
|
if(W.has_tool_quality(TOOL_SCREWDRIVER))
|
|
if(!locked)
|
|
open = !open
|
|
update_icon()
|
|
to_chat(user, span_notice("Maintenance panel is now [open ? "opened" : "closed"]."))
|
|
playsound(src, W.usesound, 50, 1)
|
|
else if(W.has_tool_quality(TOOL_CROWBAR) && cell && open)
|
|
remove_cell(user)
|
|
|
|
else if(istype(W, /obj/item/cell) && !cell && open)
|
|
insert_cell(W, user)
|
|
else if(W.has_tool_quality(TOOL_WELDER))
|
|
var/obj/item/weldingtool/T = W.get_welder()
|
|
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(span_red("[user] repairs [src]!"),span_blue("You repair [src]!"))
|
|
else
|
|
to_chat(user, span_notice("Unable to repair with the maintenance panel closed."))
|
|
else
|
|
to_chat(user, span_notice("[src] does not need a repair."))
|
|
else
|
|
to_chat(user, span_notice("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)
|
|
if("fire")
|
|
health -= W.force * fire_dam_coeff
|
|
if("brute")
|
|
health -= W.force * brute_dam_coeff
|
|
..()
|
|
healthcheck()
|
|
else
|
|
..()
|
|
|
|
/obj/vehicle/bullet_act(var/obj/item/projectile/Proj)
|
|
health -= Proj.get_structure_damage()
|
|
..()
|
|
healthcheck()
|
|
|
|
/obj/vehicle/proc/adjust_health(amount)
|
|
health = between(0, health + amount, maxhealth)
|
|
healthcheck()
|
|
|
|
/obj/vehicle/ex_act(severity)
|
|
switch(severity)
|
|
if(1.0)
|
|
explode()
|
|
return
|
|
if(2.0)
|
|
health -= rand(5,10)*fire_dam_coeff
|
|
health -= rand(10,20)*brute_dam_coeff
|
|
healthcheck()
|
|
return
|
|
if(3.0)
|
|
if (prob(50))
|
|
health -= rand(1,5)*fire_dam_coeff
|
|
health -= rand(1,5)*brute_dam_coeff
|
|
healthcheck()
|
|
return
|
|
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)
|
|
pulse2.icon = 'icons/effects/effects.dmi'
|
|
pulse2.icon_state = "empdisable"
|
|
pulse2.name = "emp sparks"
|
|
pulse2.anchored = TRUE
|
|
pulse2.set_dir(pick(GLOB.cardinal))
|
|
|
|
spawn(10)
|
|
qdel(pulse2)
|
|
if(on)
|
|
turn_off()
|
|
spawn(severity*300)
|
|
stat &= ~EMPED
|
|
if(was_on)
|
|
turn_on()
|
|
|
|
/obj/vehicle/attack_ai(mob/user as mob)
|
|
return
|
|
|
|
// For downstream compatibility (in particular Paradise)
|
|
/obj/vehicle/proc/handle_rotation()
|
|
return
|
|
|
|
//-------------------------------------------
|
|
// Vehicle procs
|
|
//-------------------------------------------
|
|
/obj/vehicle/proc/turn_on()
|
|
if(!mechanical || stat)
|
|
return FALSE
|
|
if(!cell)
|
|
return FALSE
|
|
if(powered && cell.charge < charge_use)
|
|
return FALSE
|
|
if(on)
|
|
return FALSE
|
|
on = 1
|
|
playsound(src, 'sound/effects/vehicle/ignition_car.ogg', 60, 2, -2) //CHOMPedit: New sound effects.
|
|
soundloop.start()
|
|
set_light(initial(light_range))
|
|
update_icon()
|
|
return TRUE
|
|
|
|
/obj/vehicle/proc/turn_off()
|
|
if(!on)
|
|
return FALSE
|
|
if(!mechanical)
|
|
return FALSE
|
|
on = 0
|
|
playsound(src, 'sound/effects/vehicle/engine_off.ogg', 60, 2, -2) //CHOMPedit: New sound effects.
|
|
soundloop.stop()
|
|
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
|
|
to_chat(user, span_warning("You bypass [src]'s controls."))
|
|
return TRUE
|
|
|
|
/obj/vehicle/proc/explode()
|
|
src.visible_message(span_bolddanger("[src] blows apart!"), 1)
|
|
playsound(src, 'sound/effects/explosions/vehicleexplosion.ogg', 100, 8, 3) //CHOMPedit: New sound effects.
|
|
var/turf/Tsec = get_turf(src)
|
|
|
|
//stuns people who are thrown off a train that has been blown up
|
|
if(isliving(load))
|
|
var/mob/living/M = load
|
|
M.apply_effects(5, 5)
|
|
|
|
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()
|
|
if(health <= 0)
|
|
explode()
|
|
|
|
/obj/vehicle/proc/powercheck()
|
|
if(!mechanical)
|
|
return
|
|
|
|
if(!cell && !powered)
|
|
return
|
|
|
|
if(!cell && powered)
|
|
turn_off()
|
|
return
|
|
|
|
if(cell.charge < charge_use)
|
|
turn_off()
|
|
return
|
|
|
|
if(cell && powered)
|
|
turn_on()
|
|
return
|
|
|
|
/obj/vehicle/proc/insert_cell(var/obj/item/cell/C, var/mob/living/carbon/human/H)
|
|
if(!mechanical)
|
|
return
|
|
if(cell)
|
|
return
|
|
if(!istype(C))
|
|
return
|
|
|
|
H.drop_from_inventory(C)
|
|
C.forceMove(src)
|
|
cell = C
|
|
powercheck()
|
|
to_chat(H, span_notice("You install [C] in [src]."))
|
|
|
|
/obj/vehicle/proc/remove_cell(var/mob/living/carbon/human/H)
|
|
if(!mechanical)
|
|
return
|
|
if(!cell)
|
|
return
|
|
|
|
to_chat(H, span_notice("You remove [cell] from [src]."))
|
|
cell.forceMove(get_turf(H))
|
|
H.put_in_hands(cell)
|
|
cell = null
|
|
powercheck()
|
|
|
|
/obj/vehicle/proc/RunOver(var/mob/living/M)
|
|
return //write specifics for different vehicles
|
|
|
|
//-------------------------------------------
|
|
// Loading/unloading procs
|
|
//
|
|
// Set specific item restriction checks in
|
|
// the vehicle load() definition before
|
|
// calling this parent proc.
|
|
//-------------------------------------------
|
|
/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.
|
|
return 0
|
|
if(load || C.anchored)
|
|
return 0
|
|
|
|
// if a create/closet, close before loading
|
|
var/obj/structure/closet/crate = C
|
|
if(istype(crate))
|
|
crate.close()
|
|
|
|
C.forceMove(loc)
|
|
C.set_dir(dir)
|
|
C.anchored = TRUE
|
|
|
|
load = C
|
|
|
|
if(load_item_visible)
|
|
C.pixel_x += load_offset_x
|
|
if(ismob(C))
|
|
C.pixel_y += mob_offset_y
|
|
else
|
|
C.pixel_y += load_offset_y
|
|
C.layer = layer + 0.1
|
|
|
|
if(ismob(C) && user)
|
|
user_buckle_mob(C, user)
|
|
|
|
return 1
|
|
|
|
|
|
/obj/vehicle/proc/unload(var/mob/user, var/direction)
|
|
if(!load)
|
|
return
|
|
|
|
var/turf/dest = null
|
|
|
|
//find a turf to unload to
|
|
if(direction) //if direction specified, unload in that direction
|
|
dest = get_step(src, direction)
|
|
else if(user) //if a user has unloaded the vehicle, unload at their feet
|
|
dest = get_turf(user)
|
|
|
|
if(!dest)
|
|
dest = get_step_to(src, get_step(src, turn(dir, 90))) //try unloading to the side of the vehicle first if neither of the above are present
|
|
|
|
//if these all result in the same turf as the vehicle or nullspace, pick a new turf with open space
|
|
if(!dest || dest == get_turf(src))
|
|
var/list/options = new()
|
|
for(var/test_dir in GLOB.alldirs)
|
|
var/new_dir = get_step_to(src, get_step(src, test_dir))
|
|
if(new_dir && load.Adjacent(new_dir))
|
|
options += new_dir
|
|
if(options.len)
|
|
dest = pick(options)
|
|
else
|
|
dest = get_turf(src) //otherwise just dump it on the same turf as the vehicle
|
|
|
|
if(!isturf(dest)) //if there still is nowhere to unload, cancel out since the vehicle is probably in nullspace
|
|
return 0
|
|
|
|
load.forceMove(dest)
|
|
load.set_dir(get_dir(loc, dest))
|
|
load.anchored = FALSE //we can only load non-anchored items, so it makes sense to set this to false
|
|
if(ismob(load))
|
|
var/mob/L = load
|
|
L.pixel_x = L.default_pixel_x
|
|
L.pixel_y = L.default_pixel_y
|
|
else
|
|
load.pixel_x = initial(load.pixel_x)
|
|
load.pixel_y = initial(load.pixel_y)
|
|
load.layer = initial(load.layer)
|
|
|
|
if(ismob(load))
|
|
unbuckle_mob(load)
|
|
|
|
load = null
|
|
|
|
return 1
|
|
|
|
|
|
//-------------------------------------------------------
|
|
// Stat update procs
|
|
//-------------------------------------------------------
|
|
/obj/vehicle/proc/update_stats()
|
|
return
|
|
|
|
/obj/vehicle/attack_generic(var/mob/user, var/damage, var/attack_message)
|
|
if(!damage)
|
|
return
|
|
visible_message(span_danger("[user] [attack_message] the [src]!"))
|
|
user.attack_log += text("\[[time_stamp()]\] [span_red("attacked [src.name]")]")
|
|
user.do_attack_animation(src)
|
|
src.health -= damage
|
|
if(mechanical && prob(10))
|
|
new /obj/effect/decal/cleanable/blood/oil(src.loc)
|
|
spawn(1) healthcheck()
|
|
return 1
|
|
|
|
/obj/vehicle/take_damage(var/damage)
|
|
if(!damage)
|
|
return
|
|
src.health -= damage
|
|
if(mechanical && prob(10))
|
|
new /obj/effect/decal/cleanable/blood/oil(src.loc)
|
|
spawn(1) healthcheck()
|
|
return 1
|
|
|
|
//ChompADD START
|
|
//----------------------------
|
|
// Engine sounds datum
|
|
//----------------------------
|
|
|
|
/datum/looping_sound/idle_carengine
|
|
mid_sounds = 'sound/effects/vehicle/engine_loop.ogg'
|
|
mid_length = 2.60 SECONDS
|
|
chance = 100
|
|
volume = 10
|
|
exclusive = TRUE
|
|
volume_chan = VOLUME_CHANNEL_AMBIENCE
|
|
|
|
//ChompADD END
|