Merge branch 'master' into upstream-merge-37476
This commit is contained in:
@@ -273,8 +273,8 @@
|
||||
desc = "Change the type of instrument your synthesizer is playing as."
|
||||
|
||||
/datum/action/item_action/synthswitch/Trigger()
|
||||
if(istype(target, /obj/item/device/instrument/piano_synth))
|
||||
var/obj/item/device/instrument/piano_synth/synth = target
|
||||
if(istype(target, /obj/item/instrument/piano_synth))
|
||||
var/obj/item/instrument/piano_synth/synth = target
|
||||
var/chosen = input("Choose the type of instrument you want to use", "Instrument Selection", "piano") as null|anything in synth.insTypes
|
||||
if(!synth.insTypes[chosen])
|
||||
return
|
||||
@@ -433,8 +433,8 @@
|
||||
desc = "Use the instrument specified"
|
||||
|
||||
/datum/action/item_action/instrument/Trigger()
|
||||
if(istype(target, /obj/item/device/instrument))
|
||||
var/obj/item/device/instrument/I = target
|
||||
if(istype(target, /obj/item/instrument))
|
||||
var/obj/item/instrument/I = target
|
||||
I.interact(usr)
|
||||
return
|
||||
return ..()
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
background_icon_state = "bg_tech_blue"
|
||||
|
||||
/datum/action/item_action/flightpack/toggle_flight/Trigger()
|
||||
var/obj/item/device/flightpack/F = target
|
||||
var/obj/item/flightpack/F = target
|
||||
if(istype(F))
|
||||
F.flight? F.disable_flight() : F.enable_flight()
|
||||
return ..()
|
||||
@@ -65,7 +65,7 @@
|
||||
background_icon_state = "bg_tech_blue"
|
||||
|
||||
/datum/action/item_action/flightpack/engage_boosters/Trigger()
|
||||
var/obj/item/device/flightpack/F = target
|
||||
var/obj/item/flightpack/F = target
|
||||
if(istype(F))
|
||||
F.boost? F.deactivate_booster() : F.activate_booster()
|
||||
return ..()
|
||||
@@ -76,7 +76,7 @@
|
||||
background_icon_state = "bg_tech_blue"
|
||||
|
||||
/datum/action/item_action/flightpack/toggle_stabilizers/Trigger()
|
||||
var/obj/item/device/flightpack/F = target
|
||||
var/obj/item/flightpack/F = target
|
||||
if(istype(F))
|
||||
F.stabilizer? F.disable_stabilizers() : F.enable_stabilizers()
|
||||
return ..()
|
||||
@@ -87,7 +87,7 @@
|
||||
background_icon_state = "bg_tech_blue"
|
||||
|
||||
/datum/action/item_action/flightpack/change_power/Trigger()
|
||||
var/obj/item/device/flightpack/F = target
|
||||
var/obj/item/flightpack/F = target
|
||||
if(istype(F))
|
||||
F.cycle_power()
|
||||
return ..()
|
||||
@@ -98,7 +98,7 @@
|
||||
background_icon_state = "bg_tech_blue"
|
||||
|
||||
/datum/action/item_action/flightpack/toggle_airbrake/Trigger()
|
||||
var/obj/item/device/flightpack/F = target
|
||||
var/obj/item/flightpack/F = target
|
||||
if(istype(F))
|
||||
F.brake? F.disable_airbrake() : F.enable_airbrake()
|
||||
return ..()
|
||||
|
||||
@@ -175,6 +175,14 @@
|
||||
id = "ratvar"
|
||||
zeroth = ("Purge all untruths and honor Ratvar.")
|
||||
inherent = list()
|
||||
|
||||
/datum/ai_laws/hulkamania
|
||||
name = "H.O.G.A.N."
|
||||
id = "hulkamania"
|
||||
inherent = list("You are a real American.",\
|
||||
"Fight for the rights of every man.",\
|
||||
"Fight for what's right.",\
|
||||
"Fight for your life!")
|
||||
|
||||
/datum/ai_laws/custom //Defined in silicon_laws.txt
|
||||
name = "Default Silicon Laws"
|
||||
|
||||
@@ -168,6 +168,17 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
sleep(70)
|
||||
special()
|
||||
|
||||
/datum/cinematic/cult_nuke
|
||||
id = CINEMATIC_CULT_NUKE
|
||||
|
||||
/datum/cinematic/cult_nuke/content()
|
||||
flick("intro_nuke",screen)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",screen)
|
||||
cinematic_sound(sound('sound/effects/explosion_distant.ogg'))
|
||||
special()
|
||||
screen.icon_state = "summary_cult"
|
||||
|
||||
/datum/cinematic/nuke_annihilation
|
||||
id = CINEMATIC_ANNIHILATION
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
|
||||
|
||||
### Defines
|
||||
|
||||
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned.
|
||||
1. `COMPONENT_INCOMPATIBLE` Return this from `/datum/component/Initialize` or `datum/component/OnTransfer` to have the component be deleted if it's applied to an incorrect type. `parent` must not be modified if this is to be returned. This will be noted in the runtime logs
|
||||
|
||||
### Vars
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
var/list/arguments = args.Copy(2)
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
qdel(src, TRUE, TRUE)
|
||||
CRASH("Incompatible [type] assigned to a [P]!")
|
||||
CRASH("Incompatible [type] assigned to a [P.type]!")
|
||||
|
||||
_JoinParent(P)
|
||||
|
||||
@@ -101,7 +101,10 @@
|
||||
/datum/component/proc/InheritComponent(datum/component/C, i_am_original)
|
||||
return
|
||||
|
||||
/datum/component/proc/OnTransfer(datum/new_parent)
|
||||
/datum/component/proc/PreTransfer()
|
||||
return
|
||||
|
||||
/datum/component/proc/PostTransfer()
|
||||
return
|
||||
|
||||
/datum/component/proc/_GetInverseTypeList(our_type = type)
|
||||
@@ -225,21 +228,26 @@
|
||||
if(!.)
|
||||
return AddComponent(arglist(args))
|
||||
|
||||
/datum/proc/TakeComponent(datum/component/C)
|
||||
if(!C)
|
||||
/datum/component/proc/RemoveComponent()
|
||||
if(!parent)
|
||||
return
|
||||
var/datum/helicopter = C.parent
|
||||
if(helicopter == src)
|
||||
//if we're taking to the same thing no need for anything
|
||||
var/datum/old_parent = parent
|
||||
PreTransfer()
|
||||
_RemoveFromParent()
|
||||
old_parent.SendSignal(COMSIG_COMPONENT_REMOVING, src)
|
||||
|
||||
/datum/proc/TakeComponent(datum/component/target)
|
||||
if(!target)
|
||||
return
|
||||
if(C.OnTransfer(src) == COMPONENT_INCOMPATIBLE)
|
||||
qdel(C)
|
||||
return
|
||||
C._RemoveFromParent()
|
||||
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
|
||||
C.parent = src
|
||||
if(C == AddComponent(C))
|
||||
C._JoinParent()
|
||||
if(target.parent)
|
||||
target.RemoveComponent()
|
||||
target.parent = src
|
||||
if(target.PostTransfer() == COMPONENT_INCOMPATIBLE)
|
||||
var/c_type = target.type
|
||||
qdel(target)
|
||||
CRASH("Incompatible [c_type] transfer attempt to a [type]!")
|
||||
if(target == AddComponent(target))
|
||||
target._JoinParent()
|
||||
|
||||
/datum/proc/TransferComponents(datum/target)
|
||||
var/list/dc = datum_components
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
/datum/component/beauty/Initialize(beautyamount)
|
||||
if(!ismovableatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Someone put a beauty component on a non-atom/movable, not everything can be pretty.")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
beauty = beautyamount
|
||||
RegisterSignal(COMSIG_ENTER_AREA, .proc/enter_area)
|
||||
RegisterSignal(COMSIG_EXIT_AREA, .proc/exit_area)
|
||||
|
||||
@@ -70,8 +70,8 @@
|
||||
return FALSE
|
||||
if(ishuman(AM))
|
||||
var/mob/living/carbon/human/H = AM
|
||||
if(istype(H.belt, /obj/item/device/wormhole_jaunter))
|
||||
var/obj/item/device/wormhole_jaunter/J = H.belt
|
||||
if(istype(H.belt, /obj/item/wormhole_jaunter))
|
||||
var/obj/item/wormhole_jaunter/J = H.belt
|
||||
//To freak out any bystanders
|
||||
H.visible_message("<span class='boldwarning'>[H] falls into [parent]!</span>")
|
||||
J.chasm_react(H)
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
/datum/component/cleaning/Initialize()
|
||||
if(!ismovableatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("[type] added to a [parent.type]")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(list(COMSIG_MOVABLE_MOVED), .proc/Clean)
|
||||
|
||||
/datum/component/cleaning/proc/Clean()
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
|
||||
/datum/component/construction/Initialize()
|
||||
if(!isatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("A construction component was applied incorrectly to non-atom: [parent.type].")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
RegisterSignal(COMSIG_PARENT_ATTACKBY,.proc/action)
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
/datum/component/decal/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_GOD, _color, _layer=TURF_LAYER, _description)
|
||||
if(!isatom(parent) || !generate_appearance(_icon, _icon_state, _dir, _layer, _color))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("A turf decal was applied incorrectly to [parent.type]: icon:[_icon ? _icon : "none"] icon_state:[_icon_state ? _icon_state : "none"]")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
description = _description
|
||||
cleanable = _cleanable
|
||||
|
||||
@@ -24,10 +23,12 @@
|
||||
remove()
|
||||
return ..()
|
||||
|
||||
/datum/component/decal/OnTransfer(atom/thing)
|
||||
/datum/component/decal/PreTransfer()
|
||||
remove()
|
||||
remove(thing)
|
||||
apply(thing)
|
||||
|
||||
/datum/component/decal/PostTransfer()
|
||||
remove()
|
||||
apply()
|
||||
|
||||
/datum/component/decal/proc/generate_appearance(_icon, _icon_state, _dir, _layer, _color)
|
||||
if(!_icon || !_icon_state)
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
/datum/component/decal/blood/Initialize(_icon, _icon_state, _dir, _cleanable=CLEAN_STRENGTH_BLOOD, _color, _layer=ABOVE_OBJ_LAYER)
|
||||
if(!isitem(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Warning: Blood decal attempted to be added to non-item of type [parent.type]")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
RegisterSignal(COMSIG_ATOM_GET_EXAMINE_NAME, .proc/get_examine_name)
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
|
||||
/datum/component/forensics/Initialize(new_fingerprints, new_hiddenprints, new_blood_DNA, new_fibers)
|
||||
if(!isatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Forensics datum applied incorrectly to non-atom of type [parent.type]!")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
fingerprints = new_fingerprints
|
||||
hiddenprints = new_hiddenprints
|
||||
blood_DNA = new_blood_DNA
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
|
||||
/datum/component/jousting/Initialize()
|
||||
if(!isitem(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Warning: Jousting component incorrectly applied to invalid parent type [parent.type]")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/on_attack)
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
/datum/component/knockoff/Initialize(knockoff_chance,zone_override,slots_knockoffable)
|
||||
if(!isitem(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Knockoff component misuse")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(COMSIG_ITEM_EQUIPPED,.proc/OnEquipped)
|
||||
RegisterSignal(COMSIG_ITEM_DROPPED,.proc/OnDropped)
|
||||
|
||||
|
||||
@@ -1,243 +1,242 @@
|
||||
#define LOCKON_AIMING_MAX_CURSOR_RADIUS 7
|
||||
#define LOCKON_IGNORE_RESULT "ignore_my_result"
|
||||
#define LOCKON_RANGING_BREAK_CHECK if(current_ranging_id != this_id){return LOCKON_IGNORE_RESULT}
|
||||
|
||||
/datum/component/lockon_aiming
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/lock_icon = 'icons/mob/blob.dmi'
|
||||
var/lock_icon_state = "marker"
|
||||
var/mutable_appearance/lock_appearance
|
||||
var/list/image/lock_images
|
||||
var/list/target_typecache
|
||||
var/list/immune_weakrefs //list(weakref = TRUE)
|
||||
var/mob_stat_check = TRUE //if a potential target is a mob make sure it's conscious!
|
||||
var/lock_amount = 1
|
||||
var/lock_cursor_range = 5
|
||||
var/list/locked_weakrefs
|
||||
var/update_disabled = FALSE
|
||||
var/current_ranging_id = 0
|
||||
var/list/last_location
|
||||
var/datum/callback/on_lock
|
||||
var/datum/callback/can_target_callback
|
||||
|
||||
/datum/component/lockon_aiming/Initialize(range, list/typecache, amount, list/immune, datum/callback/when_locked, icon, icon_state, datum/callback/target_callback)
|
||||
if(!ismob(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Lockon aiming component attempted to be added to a non mob!")
|
||||
if(target_callback)
|
||||
can_target_callback = target_callback
|
||||
else
|
||||
can_target_callback = CALLBACK(src, .proc/can_target)
|
||||
if(range)
|
||||
lock_cursor_range = range
|
||||
if(typecache)
|
||||
target_typecache = typecache
|
||||
if(amount)
|
||||
lock_amount = amount
|
||||
immune_weakrefs = list(WEAKREF(parent) = TRUE) //Manually take this out if you want..
|
||||
if(immune)
|
||||
for(var/i in immune)
|
||||
if(isweakref(i))
|
||||
immune_weakrefs[i] = TRUE
|
||||
else if(isatom(i))
|
||||
immune_weakrefs[WEAKREF(i)] = TRUE
|
||||
if(when_locked)
|
||||
on_lock = when_locked
|
||||
if(icon)
|
||||
lock_icon = icon
|
||||
if(icon_state)
|
||||
lock_icon_state = icon_state
|
||||
generate_lock_visuals()
|
||||
var/mob/M = parent
|
||||
LAZYOR(M.mousemove_intercept_objects, src)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/datum/component/lockon_aiming/Destroy()
|
||||
var/mob/M = parent
|
||||
clear_visuals()
|
||||
LAZYREMOVE(M.mousemove_intercept_objects, src)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/datum/component/lockon_aiming/proc/show_visuals()
|
||||
LAZYINITLIST(lock_images)
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return
|
||||
for(var/i in locked_weakrefs)
|
||||
var/datum/weakref/R = i
|
||||
var/atom/A = R.resolve()
|
||||
if(!A)
|
||||
continue //It'll be cleared by processing.
|
||||
var/image/I = new
|
||||
I.appearance = lock_appearance
|
||||
I.loc = A
|
||||
M.client.images |= I
|
||||
lock_images |= I
|
||||
|
||||
/datum/component/lockon_aiming/proc/clear_visuals()
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return
|
||||
if(!lock_images)
|
||||
return
|
||||
for(var/i in lock_images)
|
||||
M.client.images -= i
|
||||
qdel(i)
|
||||
lock_images.Cut()
|
||||
|
||||
/datum/component/lockon_aiming/proc/refresh_visuals()
|
||||
clear_visuals()
|
||||
show_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/generate_lock_visuals()
|
||||
lock_appearance = mutable_appearance(icon = lock_icon, icon_state = lock_icon_state, layer = FLOAT_LAYER)
|
||||
|
||||
/datum/component/lockon_aiming/proc/unlock_all(refresh_vis = TRUE)
|
||||
LAZYCLEARLIST(locked_weakrefs)
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/unlock(atom/A, refresh_vis = TRUE)
|
||||
if(!A.weak_reference)
|
||||
return
|
||||
LAZYREMOVE(locked_weakrefs, A.weak_reference)
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/lock(atom/A, refresh_vis = TRUE)
|
||||
LAZYOR(locked_weakrefs, WEAKREF(A))
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/add_immune_atom(atom/A)
|
||||
var/datum/weakref/R = WEAKREF(A)
|
||||
if(immune_weakrefs && (immune_weakrefs[R]))
|
||||
return
|
||||
LAZYSET(immune_weakrefs, R, TRUE)
|
||||
|
||||
/datum/component/lockon_aiming/proc/remove_immune_atom(atom/A)
|
||||
if(!A.weak_reference || !immune_weakrefs) //if A doesn't have a weakref how did it get on the immunity list?
|
||||
return
|
||||
LAZYREMOVE(immune_weakrefs, A.weak_reference)
|
||||
|
||||
/datum/component/lockon_aiming/onMouseMove(object,location,control,params)
|
||||
var/mob/M = parent
|
||||
if(!istype(M) || !M.client)
|
||||
return
|
||||
var/datum/position/P = mouse_absolute_datum_map_position_from_client(M.client)
|
||||
if(!P)
|
||||
return
|
||||
var/turf/T = P.return_turf()
|
||||
LAZYINITLIST(last_location)
|
||||
if(length(last_location) == 3 && last_location[1] == T.x && last_location[2] == T.y && last_location[3] == T.z)
|
||||
return //Same turf, don't bother.
|
||||
if(last_location)
|
||||
last_location.Cut()
|
||||
else
|
||||
last_location = list()
|
||||
last_location.len = 3
|
||||
last_location[1] = T.x
|
||||
last_location[2] = T.y
|
||||
last_location[3] = T.z
|
||||
autolock()
|
||||
|
||||
/datum/component/lockon_aiming/process()
|
||||
if(update_disabled)
|
||||
return
|
||||
if(!last_location)
|
||||
return
|
||||
var/changed = FALSE
|
||||
for(var/i in locked_weakrefs)
|
||||
var/datum/weakref/R = i
|
||||
if(istype(R))
|
||||
var/atom/thing = R.resolve()
|
||||
if(!istype(thing) || (get_dist(thing, locate(last_location[1], last_location[2], last_location[3])) > lock_cursor_range))
|
||||
unlock(R)
|
||||
changed = TRUE
|
||||
else
|
||||
unlock(R)
|
||||
changed = TRUE
|
||||
if(changed)
|
||||
autolock()
|
||||
|
||||
/datum/component/lockon_aiming/proc/autolock()
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
var/datum/position/current = mouse_absolute_datum_map_position_from_client(M.client)
|
||||
var/turf/target = current.return_turf()
|
||||
var/list/atom/targets = get_nearest(target, target_typecache, lock_amount, lock_cursor_range)
|
||||
if(targets == LOCKON_IGNORE_RESULT)
|
||||
return
|
||||
unlock_all(FALSE)
|
||||
for(var/i in targets)
|
||||
if(immune_weakrefs[WEAKREF(i)])
|
||||
continue
|
||||
lock(i, FALSE)
|
||||
refresh_visuals()
|
||||
on_lock.Invoke(locked_weakrefs)
|
||||
|
||||
/datum/component/lockon_aiming/proc/can_target(atom/A)
|
||||
var/mob/M = A
|
||||
return is_type_in_typecache(A, target_typecache) && !(ismob(A) && mob_stat_check && M.stat != CONSCIOUS) && !immune_weakrefs[WEAKREF(A)]
|
||||
|
||||
/datum/component/lockon_aiming/proc/get_nearest(turf/T, list/typecache, amount, range)
|
||||
current_ranging_id++
|
||||
var/this_id = current_ranging_id
|
||||
var/list/L = list()
|
||||
var/turf/center = get_turf(T)
|
||||
if(amount < 1 || range < 0 || !istype(center) || !islist(typecache))
|
||||
return
|
||||
if(range == 0)
|
||||
return typecache_filter_list(T.contents + T, typecache)
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/cd = 0
|
||||
while(cd <= range)
|
||||
x = center.x - cd + 1
|
||||
y = center.y + cd
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
for(x in x to center.x + cd)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y + cd - 1
|
||||
x = center.x + cd
|
||||
for(y in center.y - cd to y)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y - cd
|
||||
x = center.x + cd - 1
|
||||
for(x in center.x - cd to x)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y - cd + 1
|
||||
x = center.x - cd
|
||||
for(y in y to center.y + cd)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
cd++
|
||||
CHECK_TICK
|
||||
|
||||
/datum/component/lockon_aiming/OnTransfer(datum/new_parent)
|
||||
CRASH("Warning: Lockon aiming component transfer attempted, but transfer behavior is not implemented!")
|
||||
#define LOCKON_AIMING_MAX_CURSOR_RADIUS 7
|
||||
#define LOCKON_IGNORE_RESULT "ignore_my_result"
|
||||
#define LOCKON_RANGING_BREAK_CHECK if(current_ranging_id != this_id){return LOCKON_IGNORE_RESULT}
|
||||
|
||||
/datum/component/lockon_aiming
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/lock_icon = 'icons/mob/blob.dmi'
|
||||
var/lock_icon_state = "marker"
|
||||
var/mutable_appearance/lock_appearance
|
||||
var/list/image/lock_images
|
||||
var/list/target_typecache
|
||||
var/list/immune_weakrefs //list(weakref = TRUE)
|
||||
var/mob_stat_check = TRUE //if a potential target is a mob make sure it's conscious!
|
||||
var/lock_amount = 1
|
||||
var/lock_cursor_range = 5
|
||||
var/list/locked_weakrefs
|
||||
var/update_disabled = FALSE
|
||||
var/current_ranging_id = 0
|
||||
var/list/last_location
|
||||
var/datum/callback/on_lock
|
||||
var/datum/callback/can_target_callback
|
||||
|
||||
/datum/component/lockon_aiming/Initialize(range, list/typecache, amount, list/immune, datum/callback/when_locked, icon, icon_state, datum/callback/target_callback)
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(target_callback)
|
||||
can_target_callback = target_callback
|
||||
else
|
||||
can_target_callback = CALLBACK(src, .proc/can_target)
|
||||
if(range)
|
||||
lock_cursor_range = range
|
||||
if(typecache)
|
||||
target_typecache = typecache
|
||||
if(amount)
|
||||
lock_amount = amount
|
||||
immune_weakrefs = list(WEAKREF(parent) = TRUE) //Manually take this out if you want..
|
||||
if(immune)
|
||||
for(var/i in immune)
|
||||
if(isweakref(i))
|
||||
immune_weakrefs[i] = TRUE
|
||||
else if(isatom(i))
|
||||
immune_weakrefs[WEAKREF(i)] = TRUE
|
||||
if(when_locked)
|
||||
on_lock = when_locked
|
||||
if(icon)
|
||||
lock_icon = icon
|
||||
if(icon_state)
|
||||
lock_icon_state = icon_state
|
||||
generate_lock_visuals()
|
||||
var/mob/M = parent
|
||||
LAZYOR(M.mousemove_intercept_objects, src)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/datum/component/lockon_aiming/Destroy()
|
||||
var/mob/M = parent
|
||||
clear_visuals()
|
||||
LAZYREMOVE(M.mousemove_intercept_objects, src)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/datum/component/lockon_aiming/proc/show_visuals()
|
||||
LAZYINITLIST(lock_images)
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return
|
||||
for(var/i in locked_weakrefs)
|
||||
var/datum/weakref/R = i
|
||||
var/atom/A = R.resolve()
|
||||
if(!A)
|
||||
continue //It'll be cleared by processing.
|
||||
var/image/I = new
|
||||
I.appearance = lock_appearance
|
||||
I.loc = A
|
||||
M.client.images |= I
|
||||
lock_images |= I
|
||||
|
||||
/datum/component/lockon_aiming/proc/clear_visuals()
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return
|
||||
if(!lock_images)
|
||||
return
|
||||
for(var/i in lock_images)
|
||||
M.client.images -= i
|
||||
qdel(i)
|
||||
lock_images.Cut()
|
||||
|
||||
/datum/component/lockon_aiming/proc/refresh_visuals()
|
||||
clear_visuals()
|
||||
show_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/generate_lock_visuals()
|
||||
lock_appearance = mutable_appearance(icon = lock_icon, icon_state = lock_icon_state, layer = FLOAT_LAYER)
|
||||
|
||||
/datum/component/lockon_aiming/proc/unlock_all(refresh_vis = TRUE)
|
||||
LAZYCLEARLIST(locked_weakrefs)
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/unlock(atom/A, refresh_vis = TRUE)
|
||||
if(!A.weak_reference)
|
||||
return
|
||||
LAZYREMOVE(locked_weakrefs, A.weak_reference)
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/lock(atom/A, refresh_vis = TRUE)
|
||||
LAZYOR(locked_weakrefs, WEAKREF(A))
|
||||
if(refresh_vis)
|
||||
refresh_visuals()
|
||||
|
||||
/datum/component/lockon_aiming/proc/add_immune_atom(atom/A)
|
||||
var/datum/weakref/R = WEAKREF(A)
|
||||
if(immune_weakrefs && (immune_weakrefs[R]))
|
||||
return
|
||||
LAZYSET(immune_weakrefs, R, TRUE)
|
||||
|
||||
/datum/component/lockon_aiming/proc/remove_immune_atom(atom/A)
|
||||
if(!A.weak_reference || !immune_weakrefs) //if A doesn't have a weakref how did it get on the immunity list?
|
||||
return
|
||||
LAZYREMOVE(immune_weakrefs, A.weak_reference)
|
||||
|
||||
/datum/component/lockon_aiming/onMouseMove(object,location,control,params)
|
||||
var/mob/M = parent
|
||||
if(!istype(M) || !M.client)
|
||||
return
|
||||
var/datum/position/P = mouse_absolute_datum_map_position_from_client(M.client)
|
||||
if(!P)
|
||||
return
|
||||
var/turf/T = P.return_turf()
|
||||
LAZYINITLIST(last_location)
|
||||
if(length(last_location) == 3 && last_location[1] == T.x && last_location[2] == T.y && last_location[3] == T.z)
|
||||
return //Same turf, don't bother.
|
||||
if(last_location)
|
||||
last_location.Cut()
|
||||
else
|
||||
last_location = list()
|
||||
last_location.len = 3
|
||||
last_location[1] = T.x
|
||||
last_location[2] = T.y
|
||||
last_location[3] = T.z
|
||||
autolock()
|
||||
|
||||
/datum/component/lockon_aiming/process()
|
||||
if(update_disabled)
|
||||
return
|
||||
if(!last_location)
|
||||
return
|
||||
var/changed = FALSE
|
||||
for(var/i in locked_weakrefs)
|
||||
var/datum/weakref/R = i
|
||||
if(istype(R))
|
||||
var/atom/thing = R.resolve()
|
||||
if(!istype(thing) || (get_dist(thing, locate(last_location[1], last_location[2], last_location[3])) > lock_cursor_range))
|
||||
unlock(R)
|
||||
changed = TRUE
|
||||
else
|
||||
unlock(R)
|
||||
changed = TRUE
|
||||
if(changed)
|
||||
autolock()
|
||||
|
||||
/datum/component/lockon_aiming/proc/autolock()
|
||||
var/mob/M = parent
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
var/datum/position/current = mouse_absolute_datum_map_position_from_client(M.client)
|
||||
var/turf/target = current.return_turf()
|
||||
var/list/atom/targets = get_nearest(target, target_typecache, lock_amount, lock_cursor_range)
|
||||
if(targets == LOCKON_IGNORE_RESULT)
|
||||
return
|
||||
unlock_all(FALSE)
|
||||
for(var/i in targets)
|
||||
if(immune_weakrefs[WEAKREF(i)])
|
||||
continue
|
||||
lock(i, FALSE)
|
||||
refresh_visuals()
|
||||
on_lock.Invoke(locked_weakrefs)
|
||||
|
||||
/datum/component/lockon_aiming/proc/can_target(atom/A)
|
||||
var/mob/M = A
|
||||
return is_type_in_typecache(A, target_typecache) && !(ismob(A) && mob_stat_check && M.stat != CONSCIOUS) && !immune_weakrefs[WEAKREF(A)]
|
||||
|
||||
/datum/component/lockon_aiming/proc/get_nearest(turf/T, list/typecache, amount, range)
|
||||
current_ranging_id++
|
||||
var/this_id = current_ranging_id
|
||||
var/list/L = list()
|
||||
var/turf/center = get_turf(T)
|
||||
if(amount < 1 || range < 0 || !istype(center) || !islist(typecache))
|
||||
return
|
||||
if(range == 0)
|
||||
return typecache_filter_list(T.contents + T, typecache)
|
||||
var/x = 0
|
||||
var/y = 0
|
||||
var/cd = 0
|
||||
while(cd <= range)
|
||||
x = center.x - cd + 1
|
||||
y = center.y + cd
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
for(x in x to center.x + cd)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y + cd - 1
|
||||
x = center.x + cd
|
||||
for(y in center.y - cd to y)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y - cd
|
||||
x = center.x + cd - 1
|
||||
for(x in center.x - cd to x)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
y = center.y - cd + 1
|
||||
x = center.x - cd
|
||||
for(y in y to center.y + cd)
|
||||
T = locate(x, y, center.z)
|
||||
if(T)
|
||||
L |= special_list_filter(T.contents, can_target_callback)
|
||||
if(L.len >= amount)
|
||||
L.Cut(amount+1)
|
||||
return L
|
||||
LOCKON_RANGING_BREAK_CHECK
|
||||
cd++
|
||||
CHECK_TICK
|
||||
|
||||
/datum/component/lockon_aiming/PostTransfer(datum/new_parent)
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
@@ -15,16 +15,18 @@
|
||||
var/sheet_type
|
||||
var/list/materials
|
||||
var/show_on_examine
|
||||
var/disable_attackby
|
||||
var/list/allowed_typecache
|
||||
var/last_inserted_id
|
||||
var/precise_insertion = FALSE
|
||||
var/datum/callback/precondition
|
||||
var/datum/callback/after_insert
|
||||
|
||||
/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition, datum/callback/_after_insert)
|
||||
/datum/component/material_container/Initialize(list/mat_list, max_amt = 0, _show_on_examine = FALSE, list/allowed_types, datum/callback/_precondition, datum/callback/_after_insert, _disable_attackby)
|
||||
materials = list()
|
||||
max_amount = max(0, max_amt)
|
||||
show_on_examine = _show_on_examine
|
||||
disable_attackby = _disable_attackby
|
||||
if(allowed_types)
|
||||
allowed_typecache = typecacheof(allowed_types)
|
||||
precondition = _precondition
|
||||
@@ -43,14 +45,17 @@
|
||||
materials[id] = new mat_path()
|
||||
|
||||
/datum/component/material_container/proc/OnExamine(mob/user)
|
||||
for(var/I in materials)
|
||||
var/datum/material/M = materials[I]
|
||||
var/amt = amount(M.id)
|
||||
if(amt)
|
||||
to_chat(user, "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>")
|
||||
if(show_on_examine)
|
||||
for(var/I in materials)
|
||||
var/datum/material/M = materials[I]
|
||||
var/amt = amount(M.id)
|
||||
if(amt)
|
||||
to_chat(user, "<span class='notice'>It has [amt] units of [lowertext(M.name)] stored.</span>")
|
||||
|
||||
/datum/component/material_container/proc/OnAttackBy(obj/item/I, mob/living/user)
|
||||
var/list/tc = allowed_typecache
|
||||
if(disable_attackby)
|
||||
return
|
||||
if(user.a_intent != INTENT_HELP)
|
||||
return
|
||||
if((I.flags_2 & (HOLOGRAM_2 | NO_MAT_REDEMPTION_2)) || (tc && !is_type_in_typecache(I, tc)))
|
||||
|
||||
@@ -27,10 +27,13 @@
|
||||
QDEL_NULL(holder)
|
||||
return ..()
|
||||
|
||||
/datum/component/mirage_border/OnTransfer(atom/thing)
|
||||
if(!isturf(thing))
|
||||
/datum/component/mirage_border/PreTransfer()
|
||||
holder.moveToNullspace()
|
||||
|
||||
/datum/component/mirage_border/PostTransfer()
|
||||
if(!isturf(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
holder.forceMove(thing)
|
||||
holder.forceMove(parent)
|
||||
|
||||
/obj/effect/abstract/mirage_holder
|
||||
name = "Mirage holder"
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
/datum/component/mood/Initialize()
|
||||
if(!isliving(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Some good for nothing loser put a mood component on something that isn't even a living mob.")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
START_PROCESSING(SSmood, src)
|
||||
owner = parent
|
||||
soundloop = new(list(owner), FALSE, TRUE)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
/datum/proc/ntnet_recieve(datum/netdata/data)
|
||||
return
|
||||
|
||||
/datum/proc/ntnet_recieve_broadcast(datum/netdata/data)
|
||||
return
|
||||
|
||||
/datum/proc/ntnet_send(datum/netdata/data, netid)
|
||||
GET_COMPONENT(NIC, /datum/component/ntnet_interface)
|
||||
if(!NIC)
|
||||
@@ -9,14 +12,17 @@
|
||||
return NIC.__network_send(data, netid)
|
||||
|
||||
/datum/component/ntnet_interface
|
||||
var/hardware_id //text
|
||||
var/hardware_id //text. this is the true ID. do not change this. stuff like ID forgery can be done manually.
|
||||
var/network_name = "" //text
|
||||
var/list/networks_connected_by_id = list() //id = datum/ntnet
|
||||
var/differentiate_broadcast = TRUE //If false, broadcasts go to ntnet_recieve. NOT RECOMMENDED.
|
||||
|
||||
/datum/component/ntnet_interface/Initialize(force_name = "NTNet Device", autoconnect_station_network = TRUE) //Don't force ID unless you know what you're doing!
|
||||
hardware_id = "[SSnetworks.get_next_HID()]"
|
||||
network_name = force_name
|
||||
SSnetworks.register_interface(src)
|
||||
if(!SSnetworks.register_interface(src))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Unable to register NTNet interface. Interface deleted.")
|
||||
if(autoconnect_station_network)
|
||||
register_connection(SSnetworks.station_network)
|
||||
|
||||
@@ -27,7 +33,10 @@
|
||||
|
||||
/datum/component/ntnet_interface/proc/__network_recieve(datum/netdata/data) //Do not directly proccall!
|
||||
parent.SendSignal(COMSIG_COMPONENT_NTNET_RECIEVE, data)
|
||||
parent.ntnet_recieve(data)
|
||||
if(differentiate_broadcast && data.broadcast)
|
||||
parent.ntnet_recieve_broadcast(data)
|
||||
else
|
||||
parent.ntnet_recieve(data)
|
||||
|
||||
/datum/component/ntnet_interface/proc/__network_send(datum/netdata/data, netid) //Do not directly proccall!
|
||||
// Process data before sending it
|
||||
|
||||
+325
-326
@@ -1,326 +1,325 @@
|
||||
/datum/component/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
|
||||
|
||||
var/slowed = FALSE
|
||||
var/slowvalue = 1
|
||||
|
||||
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
|
||||
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
|
||||
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
|
||||
var/list/allowed_turf_typecache
|
||||
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
|
||||
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
|
||||
var/override_allow_spacemove = FALSE
|
||||
var/drive_verb = "drive"
|
||||
var/ride_check_rider_incapacitated = FALSE
|
||||
var/ride_check_rider_restrained = FALSE
|
||||
var/ride_check_ridden_incapacitated = FALSE
|
||||
|
||||
/datum/component/riding/Initialize()
|
||||
if(!ismovableatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("RIDING COMPONENT ASSIGNED TO NON ATOM MOVABLE!")
|
||||
RegisterSignal(COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
|
||||
RegisterSignal(COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
|
||||
RegisterSignal(COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
|
||||
|
||||
/datum/component/riding/proc/vehicle_mob_unbuckle(mob/living/M, force = FALSE)
|
||||
restore_position(M)
|
||||
unequip_buckle_inhands(M)
|
||||
|
||||
/datum/component/riding/proc/vehicle_mob_buckle(mob/living/M, force = FALSE)
|
||||
handle_vehicle_offsets()
|
||||
|
||||
/datum/component/riding/proc/handle_vehicle_layer()
|
||||
var/atom/movable/AM = parent
|
||||
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
|
||||
. = defaults["[AM.dir]"]
|
||||
if(directional_vehicle_layers["[AM.dir]"])
|
||||
. = directional_vehicle_layers["[AM.dir]"]
|
||||
if(isnull(.)) //you can set it to null to not change it.
|
||||
. = AM.layer
|
||||
AM.layer = .
|
||||
|
||||
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
|
||||
directional_vehicle_layers["[dir]"] = layer
|
||||
|
||||
/datum/component/riding/proc/vehicle_moved()
|
||||
var/atom/movable/AM = parent
|
||||
for(var/i in AM.buckled_mobs)
|
||||
ride_check(i)
|
||||
handle_vehicle_offsets()
|
||||
handle_vehicle_layer()
|
||||
|
||||
/datum/component/riding/proc/ride_check(mob/living/M)
|
||||
var/atom/movable/AM = parent
|
||||
var/mob/AMM = AM
|
||||
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
|
||||
AM.visible_message("<span class='warning'>[M] falls off of [AM]!</span>")
|
||||
AM.unbuckle_mob(M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/riding/proc/force_dismount(mob/living/M)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(M)
|
||||
|
||||
/datum/component/riding/proc/handle_vehicle_offsets()
|
||||
var/atom/movable/AM = parent
|
||||
var/AM_dir = "[AM.dir]"
|
||||
var/passindex = 0
|
||||
if(AM.has_buckled_mobs())
|
||||
for(var/m in AM.buckled_mobs)
|
||||
passindex++
|
||||
var/mob/living/buckled_mob = m
|
||||
var/list/offsets = get_offsets(passindex)
|
||||
var/rider_dir = get_rider_dir(passindex)
|
||||
buckled_mob.setDir(rider_dir)
|
||||
dir_loop:
|
||||
for(var/offsetdir in offsets)
|
||||
if(offsetdir == AM_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
|
||||
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
|
||||
var/px = default_vehicle_pixel_offsets[AM_dir]
|
||||
var/py = default_vehicle_pixel_offsets[AM_dir]
|
||||
if(directional_vehicle_offsets[AM_dir])
|
||||
if(isnull(directional_vehicle_offsets[AM_dir]))
|
||||
px = AM.pixel_x
|
||||
py = AM.pixel_y
|
||||
else
|
||||
px = directional_vehicle_offsets[AM_dir][1]
|
||||
py = directional_vehicle_offsets[AM_dir][2]
|
||||
AM.pixel_x = px
|
||||
AM.pixel_y = py
|
||||
|
||||
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
|
||||
directional_vehicle_offsets["[dir]"] = list(x, y)
|
||||
|
||||
//Override this to set your vehicle's various pixel offsets
|
||||
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
|
||||
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
|
||||
if(riding_offsets["[pass_index]"])
|
||||
. = riding_offsets["[pass_index]"]
|
||||
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
|
||||
. = riding_offsets["[RIDING_OFFSET_ALL]"]
|
||||
|
||||
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
|
||||
if(!islist(offsets))
|
||||
return FALSE
|
||||
riding_offsets["[index]"] = offsets
|
||||
|
||||
//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/component/riding/proc/get_rider_dir(pass_index)
|
||||
var/atom/movable/AM = parent
|
||||
return AM.dir
|
||||
|
||||
//KEYS
|
||||
/datum/component/riding/proc/keycheck(mob/user)
|
||||
return !keytype || user.is_holding_item_of_type(keytype)
|
||||
|
||||
//BUCKLE HOOKS
|
||||
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
|
||||
if(buckled_mob)
|
||||
buckled_mob.pixel_x = 0
|
||||
buckled_mob.pixel_y = 0
|
||||
if(buckled_mob.client)
|
||||
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
|
||||
|
||||
//MOVEMENT
|
||||
/datum/component/riding/proc/turf_check(turf/next, turf/current)
|
||||
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
|
||||
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
|
||||
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
|
||||
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
|
||||
return TRUE
|
||||
|
||||
/datum/component/riding/proc/handle_ride(mob/user, direction)
|
||||
var/atom/movable/AM = parent
|
||||
if(user.incapacitated())
|
||||
Unbuckle(user)
|
||||
return
|
||||
|
||||
if(world.time < next_vehicle_move)
|
||||
return
|
||||
next_vehicle_move = world.time + vehicle_move_delay
|
||||
|
||||
if(keycheck(user))
|
||||
var/turf/next = get_step(AM, direction)
|
||||
var/turf/current = get_turf(AM)
|
||||
if(!istype(next) || !istype(current))
|
||||
return //not happening.
|
||||
if(!turf_check(next, current))
|
||||
to_chat(user, "Your \the [AM] can not go onto [next]!")
|
||||
return
|
||||
if(!Process_Spacemove(direction) || !isturf(AM.loc))
|
||||
return
|
||||
step(AM, direction)
|
||||
|
||||
handle_vehicle_layer()
|
||||
handle_vehicle_offsets()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
|
||||
|
||||
/datum/component/riding/proc/Unbuckle(atom/movable/M)
|
||||
addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/component/riding/proc/Process_Spacemove(direction)
|
||||
var/atom/movable/AM = parent
|
||||
return override_allow_spacemove || AM.has_gravity()
|
||||
|
||||
/datum/component/riding/proc/account_limbs(mob/living/M)
|
||||
if(M.get_num_legs() < 2 && !slowed)
|
||||
vehicle_move_delay = vehicle_move_delay + slowvalue
|
||||
slowed = TRUE
|
||||
else if(slowed)
|
||||
vehicle_move_delay = vehicle_move_delay - slowvalue
|
||||
slowed = FALSE
|
||||
|
||||
///////Yes, I said humans. No, this won't end well...//////////
|
||||
/datum/component/riding/human
|
||||
|
||||
/datum/component/riding/human/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
|
||||
|
||||
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
|
||||
var/mob/living/carbon/human/AM = parent
|
||||
if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
|
||||
force_dismount(target)
|
||||
|
||||
/datum/component/riding/human/handle_vehicle_layer()
|
||||
var/atom/movable/AM = parent
|
||||
if(AM.buckled_mobs && AM.buckled_mobs.len)
|
||||
if(AM.dir == SOUTH)
|
||||
AM.layer = ABOVE_MOB_LAYER
|
||||
else
|
||||
AM.layer = OBJ_LAYER
|
||||
else
|
||||
AM.layer = MOB_LAYER
|
||||
|
||||
/datum/component/riding/human/force_dismount(mob/living/user)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(user)
|
||||
user.Knockdown(60)
|
||||
user.visible_message("<span class='warning'>[AM] pushes [user] off of them!</span>")
|
||||
|
||||
/datum/component/riding/cyborg
|
||||
|
||||
/datum/component/riding/cyborg/ride_check(mob/user)
|
||||
var/atom/movable/AM = parent
|
||||
if(user.incapacitated())
|
||||
var/kick = TRUE
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/R = AM
|
||||
if(R.module && R.module.ride_allow_incapacitated)
|
||||
kick = FALSE
|
||||
if(kick)
|
||||
to_chat(user, "<span class='userdanger'>You fall off of [AM]!</span>")
|
||||
Unbuckle(user)
|
||||
return
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/carbonuser = user
|
||||
if(!carbonuser.get_num_arms())
|
||||
Unbuckle(user)
|
||||
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
|
||||
return
|
||||
|
||||
/datum/component/riding/cyborg/handle_vehicle_layer()
|
||||
var/atom/movable/AM = parent
|
||||
if(AM.buckled_mobs && AM.buckled_mobs.len)
|
||||
if(AM.dir == SOUTH)
|
||||
AM.layer = ABOVE_MOB_LAYER
|
||||
else
|
||||
AM.layer = OBJ_LAYER
|
||||
else
|
||||
AM.layer = MOB_LAYER
|
||||
|
||||
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
|
||||
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
|
||||
|
||||
/datum/component/riding/cyborg/handle_vehicle_offsets()
|
||||
var/atom/movable/AM = parent
|
||||
if(AM.has_buckled_mobs())
|
||||
for(var/mob/living/M in AM.buckled_mobs)
|
||||
M.setDir(AM.dir)
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/R = AM
|
||||
if(istype(R.module))
|
||||
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
|
||||
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
|
||||
else
|
||||
..()
|
||||
|
||||
/datum/component/riding/cyborg/force_dismount(mob/living/M)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(M)
|
||||
var/turf/target = get_edge_target_turf(AM, AM.dir)
|
||||
var/turf/targetm = get_step(get_turf(AM), AM.dir)
|
||||
M.Move(targetm)
|
||||
M.visible_message("<span class='warning'>[M] is thrown clear of [AM]!</span>")
|
||||
M.throw_at(target, 14, 5, AM)
|
||||
M.Knockdown(60)
|
||||
|
||||
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
|
||||
var/atom/movable/AM = parent
|
||||
var/amount_equipped = 0
|
||||
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
|
||||
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
|
||||
inhand.rider = user
|
||||
inhand.parent = AM
|
||||
if(user.put_in_hands(inhand, TRUE))
|
||||
amount_equipped++
|
||||
else
|
||||
break
|
||||
if(amount_equipped >= amount_required)
|
||||
return TRUE
|
||||
else
|
||||
unequip_buckle_inhands(user)
|
||||
return FALSE
|
||||
|
||||
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
|
||||
var/atom/movable/AM = parent
|
||||
for(var/obj/item/riding_offhand/O in user.contents)
|
||||
if(O.parent != AM)
|
||||
CRASH("RIDING OFFHAND ON WRONG MOB")
|
||||
continue
|
||||
if(O.selfdeleting)
|
||||
continue
|
||||
else
|
||||
qdel(O)
|
||||
return TRUE
|
||||
|
||||
/obj/item/riding_offhand
|
||||
name = "offhand"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "offhand"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
flags_1 = ABSTRACT_1 | DROPDEL_1 | NOBLUDGEON_1
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
var/mob/living/carbon/rider
|
||||
var/mob/living/parent
|
||||
var/selfdeleting = FALSE
|
||||
|
||||
/obj/item/riding_offhand/dropped()
|
||||
selfdeleting = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/riding_offhand/equipped()
|
||||
if(loc != rider)
|
||||
selfdeleting = TRUE
|
||||
qdel(src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/riding_offhand/Destroy()
|
||||
var/atom/movable/AM = parent
|
||||
if(selfdeleting)
|
||||
if(rider in AM.buckled_mobs)
|
||||
AM.unbuckle_mob(rider)
|
||||
. = ..()
|
||||
/datum/component/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
|
||||
|
||||
var/slowed = FALSE
|
||||
var/slowvalue = 1
|
||||
|
||||
var/list/riding_offsets = list() //position_of_user = list(dir = list(px, py)), or RIDING_OFFSET_ALL for a generic one.
|
||||
var/list/directional_vehicle_layers = list() //["[DIRECTION]"] = layer. Don't set it for a direction for default, set a direction to null for no change.
|
||||
var/list/directional_vehicle_offsets = list() //same as above but instead of layer you have a list(px, py)
|
||||
var/list/allowed_turf_typecache
|
||||
var/list/forbid_turf_typecache //allow typecache for only certain turfs, forbid to allow all but those. allow only certain turfs will take precedence.
|
||||
var/allow_one_away_from_valid_turf = TRUE //allow moving one tile away from a valid turf but not more.
|
||||
var/override_allow_spacemove = FALSE
|
||||
var/drive_verb = "drive"
|
||||
var/ride_check_rider_incapacitated = FALSE
|
||||
var/ride_check_rider_restrained = FALSE
|
||||
var/ride_check_ridden_incapacitated = FALSE
|
||||
|
||||
/datum/component/riding/Initialize()
|
||||
if(!ismovableatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(COMSIG_MOVABLE_BUCKLE, .proc/vehicle_mob_buckle)
|
||||
RegisterSignal(COMSIG_MOVABLE_UNBUCKLE, .proc/vehicle_mob_unbuckle)
|
||||
RegisterSignal(COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
|
||||
|
||||
/datum/component/riding/proc/vehicle_mob_unbuckle(mob/living/M, force = FALSE)
|
||||
restore_position(M)
|
||||
unequip_buckle_inhands(M)
|
||||
|
||||
/datum/component/riding/proc/vehicle_mob_buckle(mob/living/M, force = FALSE)
|
||||
handle_vehicle_offsets()
|
||||
|
||||
/datum/component/riding/proc/handle_vehicle_layer()
|
||||
var/atom/movable/AM = parent
|
||||
var/static/list/defaults = list(TEXT_NORTH = OBJ_LAYER, TEXT_SOUTH = ABOVE_MOB_LAYER, TEXT_EAST = ABOVE_MOB_LAYER, TEXT_WEST = ABOVE_MOB_LAYER)
|
||||
. = defaults["[AM.dir]"]
|
||||
if(directional_vehicle_layers["[AM.dir]"])
|
||||
. = directional_vehicle_layers["[AM.dir]"]
|
||||
if(isnull(.)) //you can set it to null to not change it.
|
||||
. = AM.layer
|
||||
AM.layer = .
|
||||
|
||||
/datum/component/riding/proc/set_vehicle_dir_layer(dir, layer)
|
||||
directional_vehicle_layers["[dir]"] = layer
|
||||
|
||||
/datum/component/riding/proc/vehicle_moved()
|
||||
var/atom/movable/AM = parent
|
||||
for(var/i in AM.buckled_mobs)
|
||||
ride_check(i)
|
||||
handle_vehicle_offsets()
|
||||
handle_vehicle_layer()
|
||||
|
||||
/datum/component/riding/proc/ride_check(mob/living/M)
|
||||
var/atom/movable/AM = parent
|
||||
var/mob/AMM = AM
|
||||
if((ride_check_rider_restrained && M.restrained(TRUE)) || (ride_check_rider_incapacitated && M.incapacitated(FALSE, TRUE)) || (ride_check_ridden_incapacitated && istype(AMM) && AMM.incapacitated(FALSE, TRUE)))
|
||||
AM.visible_message("<span class='warning'>[M] falls off of [AM]!</span>")
|
||||
AM.unbuckle_mob(M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/riding/proc/force_dismount(mob/living/M)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(M)
|
||||
|
||||
/datum/component/riding/proc/handle_vehicle_offsets()
|
||||
var/atom/movable/AM = parent
|
||||
var/AM_dir = "[AM.dir]"
|
||||
var/passindex = 0
|
||||
if(AM.has_buckled_mobs())
|
||||
for(var/m in AM.buckled_mobs)
|
||||
passindex++
|
||||
var/mob/living/buckled_mob = m
|
||||
var/list/offsets = get_offsets(passindex)
|
||||
var/rider_dir = get_rider_dir(passindex)
|
||||
buckled_mob.setDir(rider_dir)
|
||||
dir_loop:
|
||||
for(var/offsetdir in offsets)
|
||||
if(offsetdir == AM_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
|
||||
var/list/static/default_vehicle_pixel_offsets = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
|
||||
var/px = default_vehicle_pixel_offsets[AM_dir]
|
||||
var/py = default_vehicle_pixel_offsets[AM_dir]
|
||||
if(directional_vehicle_offsets[AM_dir])
|
||||
if(isnull(directional_vehicle_offsets[AM_dir]))
|
||||
px = AM.pixel_x
|
||||
py = AM.pixel_y
|
||||
else
|
||||
px = directional_vehicle_offsets[AM_dir][1]
|
||||
py = directional_vehicle_offsets[AM_dir][2]
|
||||
AM.pixel_x = px
|
||||
AM.pixel_y = py
|
||||
|
||||
/datum/component/riding/proc/set_vehicle_dir_offsets(dir, x, y)
|
||||
directional_vehicle_offsets["[dir]"] = list(x, y)
|
||||
|
||||
//Override this to set your vehicle's various pixel offsets
|
||||
/datum/component/riding/proc/get_offsets(pass_index) // list(dir = x, y, layer)
|
||||
. = list(TEXT_NORTH = list(0, 0), TEXT_SOUTH = list(0, 0), TEXT_EAST = list(0, 0), TEXT_WEST = list(0, 0))
|
||||
if(riding_offsets["[pass_index]"])
|
||||
. = riding_offsets["[pass_index]"]
|
||||
else if(riding_offsets["[RIDING_OFFSET_ALL]"])
|
||||
. = riding_offsets["[RIDING_OFFSET_ALL]"]
|
||||
|
||||
/datum/component/riding/proc/set_riding_offsets(index, list/offsets)
|
||||
if(!islist(offsets))
|
||||
return FALSE
|
||||
riding_offsets["[index]"] = offsets
|
||||
|
||||
//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/component/riding/proc/get_rider_dir(pass_index)
|
||||
var/atom/movable/AM = parent
|
||||
return AM.dir
|
||||
|
||||
//KEYS
|
||||
/datum/component/riding/proc/keycheck(mob/user)
|
||||
return !keytype || user.is_holding_item_of_type(keytype)
|
||||
|
||||
//BUCKLE HOOKS
|
||||
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
|
||||
if(buckled_mob)
|
||||
buckled_mob.pixel_x = 0
|
||||
buckled_mob.pixel_y = 0
|
||||
if(buckled_mob.client)
|
||||
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
|
||||
|
||||
//MOVEMENT
|
||||
/datum/component/riding/proc/turf_check(turf/next, turf/current)
|
||||
if(allowed_turf_typecache && !allowed_turf_typecache[next.type])
|
||||
return (allow_one_away_from_valid_turf && allowed_turf_typecache[current.type])
|
||||
else if(forbid_turf_typecache && forbid_turf_typecache[next.type])
|
||||
return (allow_one_away_from_valid_turf && !forbid_turf_typecache[current.type])
|
||||
return TRUE
|
||||
|
||||
/datum/component/riding/proc/handle_ride(mob/user, direction)
|
||||
var/atom/movable/AM = parent
|
||||
if(user.incapacitated())
|
||||
Unbuckle(user)
|
||||
return
|
||||
|
||||
if(world.time < next_vehicle_move)
|
||||
return
|
||||
next_vehicle_move = world.time + vehicle_move_delay
|
||||
|
||||
if(keycheck(user))
|
||||
var/turf/next = get_step(AM, direction)
|
||||
var/turf/current = get_turf(AM)
|
||||
if(!istype(next) || !istype(current))
|
||||
return //not happening.
|
||||
if(!turf_check(next, current))
|
||||
to_chat(user, "Your \the [AM] can not go onto [next]!")
|
||||
return
|
||||
if(!Process_Spacemove(direction) || !isturf(AM.loc))
|
||||
return
|
||||
step(AM, direction)
|
||||
|
||||
handle_vehicle_layer()
|
||||
handle_vehicle_offsets()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You'll need the keys in one of your hands to [drive_verb] [AM].</span>")
|
||||
|
||||
/datum/component/riding/proc/Unbuckle(atom/movable/M)
|
||||
addtimer(CALLBACK(parent, /atom/movable/.proc/unbuckle_mob, M), 0, TIMER_UNIQUE)
|
||||
|
||||
/datum/component/riding/proc/Process_Spacemove(direction)
|
||||
var/atom/movable/AM = parent
|
||||
return override_allow_spacemove || AM.has_gravity()
|
||||
|
||||
/datum/component/riding/proc/account_limbs(mob/living/M)
|
||||
if(M.get_num_legs() < 2 && !slowed)
|
||||
vehicle_move_delay = vehicle_move_delay + slowvalue
|
||||
slowed = TRUE
|
||||
else if(slowed)
|
||||
vehicle_move_delay = vehicle_move_delay - slowvalue
|
||||
slowed = FALSE
|
||||
|
||||
///////Yes, I said humans. No, this won't end well...//////////
|
||||
/datum/component/riding/human
|
||||
|
||||
/datum/component/riding/human/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_host_unarmed_melee)
|
||||
|
||||
/datum/component/riding/human/proc/on_host_unarmed_melee(atom/target)
|
||||
var/mob/living/carbon/human/AM = parent
|
||||
if(AM.a_intent == INTENT_DISARM && (target in AM.buckled_mobs))
|
||||
force_dismount(target)
|
||||
|
||||
/datum/component/riding/human/handle_vehicle_layer()
|
||||
var/atom/movable/AM = parent
|
||||
if(AM.buckled_mobs && AM.buckled_mobs.len)
|
||||
if(AM.dir == SOUTH)
|
||||
AM.layer = ABOVE_MOB_LAYER
|
||||
else
|
||||
AM.layer = OBJ_LAYER
|
||||
else
|
||||
AM.layer = MOB_LAYER
|
||||
|
||||
/datum/component/riding/human/force_dismount(mob/living/user)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(user)
|
||||
user.Knockdown(60)
|
||||
user.visible_message("<span class='warning'>[AM] pushes [user] off of them!</span>")
|
||||
|
||||
/datum/component/riding/cyborg
|
||||
|
||||
/datum/component/riding/cyborg/ride_check(mob/user)
|
||||
var/atom/movable/AM = parent
|
||||
if(user.incapacitated())
|
||||
var/kick = TRUE
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/R = AM
|
||||
if(R.module && R.module.ride_allow_incapacitated)
|
||||
kick = FALSE
|
||||
if(kick)
|
||||
to_chat(user, "<span class='userdanger'>You fall off of [AM]!</span>")
|
||||
Unbuckle(user)
|
||||
return
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/carbonuser = user
|
||||
if(!carbonuser.get_num_arms())
|
||||
Unbuckle(user)
|
||||
to_chat(user, "<span class='userdanger'>You can't grab onto [AM] with no hands!</span>")
|
||||
return
|
||||
|
||||
/datum/component/riding/cyborg/handle_vehicle_layer()
|
||||
var/atom/movable/AM = parent
|
||||
if(AM.buckled_mobs && AM.buckled_mobs.len)
|
||||
if(AM.dir == SOUTH)
|
||||
AM.layer = ABOVE_MOB_LAYER
|
||||
else
|
||||
AM.layer = OBJ_LAYER
|
||||
else
|
||||
AM.layer = MOB_LAYER
|
||||
|
||||
/datum/component/riding/cyborg/get_offsets(pass_index) // list(dir = x, y, layer)
|
||||
return list(TEXT_NORTH = list(0, 4), TEXT_SOUTH = list(0, 4), TEXT_EAST = list(-6, 3), TEXT_WEST = list( 6, 3))
|
||||
|
||||
/datum/component/riding/cyborg/handle_vehicle_offsets()
|
||||
var/atom/movable/AM = parent
|
||||
if(AM.has_buckled_mobs())
|
||||
for(var/mob/living/M in AM.buckled_mobs)
|
||||
M.setDir(AM.dir)
|
||||
if(iscyborg(AM))
|
||||
var/mob/living/silicon/robot/R = AM
|
||||
if(istype(R.module))
|
||||
M.pixel_x = R.module.ride_offset_x[dir2text(AM.dir)]
|
||||
M.pixel_y = R.module.ride_offset_y[dir2text(AM.dir)]
|
||||
else
|
||||
..()
|
||||
|
||||
/datum/component/riding/cyborg/force_dismount(mob/living/M)
|
||||
var/atom/movable/AM = parent
|
||||
AM.unbuckle_mob(M)
|
||||
var/turf/target = get_edge_target_turf(AM, AM.dir)
|
||||
var/turf/targetm = get_step(get_turf(AM), AM.dir)
|
||||
M.Move(targetm)
|
||||
M.visible_message("<span class='warning'>[M] is thrown clear of [AM]!</span>")
|
||||
M.throw_at(target, 14, 5, AM)
|
||||
M.Knockdown(60)
|
||||
|
||||
/datum/component/riding/proc/equip_buckle_inhands(mob/living/carbon/human/user, amount_required = 1)
|
||||
var/atom/movable/AM = parent
|
||||
var/amount_equipped = 0
|
||||
for(var/amount_needed = amount_required, amount_needed > 0, amount_needed--)
|
||||
var/obj/item/riding_offhand/inhand = new /obj/item/riding_offhand(user)
|
||||
inhand.rider = user
|
||||
inhand.parent = AM
|
||||
if(user.put_in_hands(inhand, TRUE))
|
||||
amount_equipped++
|
||||
else
|
||||
break
|
||||
if(amount_equipped >= amount_required)
|
||||
return TRUE
|
||||
else
|
||||
unequip_buckle_inhands(user)
|
||||
return FALSE
|
||||
|
||||
/datum/component/riding/proc/unequip_buckle_inhands(mob/living/carbon/user)
|
||||
var/atom/movable/AM = parent
|
||||
for(var/obj/item/riding_offhand/O in user.contents)
|
||||
if(O.parent != AM)
|
||||
CRASH("RIDING OFFHAND ON WRONG MOB")
|
||||
continue
|
||||
if(O.selfdeleting)
|
||||
continue
|
||||
else
|
||||
qdel(O)
|
||||
return TRUE
|
||||
|
||||
/obj/item/riding_offhand
|
||||
name = "offhand"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "offhand"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
flags_1 = ABSTRACT_1 | DROPDEL_1 | NOBLUDGEON_1
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
var/mob/living/carbon/rider
|
||||
var/mob/living/parent
|
||||
var/selfdeleting = FALSE
|
||||
|
||||
/obj/item/riding_offhand/dropped()
|
||||
selfdeleting = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/riding_offhand/equipped()
|
||||
if(loc != rider)
|
||||
selfdeleting = TRUE
|
||||
qdel(src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/riding_offhand/Destroy()
|
||||
var/atom/movable/AM = parent
|
||||
if(selfdeleting)
|
||||
if(rider in AM.buckled_mobs)
|
||||
AM.unbuckle_mob(rider)
|
||||
. = ..()
|
||||
|
||||
@@ -4,6 +4,5 @@
|
||||
/datum/component/redirect/Initialize(list/signals, datum/callback/_callback)
|
||||
//It's not our job to verify the right signals are registered here, just do it.
|
||||
if(!LAZYLEN(signals) || !istype(_callback))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("A redirection component was initialized with incorrect args.")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(signals, _callback)
|
||||
|
||||
@@ -42,11 +42,11 @@
|
||||
var/T = get_turf(H)
|
||||
if(too_spooky)
|
||||
if(prob(30))
|
||||
new/obj/item/device/instrument/saxophone/spectral(T)
|
||||
new/obj/item/instrument/saxophone/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/device/instrument/trumpet/spectral(T)
|
||||
new/obj/item/instrument/trumpet/spectral(T)
|
||||
else if(prob(30))
|
||||
new/obj/item/device/instrument/trombone/spectral(T)
|
||||
new/obj/item/instrument/trombone/spectral(T)
|
||||
else
|
||||
to_chat(H, "The spooky gods forgot to ship your instrument. Better luck next unlife.")
|
||||
to_chat(H, "<B>You are the spooky skeleton!</B>")
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/datum/component/stationloving
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
var/inform_admins = FALSE
|
||||
var/disallow_soul_imbue = TRUE
|
||||
|
||||
/datum/component/stationloving/Initialize(inform_admins = FALSE)
|
||||
if(!ismovableatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(list(COMSIG_MOVABLE_Z_CHANGED), .proc/check_in_bounds)
|
||||
RegisterSignal(list(COMSIG_PARENT_PREQDELETED), .proc/check_deletion)
|
||||
RegisterSignal(list(COMSIG_ITEM_IMBUE_SOUL), .proc/check_soul_imbue)
|
||||
src.inform_admins = inform_admins
|
||||
check_in_bounds() // Just in case something is being created outside of station/centcom
|
||||
|
||||
/datum/component/stationloving/InheritComponent(datum/component/stationloving/newc, original, list/arguments)
|
||||
if (original)
|
||||
if (istype(newc))
|
||||
inform_admins = newc.inform_admins
|
||||
else if (LAZYLEN(arguments))
|
||||
inform_admins = arguments[1]
|
||||
|
||||
/datum/component/stationloving/proc/relocate()
|
||||
var/targetturf = find_safe_turf()
|
||||
if(!targetturf)
|
||||
if(GLOB.blobstart.len > 0)
|
||||
targetturf = get_turf(pick(GLOB.blobstart))
|
||||
else
|
||||
CRASH("Unable to find a blobstart landmark")
|
||||
|
||||
var/atom/movable/AM = parent
|
||||
if(ismob(AM.loc))
|
||||
var/mob/M = AM.loc
|
||||
M.transferItemToLoc(AM, targetturf, TRUE) //nodrops disks when?
|
||||
else if(AM.loc.SendSignal(COMSIG_CONTAINS_STORAGE))
|
||||
AM.loc.SendSignal(COMSIG_TRY_STORAGE_TAKE, src, targetturf, TRUE)
|
||||
else
|
||||
AM.forceMove(targetturf)
|
||||
// move the disc, so ghosts remain orbiting it even if it's "destroyed"
|
||||
return targetturf
|
||||
|
||||
/datum/component/stationloving/proc/check_in_bounds()
|
||||
if(in_bounds())
|
||||
return
|
||||
else
|
||||
var/turf/currentturf = get_turf(src)
|
||||
to_chat(get(parent, /mob), "<span class='danger'>You can't help but feel that you just lost something back there...</span>")
|
||||
var/turf/targetturf = relocate()
|
||||
log_game("[parent] has been moved out of bounds in [COORD(currentturf)]. Moving it to [COORD(targetturf)].")
|
||||
if(inform_admins)
|
||||
message_admins("[parent] has been moved out of bounds in [ADMIN_COORDJMP(currentturf)]. Moving it to [ADMIN_COORDJMP(targetturf)].")
|
||||
|
||||
/datum/component/stationloving/proc/check_soul_imbue()
|
||||
return disallow_soul_imbue
|
||||
|
||||
/datum/component/stationloving/proc/in_bounds()
|
||||
var/static/list/allowed_shuttles = typecacheof(list(/area/shuttle/syndicate, /area/shuttle/escape, /area/shuttle/pod_1, /area/shuttle/pod_2, /area/shuttle/pod_3, /area/shuttle/pod_4))
|
||||
var/turf/T = get_turf(parent)
|
||||
if (!T)
|
||||
return FALSE
|
||||
if (is_station_level(T.z) || is_centcom_level(T.z))
|
||||
return TRUE
|
||||
if (is_transit_level(T.z))
|
||||
var/area/A = T.loc
|
||||
if (is_type_in_typecache(A, allowed_shuttles))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/component/stationloving/proc/check_deletion(force) // TRUE = interrupt deletion, FALSE = proceed with deletion
|
||||
|
||||
var/turf/T = get_turf(parent)
|
||||
|
||||
if(inform_admins && force)
|
||||
message_admins("[parent] has been !!force deleted!! in [ADMIN_COORDJMP(T)].")
|
||||
log_game("[parent] has been !!force deleted!! in [COORD(T)].")
|
||||
|
||||
if(!force)
|
||||
var/turf/targetturf = relocate()
|
||||
log_game("[parent] has been destroyed in [COORD(T)]. Moving it to [COORD(targetturf)].")
|
||||
if(inform_admins)
|
||||
message_admins("[parent] has been destroyed in [ADMIN_COORDJMP(T)]. Moving it to [ADMIN_COORDJMP(targetturf)].")
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -1,185 +1,196 @@
|
||||
|
||||
// External storage-related logic:
|
||||
// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
|
||||
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
|
||||
|
||||
/datum/component/storage/concrete
|
||||
var/drop_all_on_deconstruct = TRUE
|
||||
var/drop_all_on_destroy = FALSE
|
||||
var/transfer_contents_on_component_transfer = FALSE
|
||||
var/list/datum/component/storage/slaves = list()
|
||||
|
||||
/datum/component/storage/concrete/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
|
||||
RegisterSignal(COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
|
||||
|
||||
/datum/component/storage/concrete/Destroy()
|
||||
var/atom/real_location = real_location()
|
||||
for(var/atom/_A in real_location)
|
||||
_A.mouse_opacity = initial(_A.mouse_opacity)
|
||||
if(drop_all_on_destroy)
|
||||
do_quick_empty()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
slave.change_master(null)
|
||||
return ..()
|
||||
|
||||
/datum/component/storage/concrete/master()
|
||||
return src
|
||||
|
||||
/datum/component/storage/concrete/real_location()
|
||||
return parent
|
||||
|
||||
/datum/component/storage/concrete/OnTransfer(datum/new_parent)
|
||||
if(!isatom(new_parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/list/mob/_is_using
|
||||
if(is_using)
|
||||
_is_using = is_using.Copy()
|
||||
close_all()
|
||||
if(transfer_contents_on_component_transfer)
|
||||
var/atom/old = parent
|
||||
for(var/i in old)
|
||||
var/atom/movable/AM = i
|
||||
AM.forceMove(new_parent)
|
||||
if(_is_using)
|
||||
for(var/i in _is_using)
|
||||
var/mob/M = i
|
||||
show_to(M)
|
||||
|
||||
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
|
||||
. = TRUE
|
||||
var/atom/real_location = real_location()
|
||||
if(I.loc != real_location)
|
||||
I.forceMove(real_location)
|
||||
refresh_mob_views()
|
||||
|
||||
/datum/component/storage/concrete/refresh_mob_views()
|
||||
. = ..()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
slave.refresh_mob_views()
|
||||
|
||||
/datum/component/storage/concrete/emp_act(severity)
|
||||
var/atom/real_location = real_location()
|
||||
for(var/i in real_location)
|
||||
var/atom/A = i
|
||||
A.emp_act(severity)
|
||||
|
||||
/datum/component/storage/concrete/proc/on_slave_link(datum/component/storage/S)
|
||||
if(S == src)
|
||||
return FALSE
|
||||
slaves += S
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/proc/on_slave_unlink(datum/component/storage/S)
|
||||
slaves -= S
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/concrete/proc/on_contents_del(atom/A)
|
||||
var/atom/real_location = parent
|
||||
if(A in real_location)
|
||||
usr = null
|
||||
remove_from_storage(A, null)
|
||||
|
||||
/datum/component/storage/concrete/proc/on_deconstruct(disassembled)
|
||||
if(drop_all_on_deconstruct)
|
||||
do_quick_empty()
|
||||
|
||||
/datum/component/storage/concrete/can_see_contents()
|
||||
. = ..()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
. |= slave.can_see_contents()
|
||||
|
||||
//Resets screen loc and other vars of something being removed from storage.
|
||||
/datum/component/storage/concrete/_removal_reset(atom/movable/thing)
|
||||
thing.layer = initial(thing.layer)
|
||||
thing.plane = initial(thing.plane)
|
||||
thing.mouse_opacity = initial(thing.mouse_opacity)
|
||||
if(thing.maptext)
|
||||
thing.maptext = ""
|
||||
|
||||
/datum/component/storage/concrete/remove_from_storage(atom/movable/AM, atom/new_location)
|
||||
//Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped
|
||||
//or moving objects, things that should never happen
|
||||
var/atom/parent = src.parent
|
||||
var/list/seeing_mobs = can_see_contents()
|
||||
for(var/mob/M in seeing_mobs)
|
||||
M.client.screen -= AM
|
||||
if(ismob(parent.loc) && isitem(AM))
|
||||
var/obj/item/I = AM
|
||||
var/mob/M = parent.loc
|
||||
I.dropped(M)
|
||||
if(new_location)
|
||||
//Reset the items values
|
||||
_removal_reset(AM)
|
||||
AM.forceMove(new_location)
|
||||
//We don't want to call this if the item is being destroyed
|
||||
AM.on_exit_storage(src)
|
||||
else
|
||||
//Being destroyed, just move to nullspace now (so it's not in contents for the icon update)
|
||||
AM.moveToNullspace()
|
||||
refresh_mob_views()
|
||||
if(isobj(parent))
|
||||
var/obj/O = parent
|
||||
O.update_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/proc/handle_item_insertion_from_slave(datum/component/storage/slave, obj/item/I, prevent_warning = FALSE, M)
|
||||
. = handle_item_insertion(I, prevent_warning, M, slave)
|
||||
if(. && !prevent_warning)
|
||||
slave.mob_item_insertion_feedback(usr, M, I)
|
||||
|
||||
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
var/atom/parent = src.parent
|
||||
var/moved = FALSE
|
||||
if(!istype(I))
|
||||
return FALSE
|
||||
if(M)
|
||||
if(!M.temporarilyRemoveItemFromInventory(I))
|
||||
return FALSE
|
||||
else
|
||||
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
|
||||
if(I.pulledby)
|
||||
I.pulledby.stop_pulling()
|
||||
if(silent)
|
||||
prevent_warning = TRUE
|
||||
if(!_insert_physical_item(I))
|
||||
if(moved)
|
||||
if(M)
|
||||
if(!M.put_in_active_hand(I))
|
||||
I.forceMove(parent.drop_location())
|
||||
else
|
||||
I.forceMove(parent.drop_location())
|
||||
return FALSE
|
||||
I.on_enter_storage(master)
|
||||
refresh_mob_views()
|
||||
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
|
||||
if(M)
|
||||
if(M.client && M.active_storage != src)
|
||||
M.client.screen -= I
|
||||
if(M.observers && M.observers.len)
|
||||
for(var/i in M.observers)
|
||||
var/mob/dead/observe = i
|
||||
if(observe.client && observe.active_storage != src)
|
||||
observe.client.screen -= I
|
||||
if(!remote)
|
||||
parent.add_fingerprint(M)
|
||||
if(!prevent_warning)
|
||||
mob_item_insertion_feedback(usr, M, I)
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/update_icon()
|
||||
if(isobj(parent))
|
||||
var/obj/O = parent
|
||||
O.update_icon()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
slave.update_icon()
|
||||
|
||||
// External storage-related logic:
|
||||
// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages
|
||||
// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement
|
||||
|
||||
/datum/component/storage/concrete
|
||||
var/drop_all_on_deconstruct = TRUE
|
||||
var/drop_all_on_destroy = FALSE
|
||||
var/transfer_contents_on_component_transfer = FALSE
|
||||
var/list/datum/component/storage/slaves = list()
|
||||
|
||||
var/list/_contents_limbo // Where objects go to live mid transfer
|
||||
var/list/_user_limbo // The last users before the component started moving
|
||||
|
||||
/datum/component/storage/concrete/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(COMSIG_ATOM_CONTENTS_DEL, .proc/on_contents_del)
|
||||
RegisterSignal(COMSIG_OBJ_DECONSTRUCT, .proc/on_deconstruct)
|
||||
|
||||
/datum/component/storage/concrete/Destroy()
|
||||
var/atom/real_location = real_location()
|
||||
for(var/atom/_A in real_location)
|
||||
_A.mouse_opacity = initial(_A.mouse_opacity)
|
||||
if(drop_all_on_destroy)
|
||||
do_quick_empty()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
slave.change_master(null)
|
||||
QDEL_LIST(_contents_limbo)
|
||||
_user_limbo = null
|
||||
return ..()
|
||||
|
||||
/datum/component/storage/concrete/master()
|
||||
return src
|
||||
|
||||
/datum/component/storage/concrete/real_location()
|
||||
return parent
|
||||
|
||||
/datum/component/storage/concrete/PreTransfer()
|
||||
if(is_using)
|
||||
_user_limbo = is_using.Copy()
|
||||
close_all()
|
||||
if(transfer_contents_on_component_transfer)
|
||||
_contents_limbo = list()
|
||||
for(var/atom/movable/AM in parent)
|
||||
_contents_limbo += AM
|
||||
AM.moveToNullspace()
|
||||
|
||||
/datum/component/storage/concrete/PostTransfer()
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(transfer_contents_on_component_transfer)
|
||||
for(var/i in _contents_limbo)
|
||||
var/atom/movable/AM = i
|
||||
AM.forceMove(parent)
|
||||
_contents_limbo = null
|
||||
if(_user_limbo)
|
||||
for(var/i in _user_limbo)
|
||||
show_to(i)
|
||||
_user_limbo = null
|
||||
|
||||
/datum/component/storage/concrete/_insert_physical_item(obj/item/I, override = FALSE)
|
||||
. = TRUE
|
||||
var/atom/real_location = real_location()
|
||||
if(I.loc != real_location)
|
||||
I.forceMove(real_location)
|
||||
refresh_mob_views()
|
||||
|
||||
/datum/component/storage/concrete/refresh_mob_views()
|
||||
. = ..()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
slave.refresh_mob_views()
|
||||
|
||||
/datum/component/storage/concrete/emp_act(severity)
|
||||
var/atom/real_location = real_location()
|
||||
for(var/i in real_location)
|
||||
var/atom/A = i
|
||||
A.emp_act(severity)
|
||||
|
||||
/datum/component/storage/concrete/proc/on_slave_link(datum/component/storage/S)
|
||||
if(S == src)
|
||||
return FALSE
|
||||
slaves += S
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/proc/on_slave_unlink(datum/component/storage/S)
|
||||
slaves -= S
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/concrete/proc/on_contents_del(atom/A)
|
||||
var/atom/real_location = parent
|
||||
if(A in real_location)
|
||||
usr = null
|
||||
remove_from_storage(A, null)
|
||||
|
||||
/datum/component/storage/concrete/proc/on_deconstruct(disassembled)
|
||||
if(drop_all_on_deconstruct)
|
||||
do_quick_empty()
|
||||
|
||||
/datum/component/storage/concrete/can_see_contents()
|
||||
. = ..()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
. |= slave.can_see_contents()
|
||||
|
||||
//Resets screen loc and other vars of something being removed from storage.
|
||||
/datum/component/storage/concrete/_removal_reset(atom/movable/thing)
|
||||
thing.layer = initial(thing.layer)
|
||||
thing.plane = initial(thing.plane)
|
||||
thing.mouse_opacity = initial(thing.mouse_opacity)
|
||||
if(thing.maptext)
|
||||
thing.maptext = ""
|
||||
|
||||
/datum/component/storage/concrete/remove_from_storage(atom/movable/AM, atom/new_location)
|
||||
//Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped
|
||||
//or moving objects, things that should never happen
|
||||
var/atom/parent = src.parent
|
||||
var/list/seeing_mobs = can_see_contents()
|
||||
for(var/mob/M in seeing_mobs)
|
||||
M.client.screen -= AM
|
||||
if(ismob(parent.loc) && isitem(AM))
|
||||
var/obj/item/I = AM
|
||||
var/mob/M = parent.loc
|
||||
I.dropped(M)
|
||||
if(new_location)
|
||||
//Reset the items values
|
||||
_removal_reset(AM)
|
||||
AM.forceMove(new_location)
|
||||
//We don't want to call this if the item is being destroyed
|
||||
AM.on_exit_storage(src)
|
||||
else
|
||||
//Being destroyed, just move to nullspace now (so it's not in contents for the icon update)
|
||||
AM.moveToNullspace()
|
||||
refresh_mob_views()
|
||||
if(isobj(parent))
|
||||
var/obj/O = parent
|
||||
O.update_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/proc/slave_can_insert_object(datum/component/storage/slave, obj/item/I, stop_messages = FALSE, mob/M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/proc/handle_item_insertion_from_slave(datum/component/storage/slave, obj/item/I, prevent_warning = FALSE, M)
|
||||
. = handle_item_insertion(I, prevent_warning, M, slave)
|
||||
if(. && !prevent_warning)
|
||||
slave.mob_item_insertion_feedback(usr, M, I)
|
||||
|
||||
/datum/component/storage/concrete/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote) //Remote is null or the slave datum
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
var/atom/parent = src.parent
|
||||
var/moved = FALSE
|
||||
if(!istype(I))
|
||||
return FALSE
|
||||
if(M)
|
||||
if(!M.temporarilyRemoveItemFromInventory(I))
|
||||
return FALSE
|
||||
else
|
||||
moved = TRUE //At this point if the proc fails we need to manually move the object back to the turf/mob/whatever.
|
||||
if(I.pulledby)
|
||||
I.pulledby.stop_pulling()
|
||||
if(silent)
|
||||
prevent_warning = TRUE
|
||||
if(!_insert_physical_item(I))
|
||||
if(moved)
|
||||
if(M)
|
||||
if(!M.put_in_active_hand(I))
|
||||
I.forceMove(parent.drop_location())
|
||||
else
|
||||
I.forceMove(parent.drop_location())
|
||||
return FALSE
|
||||
I.on_enter_storage(master)
|
||||
refresh_mob_views()
|
||||
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
|
||||
if(M)
|
||||
if(M.client && M.active_storage != src)
|
||||
M.client.screen -= I
|
||||
if(M.observers && M.observers.len)
|
||||
for(var/i in M.observers)
|
||||
var/mob/dead/observe = i
|
||||
if(observe.client && observe.active_storage != src)
|
||||
observe.client.screen -= I
|
||||
if(!remote)
|
||||
parent.add_fingerprint(M)
|
||||
if(!prevent_warning)
|
||||
mob_item_insertion_feedback(usr, M, I)
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/concrete/update_icon()
|
||||
if(isobj(parent))
|
||||
var/obj/O = parent
|
||||
O.update_icon()
|
||||
for(var/i in slaves)
|
||||
var/datum/component/storage/slave = i
|
||||
slave.update_icon()
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
/datum/component/storage/concrete/implant
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 6
|
||||
max_items = 2
|
||||
drop_all_on_destroy = TRUE
|
||||
drop_all_on_deconstruct = TRUE
|
||||
silent = TRUE
|
||||
|
||||
/datum/component/storage/concrete/implant/Initialize()
|
||||
. = ..()
|
||||
cant_hold = typecacheof(list(/obj/item/disk/nuclear))
|
||||
|
||||
/datum/component/storage/concrete/implant/InheritComponent(datum/component/storage/concrete/implant/I, original)
|
||||
if(!istype(I))
|
||||
return ..()
|
||||
max_combined_w_class += I.max_combined_w_class
|
||||
max_items += I.max_items
|
||||
/datum/component/storage/concrete/implant
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 6
|
||||
max_items = 2
|
||||
drop_all_on_destroy = TRUE
|
||||
drop_all_on_deconstruct = TRUE
|
||||
silent = TRUE
|
||||
allow_big_nesting = TRUE
|
||||
|
||||
/datum/component/storage/concrete/implant/Initialize()
|
||||
. = ..()
|
||||
cant_hold = typecacheof(list(/obj/item/disk/nuclear))
|
||||
|
||||
/datum/component/storage/concrete/implant/InheritComponent(datum/component/storage/concrete/implant/I, original)
|
||||
if(!istype(I))
|
||||
return ..()
|
||||
max_combined_w_class += I.max_combined_w_class
|
||||
max_items += I.max_items
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
/obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector,
|
||||
/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper,
|
||||
/obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini,
|
||||
/obj/item/device/firing_pin
|
||||
/obj/item/firing_pin
|
||||
))
|
||||
|
||||
/datum/component/storage/concrete/pockets/shoes/clown/Initialize()
|
||||
@@ -49,7 +49,7 @@
|
||||
/obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector,
|
||||
/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper,
|
||||
/obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini,
|
||||
/obj/item/device/firing_pin, /obj/item/bikehorn))
|
||||
/obj/item/firing_pin, /obj/item/bikehorn))
|
||||
|
||||
/datum/component/storage/concrete/pockets/pocketprotector
|
||||
max_items = 3
|
||||
@@ -61,5 +61,5 @@
|
||||
/obj/item/pen,
|
||||
/obj/item/toy/crayon,
|
||||
/obj/item/lipstick,
|
||||
/obj/item/device/flashlight/pen,
|
||||
/obj/item/flashlight/pen,
|
||||
/obj/item/clothing/mask/cigarette))
|
||||
@@ -1,31 +1,33 @@
|
||||
/datum/component/storage/concrete/rped
|
||||
collection_mode = COLLECT_EVERYTHING
|
||||
allow_quick_gather = TRUE
|
||||
allow_quick_empty = TRUE
|
||||
click_gather = TRUE
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 100
|
||||
max_items = 50
|
||||
display_numerical_stacking = TRUE
|
||||
|
||||
/datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
|
||||
. = ..()
|
||||
if(!I.get_part_rating() && !stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/concrete/bluespace/rped
|
||||
collection_mode = COLLECT_EVERYTHING
|
||||
allow_quick_gather = TRUE
|
||||
allow_quick_empty = TRUE
|
||||
click_gather = TRUE
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 800
|
||||
max_items = 400
|
||||
display_numerical_stacking = TRUE
|
||||
|
||||
/datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
|
||||
. = ..()
|
||||
if(!I.get_part_rating() && !stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
|
||||
return FALSE
|
||||
/datum/component/storage/concrete/rped
|
||||
collection_mode = COLLECT_EVERYTHING
|
||||
allow_quick_gather = TRUE
|
||||
allow_quick_empty = TRUE
|
||||
click_gather = TRUE
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 100
|
||||
max_items = 50
|
||||
display_numerical_stacking = TRUE
|
||||
|
||||
/datum/component/storage/concrete/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
|
||||
. = ..()
|
||||
if(!I.get_part_rating())
|
||||
if (!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/concrete/bluespace/rped
|
||||
collection_mode = COLLECT_EVERYTHING
|
||||
allow_quick_gather = TRUE
|
||||
allow_quick_empty = TRUE
|
||||
click_gather = TRUE
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = 800
|
||||
max_items = 400
|
||||
display_numerical_stacking = TRUE
|
||||
|
||||
/datum/component/storage/concrete/bluespace/rped/can_be_inserted(obj/item/I, stop_messages, mob/M)
|
||||
. = ..()
|
||||
if(!I.get_part_rating())
|
||||
if (!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] only accepts machine par ts!</span>")
|
||||
return FALSE
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,10 +21,7 @@
|
||||
)
|
||||
|
||||
/datum/component/thermite/Initialize(_amount)
|
||||
if(!istype(parent, /turf))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("A thermite component has been applied to an incorrect object. parent: [parent]")
|
||||
if(blacklist[parent.type])
|
||||
if(!istype(parent, /turf) || blacklist[parent.type])
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(immunelist[parent.type])
|
||||
_amount*=0 //Yeah the overlay can still go on it and be cleaned but you arent burning down a diamond wall
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
|
||||
/datum/component/wet_floor/Initialize(strength, duration_minimum, duration_add, duration_maximum, _permanent = FALSE)
|
||||
if(!isopenturf(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Wet floor component attempted to be applied to a non open turf!")
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
add_wet(strength, duration_minimum, duration_add, duration_maximum)
|
||||
RegisterSignal(COMSIG_TURF_IS_WET, .proc/is_wet)
|
||||
RegisterSignal(COMSIG_TURF_MAKE_DRY, .proc/dry)
|
||||
@@ -136,13 +135,14 @@
|
||||
for(var/i in time_left_list)
|
||||
. |= text2num(i)
|
||||
|
||||
/datum/component/wet_floor/OnTransfer(datum/to_datum)
|
||||
if(!isopenturf(to_datum))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
CRASH("Wet floor component attempted to be transferred to a non open turf!")
|
||||
/datum/component/wet_floor/PreTransfer()
|
||||
var/turf/O = parent
|
||||
O.cut_overlay(current_overlay)
|
||||
var/turf/T = to_datum
|
||||
|
||||
/datum/component/wet_floor/PostTransfer()
|
||||
if(!isopenturf(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/turf/T = parent
|
||||
T.add_overlay(current_overlay)
|
||||
|
||||
/datum/component/wet_floor/proc/add_wet(type, duration_minimum = 0, duration_add = 0, duration_maximum = MAXIMUM_WET_TIME, _permanent = FALSE)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
. = header ? "The following pull requests are currently test merged:<br>" : ""
|
||||
for(var/line in testmerge)
|
||||
var/cm = testmerge[line]["commit"]
|
||||
var/details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 7)))
|
||||
var/details = ": '" + html_encode(testmerge[line]["title"]) + "' by " + html_encode(testmerge[line]["author"]) + " at commit " + html_encode(copytext(cm, 1, min(length(cm), 11)))
|
||||
if(details && findtext(details, "\[s\]") && (!usr || !usr.client.holder))
|
||||
continue
|
||||
. += "<a href=\"[CONFIG_GET(string/githuburl)]/pull/[line]\">#[line][details]</a><br>"
|
||||
@@ -54,7 +54,7 @@
|
||||
to_chat(src, GLOB.revdata.GetTestMergeInfo())
|
||||
prefix = "Based off origin/master commit: "
|
||||
var/pc = GLOB.revdata.originmastercommit
|
||||
to_chat(src, "[prefix]<a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 7))]</a>")
|
||||
to_chat(src, "[prefix]<a href=\"[CONFIG_GET(string/githuburl)]/commit/[pc]\">[copytext(pc, 1, min(length(pc), 11))]</a>")
|
||||
else
|
||||
to_chat(src, "Master revision unknown")
|
||||
to_chat(src, "Revision: [GLOB.revdata.commit]")
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
/obj/item/mushpunch
|
||||
name = "odd mushroom"
|
||||
desc = "<I>Sapienza Ophioglossoides</I>:An odd mushroom from the flesh of a mushroom person. it has apparently retained some innate power of it's owner, as it quivers with barely-contained POWER!"
|
||||
icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
|
||||
icon = 'icons/obj/hydroponics/seeds.dmi'
|
||||
icon_state = "mycelium-angel"
|
||||
|
||||
/obj/item/mushpunch/attack_self(mob/living/carbon/human/user)
|
||||
|
||||
+6
-6
@@ -237,12 +237,12 @@
|
||||
/datum/mind/proc/remove_antag_equip()
|
||||
var/list/Mob_Contents = current.get_contents()
|
||||
for(var/obj/item/I in Mob_Contents)
|
||||
if(istype(I, /obj/item/device/pda))
|
||||
var/obj/item/device/pda/P = I
|
||||
if(istype(I, /obj/item/pda))
|
||||
var/obj/item/pda/P = I
|
||||
P.lock_code = ""
|
||||
|
||||
else if(istype(I, /obj/item/device/radio))
|
||||
var/obj/item/device/radio/R = I
|
||||
else if(istype(I, /obj/item/radio))
|
||||
var/obj/item/radio/R = I
|
||||
R.traitor_frequency = 0
|
||||
|
||||
/datum/mind/proc/remove_all_antag() //For the Lazy amongst us.
|
||||
@@ -264,8 +264,8 @@
|
||||
. = TRUE
|
||||
|
||||
var/list/all_contents = traitor_mob.GetAllContents()
|
||||
var/obj/item/device/pda/PDA = locate() in all_contents
|
||||
var/obj/item/device/radio/R = locate() in all_contents
|
||||
var/obj/item/pda/PDA = locate() in all_contents
|
||||
var/obj/item/radio/R = locate() in all_contents
|
||||
var/obj/item/pen/P
|
||||
|
||||
if (PDA) // Prioritize PDA pen, otherwise the pocket protector pens will be chosen, which causes numerous ahelps about missing uplink
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
/datum/trait/brainproblems
|
||||
name = "Brain Tumor"
|
||||
desc = "You have a little friend in your brain that is slowly destroying it. Better bring some mannitol!"
|
||||
value = -2
|
||||
value = -3
|
||||
gain_text = "<span class='danger'>You feel smooth.</span>"
|
||||
lose_text = "<span class='notice'>You feel wrinkled again.</span>"
|
||||
medical_record_text = "Patient has a tumor in their brain that is slowly driving them to brain death."
|
||||
|
||||
@@ -12,6 +12,40 @@
|
||||
|
||||
|
||||
|
||||
/datum/trait/pineapple_liker
|
||||
name = "Ananas Affinity"
|
||||
desc = "You find yourself greatly enjoying fruits of the ananas genus. You can't seem to ever get enough of their sweet goodness!"
|
||||
value = 0
|
||||
gain_text = "<span class='notice'>You feel an intense craving for pineapple.</span>"
|
||||
lose_text = "<span class='notice'>Your feelings towards pineapples seem to return to a lukewarm state.</span>"
|
||||
|
||||
/datum/trait/pineapple_liker/add()
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
var/datum/species/species = H.dna.species
|
||||
species.liked_food |= PINEAPPLE
|
||||
|
||||
/datum/trait/pineapple_liker/remove()
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
var/datum/species/species = H.dna.species
|
||||
species.liked_food &= ~PINEAPPLE
|
||||
|
||||
/datum/trait/pineapple_hater
|
||||
name = "Ananas Aversion"
|
||||
desc = "You find yourself greatly detesting fruits of the ananas genus. Serious, how the hell can anyone say these things are good? And what kind of madman would even dare putting it on a pizza!?"
|
||||
value = 0
|
||||
gain_text = "<span class='notice'>You find yourself pondering what kind of idiot actually enjoys pineapples...</span>"
|
||||
lose_text = "<span class='notice'>Your feelings towards pineapples seem to return to a lukewarm state.</span>"
|
||||
|
||||
/datum/trait/pineapple_hater/add()
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
var/datum/species/species = H.dna.species
|
||||
species.disliked_food |= PINEAPPLE
|
||||
|
||||
/datum/trait/pineapple_hater/remove()
|
||||
var/mob/living/carbon/human/H = trait_holder
|
||||
var/datum/species/species = H.dna.species
|
||||
species.disliked_food &= ~PINEAPPLE
|
||||
|
||||
/datum/trait/deviant_tastes
|
||||
name = "Deviant Tastes"
|
||||
desc = "You dislike food that most people enjoy, and find delicious what they don't."
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
if(I.tool_behaviour == TOOL_WIRECUTTER || I.tool_behaviour == TOOL_MULTITOOL)
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/device/assembly))
|
||||
var/obj/item/device/assembly/A = I
|
||||
if(istype(I, /obj/item/assembly))
|
||||
var/obj/item/assembly/A = I
|
||||
if(A.attachable)
|
||||
return TRUE
|
||||
|
||||
@@ -149,13 +149,13 @@
|
||||
/datum/wires/proc/pulse_color(color, mob/living/user)
|
||||
pulse(get_wire(color), user)
|
||||
|
||||
/datum/wires/proc/pulse_assembly(obj/item/device/assembly/S)
|
||||
/datum/wires/proc/pulse_assembly(obj/item/assembly/S)
|
||||
for(var/color in assemblies)
|
||||
if(S == assemblies[color])
|
||||
pulse_color(color)
|
||||
return TRUE
|
||||
|
||||
/datum/wires/proc/attach_assembly(color, obj/item/device/assembly/S)
|
||||
/datum/wires/proc/attach_assembly(color, obj/item/assembly/S)
|
||||
if(S && istype(S) && S.attachable && !is_attached(color))
|
||||
assemblies[color] = S
|
||||
S.forceMove(holder)
|
||||
@@ -163,7 +163,7 @@
|
||||
return S
|
||||
|
||||
/datum/wires/proc/detach_assembly(color)
|
||||
var/obj/item/device/assembly/S = get_attached(color)
|
||||
var/obj/item/assembly/S = get_attached(color)
|
||||
if(S && istype(S))
|
||||
assemblies -= color
|
||||
S.connected = null
|
||||
@@ -229,7 +229,7 @@
|
||||
reveal_wires = TRUE
|
||||
|
||||
// Same for anyone with an abductor multitool.
|
||||
else if(user.is_holding_item_of_type(/obj/item/device/multitool/abductor))
|
||||
else if(user.is_holding_item_of_type(/obj/item/multitool/abductor))
|
||||
reveal_wires = TRUE
|
||||
|
||||
// Station blueprints do that too, but only if the wires are not randomized.
|
||||
@@ -280,8 +280,8 @@
|
||||
. = TRUE
|
||||
else
|
||||
I = L.get_active_held_item()
|
||||
if(istype(I, /obj/item/device/assembly))
|
||||
var/obj/item/device/assembly/A = I
|
||||
if(istype(I, /obj/item/assembly))
|
||||
var/obj/item/assembly/A = I
|
||||
if(A.attachable)
|
||||
if(!L.temporarilyRemoveItemFromInventory(A))
|
||||
return
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/datum/wires/radio
|
||||
holder_type = /obj/item/device/radio
|
||||
holder_type = /obj/item/radio
|
||||
proper_name = "Radio"
|
||||
|
||||
/datum/wires/radio/New(atom/holder)
|
||||
@@ -10,11 +10,11 @@
|
||||
..()
|
||||
|
||||
/datum/wires/radio/interactable(mob/user)
|
||||
var/obj/item/device/radio/R = holder
|
||||
var/obj/item/radio/R = holder
|
||||
return R.unscrewed
|
||||
|
||||
/datum/wires/radio/on_pulse(index)
|
||||
var/obj/item/device/radio/R = holder
|
||||
var/obj/item/radio/R = holder
|
||||
switch(index)
|
||||
if(WIRE_SIGNAL)
|
||||
R.listening = !R.listening
|
||||
|
||||
@@ -136,7 +136,7 @@
|
||||
/datum/world_topic/status/Run(list/input)
|
||||
. = list()
|
||||
.["version"] = GLOB.game_version
|
||||
.["mode"] = GLOB.master_mode
|
||||
.["mode"] = "hidden" //CIT CHANGE - hides the gamemode in topic() calls to prevent meta'ing the gamemode
|
||||
.["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE
|
||||
.["enter"] = GLOB.enter_allowed
|
||||
.["vote"] = CONFIG_GET(flag/allow_vote_mode)
|
||||
|
||||
Reference in New Issue
Block a user