datums/controller stuff
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
#undef CURRENT_RESIDENT_FILE
|
||||
|
||||
#define LIST_MODE_NUM 0
|
||||
#define LIST_MODE_TEXT 1
|
||||
#define LIST_MODE_FLAG 2
|
||||
@@ -8,7 +6,7 @@
|
||||
var/name //read-only, this is determined by the last portion of the derived entry type
|
||||
var/config_entry_value
|
||||
var/default //read-only, just set value directly
|
||||
|
||||
|
||||
var/resident_file //the file which this was loaded from, if any
|
||||
var/modified = FALSE //set to TRUE if the default has been overridden by a config entry
|
||||
|
||||
@@ -19,7 +17,7 @@
|
||||
|
||||
/datum/config_entry/New()
|
||||
if(type == abstract_type)
|
||||
CRASH("Abstract config entry [type] instatiated!")
|
||||
CRASH("Abstract config entry [type] instatiated!")
|
||||
name = lowertext(type2top(type))
|
||||
if(islist(config_entry_value))
|
||||
var/list/L = config_entry_value
|
||||
|
||||
@@ -393,5 +393,5 @@ SUBSYSTEM_DEF(air)
|
||||
#undef SSAIR_ACTIVETURFS
|
||||
#undef SSAIR_EXCITEDGROUPS
|
||||
#undef SSAIR_HIGHPRESSURE
|
||||
#undef SSAIR_HOTSPOT
|
||||
#undef SSAIR_HOTSPOTS
|
||||
#undef SSAIR_SUPERCONDUCTIVITY
|
||||
|
||||
@@ -367,14 +367,14 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
away_level = template.load_new_z()
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
message_admins("Admin [key_name_admin(usr)] has loaded [away_name] away mission.")
|
||||
log_admin("Admin [key_name(usr)] has loaded [away_name] away mission.")
|
||||
if(!away_level)
|
||||
message_admins("Loading [away_name] failed!")
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
if(GLOB.the_gateway)
|
||||
//Link any found away gate with station gate
|
||||
var/obj/machinery/gateway/centeraway/new_gate
|
||||
@@ -384,4 +384,4 @@ GLOBAL_LIST_EMPTY(the_station_areas)
|
||||
break
|
||||
//Link station gate with away gate and remove wait time.
|
||||
GLOB.the_gateway.awaygate = new_gate
|
||||
GLOB.the_gateway.wait = world.time
|
||||
GLOB.the_gateway.wait = world.time
|
||||
+26
-1
@@ -21,7 +21,7 @@
|
||||
var/mob/owner
|
||||
|
||||
/datum/action/New(Target)
|
||||
target = Target
|
||||
link_to(Target)
|
||||
button = new
|
||||
button.linked_action = src
|
||||
button.name = name
|
||||
@@ -29,6 +29,9 @@
|
||||
if(desc)
|
||||
button.desc = desc
|
||||
|
||||
/datum/action/proc/link_to(Target)
|
||||
target = Target
|
||||
|
||||
/datum/action/Destroy()
|
||||
if(owner)
|
||||
Remove(owner)
|
||||
@@ -689,3 +692,25 @@
|
||||
else
|
||||
owner.remove_alt_appearance("smallsprite")
|
||||
small = FALSE
|
||||
|
||||
/datum/action/item_action/storage_gather_mode
|
||||
name = "Switch gathering mode"
|
||||
desc = "Switches the gathering mode of a storage object."
|
||||
icon_icon = 'icons/mob/actions/actions_items.dmi'
|
||||
button_icon_state = "storage_gather_switch"
|
||||
|
||||
/datum/action/item_action/storage_gather_mode/ApplyIcon(obj/screen/movable/action_button/current_button)
|
||||
. = ..()
|
||||
var/old_layer = target.layer
|
||||
var/old_plane = target.plane
|
||||
target.layer = FLOAT_LAYER //AAAH
|
||||
target.plane = FLOAT_PLANE //^ what that guy said
|
||||
current_button.cut_overlays()
|
||||
current_button.add_overlay(target)
|
||||
target.layer = old_layer
|
||||
target.plane = old_plane
|
||||
current_button.appearance_cache = target.appearance
|
||||
|
||||
/datum/action/item_action/storage_gather_mode/Trigger()
|
||||
GET_COMPONENT_FROM(STR, /datum/component/storage, target)
|
||||
STR.gather_mode_switch(owner)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
owner.derpspeech = min(owner.derpspeech + 5, 25)
|
||||
if(prob(3))
|
||||
owner.emote("drool")
|
||||
else if(owner && owner.stat == CONSCIOUS && prob(3))
|
||||
else if(owner.stat == CONSCIOUS && prob(3))
|
||||
owner.say(pick_list_replacements(BRAIN_DAMAGE_FILE, "brain_damage"))
|
||||
..()
|
||||
|
||||
@@ -138,13 +138,13 @@
|
||||
|
||||
/datum/brain_trauma/mild/muscle_weakness/on_life()
|
||||
var/fall_chance = 1
|
||||
if(owner && owner.m_intent == MOVE_INTENT_RUN)
|
||||
if(owner.m_intent == MOVE_INTENT_RUN)
|
||||
fall_chance += 2
|
||||
if(prob(fall_chance) && !owner.lying && !owner.buckled)
|
||||
to_chat(owner, "<span class='warning'>Your leg gives out!</span>")
|
||||
owner.Knockdown(35)
|
||||
|
||||
else if(owner && owner.get_active_held_item())
|
||||
else if(owner.get_active_held_item())
|
||||
var/drop_chance = 1
|
||||
var/obj/item/I = owner.get_active_held_item()
|
||||
drop_chance += I.w_class
|
||||
@@ -167,11 +167,11 @@
|
||||
if(prob(7))
|
||||
switch(rand(1,5))
|
||||
if(1)
|
||||
if(owner && owner.canmove && !isspaceturf(owner.loc))
|
||||
if(owner.canmove && !isspaceturf(owner.loc))
|
||||
to_chat(owner, "<span class='warning'>Your leg spasms!</span>")
|
||||
step(owner, pick(GLOB.cardinals))
|
||||
if(2)
|
||||
if(owner && owner.incapacitated())
|
||||
if(owner.incapacitated())
|
||||
return
|
||||
var/obj/item/I = owner.get_active_held_item()
|
||||
if(I)
|
||||
@@ -203,7 +203,7 @@
|
||||
owner.ClickOn(owner)
|
||||
owner.a_intent = prev_intent
|
||||
if(5)
|
||||
if(owner && owner.incapacitated())
|
||||
if(owner.incapacitated())
|
||||
return
|
||||
var/obj/item/I = owner.get_active_held_item()
|
||||
var/list/turf/targets = list()
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#define ROTATION_ALTCLICK 1
|
||||
#define ROTATION_WRENCH 2
|
||||
#define ROTATION_VERBS 4
|
||||
#define ROTATION_COUNTERCLOCKWISE 8
|
||||
#define ROTATION_CLOCKWISE 16
|
||||
#define ROTATION_FLIP 32
|
||||
#define ROTATION_ALTCLICK (1<<0)
|
||||
#define ROTATION_WRENCH (1<<1)
|
||||
#define ROTATION_VERBS (1<<2)
|
||||
#define ROTATION_COUNTERCLOCKWISE (1<<3)
|
||||
#define ROTATION_CLOCKWISE (1<<4)
|
||||
#define ROTATION_FLIP (1<<5)
|
||||
|
||||
/datum/component/simple_rotation
|
||||
var/datum/callback/can_user_rotate //Checks if user can rotate
|
||||
var/datum/callback/can_be_rotated //Check if object can be rotated at all
|
||||
var/datum/callback/after_rotation //Additional stuff to do after rotation
|
||||
|
||||
|
||||
var/rotation_flags = NONE
|
||||
var/default_rotation_direction = ROTATION_CLOCKWISE
|
||||
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
|
||||
// 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()
|
||||
@@ -0,0 +1,22 @@
|
||||
/datum/component/storage/concrete/bluespace/bag_of_holding/handle_item_insertion(obj/item/W, prevent_warning = FALSE, mob/living/user)
|
||||
var/atom/A = parent
|
||||
if((istype(W, /obj/item/storage/backpack/holding) || count_by_type(W.GetAllContents(), /obj/item/storage/backpack/holding)))
|
||||
var/turf/loccheck = get_turf(A)
|
||||
if(is_reebe(loccheck.z))
|
||||
user.visible_message("<span class='warning'>An unseen force knocks [user] to the ground!</span>", "<span class='big_brass'>\"I think not!\"</span>")
|
||||
user.Knockdown(60)
|
||||
return
|
||||
var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", "Proceed", "Abort")
|
||||
if(safety == "Abort" || !in_range(A, user) || !A || !W || user.incapacitated())
|
||||
return
|
||||
A.investigate_log("has become a singularity. Caused by [user.key]", INVESTIGATE_SINGULO)
|
||||
to_chat(user, "<span class='danger'>The Bluespace interfaces of the two devices catastrophically malfunction!</span>")
|
||||
qdel(W)
|
||||
var/obj/singularity/singulo = new /obj/singularity (get_turf(A))
|
||||
singulo.energy = 300 //should make it a bit bigger~
|
||||
message_admins("[key_name_admin(user)] detonated a bag of holding")
|
||||
log_game("[key_name(user)] detonated a bag of holding")
|
||||
qdel(A)
|
||||
singulo.process()
|
||||
return
|
||||
. = ..()
|
||||
@@ -0,0 +1,21 @@
|
||||
/datum/component/storage/concrete/bluespace
|
||||
var/dumping_range = 8
|
||||
var/dumping_sound = 'sound/items/pshoom.ogg'
|
||||
var/alt_sound = 'sound/items/pshoom_2.ogg'
|
||||
|
||||
/datum/component/storage/concrete/bluespace/dump_content_at(atom/dest, mob/M)
|
||||
var/atom/A = parent
|
||||
if(A.Adjacent(M))
|
||||
var/atom/dumping_location = dest.get_dumping_location()
|
||||
if(get_dist(M, dumping_location) < dumping_range)
|
||||
if(dumping_location.storage_contents_dump_act(src, M))
|
||||
if(alt_sound && prob(1))
|
||||
playsound(src, alt_sound, 40, 1)
|
||||
else
|
||||
playsound(src, dumping_sound, 40, 1)
|
||||
M.Beam(dumping_location, icon_state="rped_upgrade", time=5)
|
||||
return TRUE
|
||||
to_chat(M, "The [A.name] buzzes.")
|
||||
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
||||
return FALSE
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/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
|
||||
@@ -0,0 +1,65 @@
|
||||
/datum/component/storage/concrete/pockets
|
||||
max_items = 2
|
||||
max_w_class = WEIGHT_CLASS_SMALL
|
||||
max_combined_w_class = 50
|
||||
rustle_sound = FALSE
|
||||
|
||||
/datum/component/storage/concrete/pockets/handle_item_insertion(obj/item/I, prevent_warning, mob/user)
|
||||
. = ..()
|
||||
if(. && silent && !prevent_warning)
|
||||
if(quickdraw)
|
||||
to_chat(user, "<span class='notice'>You discreetly slip [I] into [parent]. Alt-click [parent] to remove it.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You discreetly slip [I] into [parent].</span>")
|
||||
|
||||
/datum/component/storage/concrete/pockets
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/datum/component/storage/concrete/pockets/small
|
||||
max_items = 1
|
||||
attack_hand_interact = FALSE
|
||||
|
||||
/datum/component/storage/concrete/pockets/tiny
|
||||
max_items = 1
|
||||
max_w_class = WEIGHT_CLASS_TINY
|
||||
attack_hand_interact = FALSE
|
||||
|
||||
/datum/component/storage/concrete/pockets/small/detective
|
||||
attack_hand_interact = TRUE // so the detectives would discover pockets in their hats
|
||||
|
||||
/datum/component/storage/concrete/pockets/shoes
|
||||
attack_hand_interact = FALSE
|
||||
quickdraw = TRUE
|
||||
silent = TRUE
|
||||
|
||||
/datum/component/storage/concrete/pockets/shoes/Initialize()
|
||||
. = ..()
|
||||
can_hold = typecacheof(list(
|
||||
/obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen,
|
||||
/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
|
||||
))
|
||||
|
||||
/datum/component/storage/concrete/pockets/shoes/clown/Initialize()
|
||||
. = ..()
|
||||
can_hold = typecacheof(list(
|
||||
/obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen,
|
||||
/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))
|
||||
|
||||
/datum/component/storage/concrete/pockets/pocketprotector
|
||||
max_items = 3
|
||||
max_w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
/datum/component/storage/concrete/pockets/pocketprotector/Initialize()
|
||||
. = ..()
|
||||
can_hold = typecacheof(list( //Same items as a PDA
|
||||
/obj/item/pen,
|
||||
/obj/item/toy/crayon,
|
||||
/obj/item/lipstick,
|
||||
/obj/item/device/flashlight/pen,
|
||||
/obj/item/clothing/mask/cigarette))
|
||||
@@ -0,0 +1,31 @@
|
||||
/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
|
||||
@@ -0,0 +1,5 @@
|
||||
/datum/component/storage/concrete/secret_satchel/can_be_inserted(I,msg,user)
|
||||
if(SSpersistence.spawned_objects[I])
|
||||
to_chat(user, "<span class='warning'>[I] is unstable after its journey through space and time, it wouldn't survive another trip.</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
@@ -0,0 +1,67 @@
|
||||
//Stack-only storage.
|
||||
/datum/component/storage/concrete/stack
|
||||
display_numerical_stacking = TRUE
|
||||
var/max_combined_stack_amount = 300
|
||||
max_w_class = WEIGHT_CLASS_NORMAL
|
||||
max_combined_w_class = WEIGHT_CLASS_NORMAL * 14
|
||||
|
||||
/datum/component/storage/concrete/stack/proc/total_stack_amount()
|
||||
. = 0
|
||||
var/atom/real_location = real_location()
|
||||
for(var/i in real_location)
|
||||
var/obj/item/stack/S = i
|
||||
if(!istype(S))
|
||||
continue
|
||||
. += S.amount
|
||||
|
||||
/datum/component/storage/concrete/stack/proc/remaining_space()
|
||||
return max(0, max_combined_stack_amount - total_stack_amount())
|
||||
|
||||
//emptying procs do not need modification as stacks automatically merge.
|
||||
|
||||
/datum/component/storage/concrete/stack/_insert_physical_item(obj/item/I, override = FALSE)
|
||||
if(!istype(I, /obj/item/stack))
|
||||
if(override)
|
||||
return ..()
|
||||
return FALSE
|
||||
var/atom/real_location = real_location()
|
||||
var/obj/item/stack/S = I
|
||||
var/can_insert = min(S.amount, remaining_space())
|
||||
if(!can_insert)
|
||||
return FALSE
|
||||
for(var/i in real_location) //combine.
|
||||
if(QDELETED(I))
|
||||
return
|
||||
var/obj/item/stack/_S = i
|
||||
if(!istype(_S))
|
||||
continue
|
||||
if(_S.merge_type == S.merge_type)
|
||||
_S.add(can_insert)
|
||||
S.use(can_insert, TRUE)
|
||||
return TRUE
|
||||
return ..(S.change_stack(null, can_insert), override)
|
||||
|
||||
/datum/component/storage/concrete/stack/remove_from_storage(obj/item/I, atom/new_location)
|
||||
var/atom/real_location = real_location()
|
||||
var/obj/item/stack/S = I
|
||||
if(!istype(S))
|
||||
return ..()
|
||||
if(S.amount > S.max_amount)
|
||||
var/overrun = S.amount - S.max_amount
|
||||
S.amount = S.max_amount
|
||||
var/obj/item/stack/temp = new S.type(real_location, overrun)
|
||||
handle_item_insertion(temp)
|
||||
return ..(S, new_location)
|
||||
|
||||
/datum/component/storage/concrete/stack/_process_numerical_display()
|
||||
var/atom/real_location = real_location()
|
||||
. = list()
|
||||
for(var/i in real_location)
|
||||
var/obj/item/stack/I = i
|
||||
if(!istype(I) || QDELETED(I)) //We're specialized stack storage, just ignore non stacks.
|
||||
continue
|
||||
if(!.[I.merge_type])
|
||||
.[I.merge_type] = new /datum/numbered_display(I, I.amount)
|
||||
else
|
||||
var/datum/numbered_display/ND = .[I.merge_type]
|
||||
ND.number += I.amount
|
||||
@@ -0,0 +1,730 @@
|
||||
#define COLLECT_ONE 0
|
||||
#define COLLECT_EVERYTHING 1
|
||||
#define COLLECT_SAME 2
|
||||
|
||||
#define DROP_NOTHING 0
|
||||
#define DROP_AT_PARENT 1
|
||||
#define DROP_AT_LOCATION 2
|
||||
|
||||
// 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
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
var/datum/component/storage/concrete/master //If not null, all actions act on master and this is just an access point.
|
||||
|
||||
var/list/can_hold //if this is set, only things in this typecache will fit.
|
||||
var/list/cant_hold //if this is set, anything in this typecache will not be able to fit.
|
||||
|
||||
var/list/mob/is_using //lazy list of mobs looking at the contents of this storage.
|
||||
|
||||
var/locked = FALSE //when locked nothing can see inside or use it.
|
||||
|
||||
var/max_w_class = WEIGHT_CLASS_SMALL //max size of objects that will fit.
|
||||
var/max_combined_w_class = 14 //max combined sizes of objects that will fit.
|
||||
var/max_items = 7 //max number of objects that will fit.
|
||||
|
||||
var/emp_shielded = FALSE
|
||||
|
||||
var/silent = FALSE //whether this makes a message when things are put in.
|
||||
var/click_gather = FALSE //whether this can be clicked on items to pick it up rather than the other way around.
|
||||
var/rustle_sound = TRUE //play rustle sound on interact.
|
||||
var/allow_quick_empty = FALSE //allow empty verb which allows dumping on the floor of everything inside quickly.
|
||||
var/allow_quick_gather = FALSE //allow toggle mob verb which toggles collecting all items from a tile.
|
||||
|
||||
var/collection_mode = COLLECT_EVERYTHING
|
||||
|
||||
var/insert_preposition = "in" //you put things "in" a bag, but "on" a tray.
|
||||
|
||||
var/display_numerical_stacking = FALSE //stack things of the same type and show as a single object with a number.
|
||||
|
||||
var/obj/screen/storage/boxes //storage display object
|
||||
var/obj/screen/close/closer //close button object
|
||||
|
||||
var/allow_big_nesting = FALSE //allow storage objects of the same or greater size.
|
||||
|
||||
var/attack_hand_interact = TRUE //interact on attack hand.
|
||||
var/quickdraw = FALSE //altclick interact
|
||||
|
||||
var/datum/action/item_action/storage_gather_mode/modeswitch_action
|
||||
|
||||
//Screen variables: Do not mess with these vars unless you know what you're doing. They're not defines so storage that isn't in the same location can be supported in the future.
|
||||
var/screen_max_columns = 7 //These two determine maximum screen sizes.
|
||||
var/screen_max_rows = INFINITY
|
||||
var/screen_pixel_x = 16 //These two are pixel values for screen loc of boxes and closer
|
||||
var/screen_pixel_y = 16
|
||||
var/screen_start_x = 4 //These two are where the storage starts being rendered, screen_loc wise.
|
||||
var/screen_start_y = 2
|
||||
//End
|
||||
|
||||
/datum/component/storage/Initialize(datum/component/storage/concrete/master)
|
||||
if(!isatom(parent))
|
||||
. = COMPONENT_INCOMPATIBLE
|
||||
if(master)
|
||||
change_master(master)
|
||||
boxes = new(null, src)
|
||||
closer = new(null, src)
|
||||
orient2hud()
|
||||
|
||||
RegisterSignal(COMSIG_CONTAINS_STORAGE, .proc/on_check)
|
||||
RegisterSignal(COMSIG_IS_STORAGE_LOCKED, .proc/check_locked)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_SHOW, .proc/signal_show_attempt)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_INSERT, .proc/signal_insertion_attempt)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_CAN_INSERT, .proc/signal_can_insert)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_TAKE_TYPE, .proc/signal_take_type)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_FILL_TYPE, .proc/signal_fill_type)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_SET_LOCKSTATE, .proc/set_locked)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_TAKE, .proc/signal_take_obj)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_QUICK_EMPTY, .proc/signal_quick_empty)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_HIDE_FROM, .proc/signal_hide_attempt)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_HIDE_ALL, .proc/close_all)
|
||||
RegisterSignal(COMSIG_TRY_STORAGE_RETURN_INVENTORY, .proc/signal_return_inv)
|
||||
|
||||
RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/attackby)
|
||||
|
||||
RegisterSignal(COMSIG_ATOM_ATTACK_HAND, .proc/on_attack_hand)
|
||||
RegisterSignal(COMSIG_ATOM_ATTACK_PAW, .proc/on_attack_hand)
|
||||
RegisterSignal(COMSIG_ATOM_EMP_ACT, .proc/emp_act)
|
||||
RegisterSignal(COMSIG_ATOM_ATTACK_GHOST, .proc/show_to_ghost)
|
||||
RegisterSignal(COMSIG_ATOM_EXITED, .proc/_removal_reset)
|
||||
|
||||
RegisterSignal(COMSIG_ITEM_PRE_ATTACK, .proc/preattack_intercept)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/attack_self)
|
||||
RegisterSignal(COMSIG_ITEM_PICKUP, .proc/signal_on_pickup)
|
||||
|
||||
RegisterSignal(COMSIG_MOVABLE_THROW, .proc/close_all)
|
||||
|
||||
RegisterSignal(COMSIG_CLICK_ALT, .proc/on_alt_click)
|
||||
RegisterSignal(COMSIG_MOUSEDROP_ONTO, .proc/mousedrop_onto)
|
||||
RegisterSignal(COMSIG_MOUSEDROPPED_ONTO, .proc/mousedrop_recieve)
|
||||
|
||||
update_actions()
|
||||
|
||||
/datum/component/storage/Destroy()
|
||||
close_all()
|
||||
QDEL_NULL(boxes)
|
||||
QDEL_NULL(closer)
|
||||
LAZYCLEARLIST(is_using)
|
||||
return ..()
|
||||
|
||||
/datum/component/storage/OnTransfer(datum/new_parent)
|
||||
update_actions()
|
||||
|
||||
/datum/component/storage/proc/update_actions()
|
||||
QDEL_NULL(modeswitch_action)
|
||||
if(!isitem(parent) || !allow_quick_gather)
|
||||
return
|
||||
var/obj/item/I = parent
|
||||
modeswitch_action = new(I)
|
||||
if(I.obj_flags & IN_INVENTORY)
|
||||
var/mob/M = I.loc
|
||||
if(!istype(M))
|
||||
return
|
||||
modeswitch_action.Grant(M)
|
||||
|
||||
/datum/component/storage/proc/change_master(datum/component/storage/concrete/new_master)
|
||||
if(!istype(new_master))
|
||||
return FALSE
|
||||
master.on_slave_unlink(src)
|
||||
master = new_master
|
||||
master.on_slave_link(src)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/master()
|
||||
if(master == src)
|
||||
return //infinite loops yo.
|
||||
return master
|
||||
|
||||
/datum/component/storage/proc/real_location()
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
return master? master.real_location() : null
|
||||
|
||||
/datum/component/storage/proc/attack_self(mob/M)
|
||||
if(locked)
|
||||
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
|
||||
return FALSE
|
||||
if((M.get_active_held_item() == parent) && allow_quick_empty)
|
||||
quick_empty(M)
|
||||
|
||||
/datum/component/storage/proc/preattack_intercept(obj/O, mob/M, params)
|
||||
if(!isitem(O) || !click_gather || O.SendSignal(COMSIG_CONTAINS_STORAGE))
|
||||
return FALSE
|
||||
. = COMPONENT_NO_ATTACK
|
||||
if(locked)
|
||||
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
|
||||
return FALSE
|
||||
var/obj/item/I = O
|
||||
if(collection_mode == COLLECT_ONE)
|
||||
if(can_be_inserted(I, null, M))
|
||||
handle_item_insertion(I, null, M)
|
||||
return
|
||||
if(!isturf(I.loc))
|
||||
return
|
||||
var/list/things = I.loc.contents.Copy()
|
||||
if(collection_mode == COLLECT_SAME)
|
||||
things = typecache_filter_list(things, typecacheof(I.type))
|
||||
var/len = length(things)
|
||||
if(!len)
|
||||
to_chat(M, "<span class='notice'>You failed to pick up anything with [parent].</span>")
|
||||
return
|
||||
var/datum/progressbar/progress = new(M, len, I.loc)
|
||||
var/list/rejections = list()
|
||||
while(do_after(M, 10, TRUE, parent, FALSE, CALLBACK(src, .proc/handle_mass_pickup, things, I.loc, rejections, progress)))
|
||||
stoplag(1)
|
||||
qdel(progress)
|
||||
to_chat(M, "<span class='notice'>You put everything you could [insert_preposition] [parent].</span>")
|
||||
|
||||
/datum/component/storage/proc/handle_mass_item_insertion(list/things, datum/component/storage/src_object, mob/user, datum/progressbar/progress)
|
||||
var/atom/source_real_location = src_object.real_location()
|
||||
for(var/obj/item/I in things)
|
||||
things -= I
|
||||
if(I.loc != source_real_location)
|
||||
continue
|
||||
if(user.active_storage != src_object)
|
||||
if(I.on_found(user))
|
||||
break
|
||||
if(can_be_inserted(I,FALSE,user))
|
||||
handle_item_insertion(I, TRUE, user)
|
||||
if (TICK_CHECK)
|
||||
progress.update(progress.goal - things.len)
|
||||
return TRUE
|
||||
|
||||
progress.update(progress.goal - things.len)
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/proc/handle_mass_pickup(list/things, atom/thing_loc, list/rejections, datum/progressbar/progress)
|
||||
var/atom/real_location = real_location()
|
||||
for(var/obj/item/I in things)
|
||||
things -= I
|
||||
if(I.loc != thing_loc)
|
||||
continue
|
||||
if(I.type in rejections) // To limit bag spamming: any given type only complains once
|
||||
continue
|
||||
if(!can_be_inserted(I, stop_messages = TRUE)) // Note can_be_inserted still makes noise when the answer is no
|
||||
if(real_location.contents.len >= max_items)
|
||||
break
|
||||
rejections += I.type // therefore full bags are still a little spammy
|
||||
continue
|
||||
|
||||
handle_item_insertion(I, TRUE) //The TRUE stops the "You put the [parent] into [S]" insertion message from being displayed.
|
||||
|
||||
if (TICK_CHECK)
|
||||
progress.update(progress.goal - things.len)
|
||||
return TRUE
|
||||
|
||||
progress.update(progress.goal - things.len)
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/proc/quick_empty(mob/M)
|
||||
var/atom/A = parent
|
||||
if((!ishuman(M) && (A.loc != M)) || (M.stat != CONSCIOUS) || M.restrained() || !M.canmove)
|
||||
return
|
||||
if(locked)
|
||||
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
|
||||
return FALSE
|
||||
A.add_fingerprint(M)
|
||||
to_chat(M, "<span class='notice'>You start dumping out [parent].</span>")
|
||||
var/turf/T = get_turf(A)
|
||||
var/list/things = contents()
|
||||
var/datum/progressbar/progress = new(M, length(things), T)
|
||||
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
|
||||
stoplag(1)
|
||||
qdel(progress)
|
||||
|
||||
/datum/component/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress)
|
||||
var/atom/real_location = real_location()
|
||||
for(var/obj/item/I in things)
|
||||
things -= I
|
||||
if(I.loc != real_location)
|
||||
continue
|
||||
remove_from_storage(I, target)
|
||||
if(TICK_CHECK)
|
||||
progress.update(progress.goal - length(things))
|
||||
return TRUE
|
||||
progress.update(progress.goal - length(things))
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/proc/do_quick_empty(atom/_target)
|
||||
if(!_target)
|
||||
_target = get_turf(parent)
|
||||
if(usr)
|
||||
hide_from(usr)
|
||||
var/list/contents = contents()
|
||||
var/atom/real_location = real_location()
|
||||
for(var/obj/item/I in contents)
|
||||
if(I.loc != real_location)
|
||||
continue
|
||||
remove_from_storage(I, _target)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/set_locked(new_state)
|
||||
locked = new_state
|
||||
if(locked)
|
||||
close_all()
|
||||
|
||||
/datum/component/storage/proc/_process_numerical_display()
|
||||
. = list()
|
||||
var/atom/real_location = real_location()
|
||||
for(var/obj/item/I in real_location.contents)
|
||||
if(QDELETED(I))
|
||||
continue
|
||||
if(!.[I.type])
|
||||
.[I.type] = new /datum/numbered_display(I, 1)
|
||||
else
|
||||
var/datum/numbered_display/ND = .[I.type]
|
||||
ND.number++
|
||||
|
||||
//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing.
|
||||
/datum/component/storage/proc/orient2hud()
|
||||
var/atom/real_location = real_location()
|
||||
var/adjusted_contents = real_location.contents.len
|
||||
|
||||
//Numbered contents display
|
||||
var/list/datum/numbered_display/numbered_contents
|
||||
if(display_numerical_stacking)
|
||||
numbered_contents = _process_numerical_display()
|
||||
adjusted_contents = numbered_contents.len
|
||||
|
||||
var/columns = CLAMP(max_items, 1, screen_max_columns)
|
||||
var/rows = CLAMP(CEILING(adjusted_contents / columns, 1), 1, screen_max_rows)
|
||||
standard_orient_objs(rows, columns, numbered_contents)
|
||||
|
||||
//This proc draws out the inventory and places the items on it. It uses the standard position.
|
||||
/datum/component/storage/proc/standard_orient_objs(rows, cols, list/obj/item/numerical_display_contents)
|
||||
boxes.screen_loc = "[screen_start_x]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y] to [screen_start_x+cols-1]:[screen_pixel_x],[screen_start_y+rows-1]:[screen_pixel_y]"
|
||||
var/cx = screen_start_x
|
||||
var/cy = screen_start_y
|
||||
if(islist(numerical_display_contents))
|
||||
for(var/type in numerical_display_contents)
|
||||
var/datum/numbered_display/ND = numerical_display_contents[type]
|
||||
ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
ND.sample_object.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
ND.sample_object.maptext = "<font color='white'>[(ND.number > 1)? "[ND.number]" : ""]</font>"
|
||||
ND.sample_object.layer = ABOVE_HUD_LAYER
|
||||
ND.sample_object.plane = ABOVE_HUD_PLANE
|
||||
cx++
|
||||
if(cx - screen_start_x >= cols)
|
||||
cx = screen_start_x
|
||||
cy++
|
||||
if(cy - screen_start_y >= rows)
|
||||
break
|
||||
else
|
||||
var/atom/real_location = real_location()
|
||||
for(var/obj/O in real_location)
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
|
||||
O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
|
||||
O.maptext = ""
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
cx++
|
||||
if(cx - screen_start_x >= cols)
|
||||
cx = screen_start_x
|
||||
cy++
|
||||
if(cy - screen_start_y >= rows)
|
||||
break
|
||||
closer.screen_loc = "[screen_start_x + cols]:[screen_pixel_x],[screen_start_y]:[screen_pixel_y]"
|
||||
|
||||
/datum/component/storage/proc/show_to(mob/M)
|
||||
if(!M.client)
|
||||
return FALSE
|
||||
var/atom/real_location = real_location()
|
||||
if(M.active_storage != src && (M.stat == CONSCIOUS))
|
||||
for(var/obj/item/I in real_location)
|
||||
if(I.on_found(M))
|
||||
return FALSE
|
||||
if(M.active_storage)
|
||||
M.active_storage.hide_from(M)
|
||||
orient2hud()
|
||||
M.client.screen |= boxes
|
||||
M.client.screen |= closer
|
||||
M.client.screen |= real_location.contents
|
||||
M.active_storage = src
|
||||
LAZYOR(is_using, M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/hide_from(mob/M)
|
||||
if(!M.client)
|
||||
return TRUE
|
||||
var/atom/real_location = real_location()
|
||||
M.client.screen -= boxes
|
||||
M.client.screen -= closer
|
||||
M.client.screen -= real_location.contents
|
||||
if(M.active_storage == src)
|
||||
M.active_storage = null
|
||||
LAZYREMOVE(is_using, M)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/close(mob/M)
|
||||
hide_from(M)
|
||||
|
||||
/datum/component/storage/proc/close_all()
|
||||
. = FALSE
|
||||
for(var/mob/M in can_see_contents())
|
||||
close(M)
|
||||
. = TRUE //returns TRUE if any mobs actually got a close(M) call
|
||||
|
||||
/datum/component/storage/proc/emp_act(severity)
|
||||
var/atom/A = parent
|
||||
if(!isliving(A.loc) && !emp_shielded)
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
master.emp_act(severity)
|
||||
|
||||
//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right.
|
||||
//The numbers are calculated from the bottom-left The bottom-left slot being 1,1.
|
||||
/datum/component/storage/proc/orient_objs(tx, ty, mx, my)
|
||||
var/atom/real_location = real_location()
|
||||
var/cx = tx
|
||||
var/cy = ty
|
||||
boxes.screen_loc = "[tx]:,[ty] to [mx],[my]"
|
||||
for(var/obj/O in real_location)
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.screen_loc = "[cx],[cy]"
|
||||
O.layer = ABOVE_HUD_LAYER
|
||||
O.plane = ABOVE_HUD_PLANE
|
||||
cx++
|
||||
if(cx > mx)
|
||||
cx = tx
|
||||
cy--
|
||||
closer.screen_loc = "[mx+1],[my]"
|
||||
|
||||
//Resets something that is being removed from storage.
|
||||
/datum/component/storage/proc/_removal_reset(atom/movable/thing)
|
||||
if(!istype(thing))
|
||||
return FALSE
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
if(!istype(master))
|
||||
return FALSE
|
||||
return master._removal_reset(thing)
|
||||
|
||||
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
|
||||
/datum/component/storage/proc/remove_from_storage(atom/movable/AM, atom/new_location)
|
||||
if(!istype(AM))
|
||||
return FALSE
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
if(!istype(master))
|
||||
return FALSE
|
||||
return master.remove_from_storage(AM, new_location)
|
||||
|
||||
/datum/component/storage/proc/refresh_mob_views()
|
||||
var/list/seeing = can_see_contents()
|
||||
for(var/i in seeing)
|
||||
show_to(i)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/can_see_contents()
|
||||
var/list/cansee = list()
|
||||
for(var/mob/M in is_using)
|
||||
if(M.active_storage == src && M.client)
|
||||
cansee |= M
|
||||
else
|
||||
LAZYREMOVE(is_using, M)
|
||||
return cansee
|
||||
|
||||
//Tries to dump content
|
||||
/datum/component/storage/proc/dump_content_at(atom/dest_object, mob/M)
|
||||
var/atom/A = parent
|
||||
var/atom/dump_destination = dest_object.get_dumping_location()
|
||||
if(A.Adjacent(M) && dump_destination && M.Adjacent(dump_destination))
|
||||
if(locked)
|
||||
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
|
||||
return FALSE
|
||||
if(dump_destination.storage_contents_dump_act(src, M))
|
||||
playsound(A, "rustle", 50, 1, -5)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
//This proc is called when you want to place an item into the storage item.
|
||||
/datum/component/storage/proc/attackby(obj/item/I, mob/M, params)
|
||||
if(istype(I, /obj/item/hand_labeler))
|
||||
var/obj/item/hand_labeler/labeler = I
|
||||
if(labeler.mode)
|
||||
return FALSE
|
||||
. = TRUE //no afterattack
|
||||
if(iscyborg(M))
|
||||
return
|
||||
if(!can_be_inserted(I, FALSE, M))
|
||||
var/atom/real_location = real_location()
|
||||
if(real_location.contents.len >= max_items) //don't use items on the backpack if they don't fit
|
||||
return TRUE
|
||||
return FALSE
|
||||
handle_item_insertion(I, FALSE, M)
|
||||
|
||||
/datum/component/storage/proc/return_inv()
|
||||
. = list()
|
||||
. += contents()
|
||||
for(var/i in contents())
|
||||
var/atom/a = i
|
||||
GET_COMPONENT_FROM(STR, /datum/component/storage, a)
|
||||
if(STR)
|
||||
. += STR.return_inv()
|
||||
|
||||
/datum/component/storage/proc/contents() //ONLY USE IF YOU NEED TO COPY CONTENTS OF REAL LOCATION, COPYING IS NOT AS FAST AS DIRECT ACCESS!
|
||||
var/atom/real_location = real_location()
|
||||
return real_location.contents.Copy()
|
||||
|
||||
/datum/component/storage/proc/signal_return_inv(list/interface)
|
||||
if(!islist(interface))
|
||||
return FALSE
|
||||
interface |= return_inv()
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/mousedrop_onto(atom/over_object, mob/M)
|
||||
set waitfor = FALSE
|
||||
. = COMPONENT_NO_MOUSEDROP
|
||||
var/atom/A = parent
|
||||
if(ismob(M)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked
|
||||
A.add_fingerprint(M)
|
||||
if(!over_object)
|
||||
return FALSE
|
||||
if(ismecha(M.loc)) // stops inventory actions in a mech
|
||||
return FALSE
|
||||
// this must come before the screen objects only block, dunno why it wasn't before
|
||||
if(over_object == M)
|
||||
user_show_to_mob(M)
|
||||
if(!M.incapacitated())
|
||||
if(!istype(over_object, /obj/screen))
|
||||
dump_content_at(over_object, M)
|
||||
return
|
||||
if(A.loc != M)
|
||||
return
|
||||
playsound(A, "rustle", 50, 1, -5)
|
||||
if(istype(over_object, /obj/screen/inventory/hand))
|
||||
var/obj/screen/inventory/hand/H = over_object
|
||||
M.putItemFromInventoryInHandIfPossible(A, H.held_index)
|
||||
return
|
||||
A.add_fingerprint(M)
|
||||
|
||||
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE)
|
||||
var/atom/A = parent
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
A.add_fingerprint(M)
|
||||
if(locked)
|
||||
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
|
||||
return FALSE
|
||||
if(M.CanReach(parent, view_only = TRUE))
|
||||
show_to(M)
|
||||
|
||||
/datum/component/storage/proc/mousedrop_recieve(atom/movable/O, mob/M)
|
||||
if(isitem(O))
|
||||
var/obj/item/I = O
|
||||
if(iscarbon(M) || isdrone(M))
|
||||
var/mob/living/L = M
|
||||
if(!L.incapacitated() && I == L.get_active_held_item())
|
||||
if(!I.SendSignal(COMSIG_CONTAINS_STORAGE) && can_be_inserted(I, FALSE)) //If it has storage it should be trying to dump, not insert.
|
||||
handle_item_insertion(I, FALSE, L)
|
||||
|
||||
//This proc return 1 if the item can be picked up and 0 if it can't.
|
||||
//Set the stop_messages to stop it from printing messages
|
||||
/datum/component/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
|
||||
if(!istype(I) || (I.flags_1 & ABSTRACT_1))
|
||||
return FALSE //Not an item
|
||||
var/atom/real_location = real_location()
|
||||
var/atom/parent = src.parent
|
||||
if(real_location == I.loc)
|
||||
return FALSE //Means the item is already in the storage item
|
||||
if(locked)
|
||||
if(M)
|
||||
parent.add_fingerprint(M)
|
||||
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
|
||||
return FALSE
|
||||
if(real_location.contents.len >= max_items)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] is full, make some space!</span>")
|
||||
return FALSE //Storage item is full
|
||||
if(length(can_hold))
|
||||
if(!is_type_in_typecache(I, can_hold))
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
if(is_type_in_typecache(I, cant_hold)) //Check for specific items which this container can't hold.
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[parent] cannot hold [I]!</span>")
|
||||
return FALSE
|
||||
if(I.w_class > max_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] is too big for [parent]!</span>")
|
||||
return FALSE
|
||||
var/sum_w_class = I.w_class
|
||||
for(var/obj/item/_I in real_location)
|
||||
sum_w_class += _I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it.
|
||||
if(sum_w_class > max_combined_w_class)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[I] won't fit in [parent], make some space!</span>")
|
||||
return FALSE
|
||||
if(isitem(parent))
|
||||
var/obj/item/IP = parent
|
||||
GET_COMPONENT_FROM(STR_I, /datum/component/storage, I)
|
||||
if((I.w_class >= IP.w_class) && STR_I && !allow_big_nesting)
|
||||
if(!stop_messages)
|
||||
to_chat(M, "<span class='warning'>[IP] cannot hold [I] as it's a storage item of the same size!</span>")
|
||||
return FALSE //To prevent the stacking of same sized storage items.
|
||||
if(I.flags_1 & NODROP_1) //SHOULD be handled in unEquip, but better safe than sorry.
|
||||
to_chat(M, "<span class='warning'>\the [I] is stuck to your hand, you can't put it in \the [parent]!</span>")
|
||||
return FALSE
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
if(!istype(master))
|
||||
return FALSE
|
||||
return master.slave_can_insert_object(src, I, stop_messages, M)
|
||||
|
||||
/datum/component/storage/proc/_insert_physical_item(obj/item/I, override = FALSE)
|
||||
return FALSE
|
||||
|
||||
//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted()
|
||||
//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once,
|
||||
//such as when picking up all the items on a tile with one click.
|
||||
/datum/component/storage/proc/handle_item_insertion(obj/item/I, prevent_warning = FALSE, mob/M, datum/component/storage/remote)
|
||||
var/atom/parent = src.parent
|
||||
var/datum/component/storage/concrete/master = master()
|
||||
if(!istype(master))
|
||||
return FALSE
|
||||
if(silent)
|
||||
prevent_warning = TRUE
|
||||
if(M)
|
||||
parent.add_fingerprint(M)
|
||||
. = master.handle_item_insertion_from_slave(src, I, prevent_warning, M)
|
||||
|
||||
/datum/component/storage/proc/mob_item_insertion_feedback(mob/user, mob/M, obj/item/I, override = FALSE)
|
||||
if(silent && !override)
|
||||
return
|
||||
if(rustle_sound)
|
||||
playsound(parent, "rustle", 50, 1, -5)
|
||||
for(var/mob/viewing in viewers(user, null))
|
||||
if(M == viewing)
|
||||
to_chat(usr, "<span class='notice'>You put [I] [insert_preposition]to [parent].</span>")
|
||||
else if(in_range(M, viewing)) //If someone is standing close enough, they can tell what it is...
|
||||
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", 1)
|
||||
else if(I && I.w_class >= 3) //Otherwise they can only see large or normal items from a distance...
|
||||
viewing.show_message("<span class='notice'>[M] puts [I] [insert_preposition]to [parent].</span>", 1)
|
||||
|
||||
/datum/component/storage/proc/update_icon()
|
||||
if(isobj(parent))
|
||||
var/obj/O = parent
|
||||
O.update_icon()
|
||||
|
||||
/datum/component/storage/proc/signal_insertion_attempt(obj/item/I, mob/M, silent = FALSE, force = FALSE)
|
||||
if(!force && !can_be_inserted(I, TRUE, M))
|
||||
return FALSE
|
||||
return handle_item_insertion(I, silent, M)
|
||||
|
||||
/datum/component/storage/proc/signal_can_insert(obj/item/I, mob/M, silent = FALSE)
|
||||
return can_be_inserted(I, silent, M)
|
||||
|
||||
/datum/component/storage/proc/show_to_ghost(mob/dead/observer/M)
|
||||
return user_show_to_mob(M, TRUE)
|
||||
|
||||
/datum/component/storage/proc/signal_show_attempt(mob/showto, force = FALSE)
|
||||
return user_show_to_mob(showto, force)
|
||||
|
||||
/datum/component/storage/proc/on_check()
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/check_locked()
|
||||
return locked
|
||||
|
||||
/datum/component/storage/proc/signal_take_type(type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted)
|
||||
if(!force)
|
||||
if(check_adjacent)
|
||||
if(user)
|
||||
if(!user.CanReach(destination) || !user.CanReach(parent))
|
||||
return FALSE
|
||||
else if(!destination.CanReachStorage(parent))
|
||||
return FALSE
|
||||
var/list/taking = typecache_filter_list(contents(), typecacheof(type))
|
||||
if(length(taking) > amount)
|
||||
taking.Cut(amount)
|
||||
if(inserted) //duplicated code for performance, don't bother checking retval/checking for list every item.
|
||||
for(var/i in taking)
|
||||
if(remove_from_storage(i, destination))
|
||||
inserted |= i
|
||||
else
|
||||
for(var/i in taking)
|
||||
remove_from_storage(i, destination)
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/remaining_space_items()
|
||||
var/atom/real_location = real_location()
|
||||
return max(0, max_items - real_location.contents.len)
|
||||
|
||||
/datum/component/storage/proc/signal_fill_type(type, amount = 20, force = FALSE)
|
||||
var/atom/real_location = real_location()
|
||||
if(!force)
|
||||
amount = min(remaining_space_items(), amount)
|
||||
for(var/i in 1 to amount)
|
||||
handle_item_insertion(new type(real_location), TRUE)
|
||||
CHECK_TICK
|
||||
return TRUE
|
||||
|
||||
/datum/component/storage/proc/on_attack_hand(mob/user)
|
||||
var/atom/A = parent
|
||||
if(!attack_hand_interact)
|
||||
return
|
||||
if(user.active_storage == src && A.loc == user) //if you're already looking inside the storage item
|
||||
user.active_storage.close(user)
|
||||
close(user)
|
||||
. = COMPONENT_NO_ATTACK_HAND
|
||||
return
|
||||
|
||||
if(rustle_sound)
|
||||
playsound(A, "rustle", 50, 1, -5)
|
||||
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.l_store == A && !H.get_active_held_item()) //Prevents opening if it's in a pocket.
|
||||
. = COMPONENT_NO_ATTACK_HAND
|
||||
H.put_in_hands(A)
|
||||
H.l_store = null
|
||||
return
|
||||
if(H.r_store == A && !H.get_active_held_item())
|
||||
. = COMPONENT_NO_ATTACK_HAND
|
||||
H.put_in_hands(A)
|
||||
H.r_store = null
|
||||
return
|
||||
|
||||
if(A.loc == user)
|
||||
. = COMPONENT_NO_ATTACK_HAND
|
||||
show_to(user)
|
||||
|
||||
/datum/component/storage/proc/signal_on_pickup(mob/user)
|
||||
var/atom/A = parent
|
||||
update_actions()
|
||||
for(var/mob/M in range(1, A))
|
||||
if(M.active_storage == src)
|
||||
close(M)
|
||||
|
||||
/datum/component/storage/proc/signal_take_obj(atom/movable/AM, new_loc, force = FALSE)
|
||||
if(!(AM in real_location()))
|
||||
return FALSE
|
||||
return remove_from_storage(AM, new_loc)
|
||||
|
||||
/datum/component/storage/proc/signal_quick_empty(atom/loctarget)
|
||||
return do_quick_empty(loctarget)
|
||||
|
||||
/datum/component/storage/proc/signal_hide_attempt(mob/target)
|
||||
return hide_from(target)
|
||||
|
||||
/datum/component/storage/proc/on_alt_click(mob/user)
|
||||
if(!isliving(user) || user.incapacitated() || !quickdraw || !user.CanReach(parent))
|
||||
return
|
||||
var/obj/item/I = locate() in real_location()
|
||||
if(!I)
|
||||
return
|
||||
remove_from_storage(I, get_turf(user))
|
||||
if(!user.put_in_hands(I))
|
||||
to_chat(user, "<span class='notice'>You fumble for [I] and it falls on the floor.</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] draws [I] from [parent]!</span>", "<span class='notice'>You draw [I] from [parent].</span>")
|
||||
|
||||
/datum/component/storage/proc/gather_mode_switch(mob/user)
|
||||
collection_mode = (collection_mode+1)%3
|
||||
switch(collection_mode)
|
||||
if(COLLECT_SAME)
|
||||
to_chat(user, "[parent] now picks up all items of a single type at once.")
|
||||
if(COLLECT_EVERYTHING)
|
||||
to_chat(user, "[parent] now picks up all items in a tile at once.")
|
||||
if(COLLECT_ONE)
|
||||
to_chat(user, "[parent] now picks up one item at a time.")
|
||||
@@ -17,6 +17,14 @@
|
||||
if(HasDisease(D))
|
||||
return FALSE
|
||||
|
||||
var/can_infect = FALSE
|
||||
for(var/host_type in D.infectable_biotypes)
|
||||
if(host_type in mob_biotypes)
|
||||
can_infect = TRUE
|
||||
break
|
||||
if(!can_infect)
|
||||
return FALSE
|
||||
|
||||
if(!(type in D.viable_mobtypes))
|
||||
return FALSE
|
||||
|
||||
@@ -132,14 +140,6 @@
|
||||
if(has_trait(TRAIT_VIRUSIMMUNE) && !D.bypasses_immunity)
|
||||
return FALSE
|
||||
|
||||
var/can_infect = FALSE
|
||||
for(var/host_type in D.infectable_hosts)
|
||||
if(host_type in dna.species.species_traits)
|
||||
can_infect = TRUE
|
||||
break
|
||||
if(!can_infect)
|
||||
return FALSE
|
||||
|
||||
for(var/thing in D.required_organs)
|
||||
if(!((locate(thing) in bodyparts) || (locate(thing) in internal_organs)))
|
||||
return FALSE
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
var/list/required_organs = list()
|
||||
var/needs_all_cures = TRUE
|
||||
var/list/strain_data = list() //dna_spread special bullshit
|
||||
var/list/infectable_hosts = list(SPECIES_ORGANIC) //if the disease can spread on organics, synthetics, or undead
|
||||
var/list/infectable_biotypes = list(MOB_ORGANIC) //if the disease can spread on organics, synthetics, or undead
|
||||
var/process_dead = FALSE //if this ticks while the host is dead
|
||||
|
||||
/datum/disease/Destroy()
|
||||
@@ -139,7 +139,7 @@
|
||||
var/static/list/copy_vars = list("name", "visibility_flags", "disease_flags", "spread_flags", "form", "desc", "agent", "spread_text",
|
||||
"cure_text", "max_stages", "stage_prob", "viable_mobtypes", "cures", "infectivity", "cure_chance",
|
||||
"bypasses_immunity", "permeability_mod", "severity", "required_organs", "needs_all_cures", "strain_data",
|
||||
"infectable_hosts", "process_dead")
|
||||
"infectable_biotypes", "process_dead")
|
||||
|
||||
var/datum/disease/D = new type()
|
||||
for(var/V in copy_vars)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
if(!..())
|
||||
return
|
||||
A.process_dead = TRUE
|
||||
A.infectable_hosts |= SPECIES_UNDEAD
|
||||
A.infectable_biotypes |= MOB_UNDEAD
|
||||
|
||||
/datum/symptom/inorganic_adaptation
|
||||
name = "Inorganic Biology"
|
||||
@@ -27,4 +27,4 @@
|
||||
/datum/symptom/inorganic_adaptation/Start(datum/disease/advance/A)
|
||||
if(!..())
|
||||
return
|
||||
A.infectable_hosts |= SPECIES_INORGANIC
|
||||
A.infectable_biotypes |= MOB_INORGANIC
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
//////////////////////////////////////
|
||||
|
||||
Weakness
|
||||
|
||||
Slightly noticeable.
|
||||
Lowers resistance slightly.
|
||||
Decreases stage speed moderately.
|
||||
Decreases transmittablity moderately.
|
||||
Moderate Level.
|
||||
|
||||
Bonus
|
||||
Deals stamina damage to the host
|
||||
|
||||
//////////////////////////////////////
|
||||
*/
|
||||
|
||||
/datum/symptom/weakness
|
||||
|
||||
name = "Weakness"
|
||||
stealth = -1
|
||||
resistance = -1
|
||||
stage_speed = -2
|
||||
transmittable = -2
|
||||
level = 3
|
||||
severity = 3
|
||||
|
||||
/datum/symptom/weakness/Activate(datum/disease/advance/A)
|
||||
..()
|
||||
if(prob(SYMPTOM_ACTIVATION_PROB))
|
||||
var/mob/living/M = A.affected_mob
|
||||
switch(A.stage)
|
||||
if(1, 2)
|
||||
to_chat(M, "<span class='warning'>[pick("You feel weak.", "You feel lazy.")]</span>")
|
||||
if(3, 4)
|
||||
to_chat(M, "<span class='warning'><b>[pick("You feel very frail.", "You think you might faint.")]</span>")
|
||||
M.adjustStaminaLoss(15)
|
||||
else
|
||||
to_chat(M, "<span class='userdanger'>[pick("You feel tremendously weak!", "Your body trembles as exhaustion creeps over you.")]</span>")
|
||||
M.adjustStaminaLoss(30)
|
||||
if(M.getStaminaLoss() > 60 && !M.stat)
|
||||
M.visible_message("<span class='warning'>[M] faints!</span>", "<span class='userdanger'>You swoon and faint...</span>")
|
||||
M.AdjustSleeping(100)
|
||||
return
|
||||
@@ -10,7 +10,7 @@
|
||||
viable_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
|
||||
desc = "If left untreated subject will regurgitate bees."
|
||||
severity = DISEASE_SEVERITY_MEDIUM
|
||||
infectable_hosts = list(SPECIES_ORGANIC, SPECIES_UNDEAD) //bees nesting in corpses
|
||||
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD) //bees nesting in corpses
|
||||
|
||||
/datum/disease/beesease/stage_act()
|
||||
..()
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
permeability_mod = 0.75
|
||||
desc = "This disease disrupts the magnetic field of your body, making it act as if a powerful magnet. Injections of iron help stabilize the field."
|
||||
severity = DISEASE_SEVERITY_MEDIUM
|
||||
infectable_hosts = list(SPECIES_ORGANIC, SPECIES_ROBOTIC)
|
||||
infectable_biotypes = list(MOB_ORGANIC, MOB_ROBOTIC)
|
||||
process_dead = TRUE
|
||||
|
||||
/datum/disease/magnitis/stage_act()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
viable_mobtypes = list(/mob/living/carbon/human)
|
||||
desc = "Subject is possesed by the vengeful spirit of a parrot. Call the priest."
|
||||
severity = DISEASE_SEVERITY_MEDIUM
|
||||
infectable_hosts = list(SPECIES_ORGANIC, SPECIES_UNDEAD, SPECIES_INORGANIC, SPECIES_ROBOTIC)
|
||||
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD, MOB_INORGANIC, MOB_ROBOTIC)
|
||||
bypasses_immunity = TRUE //2spook
|
||||
var/mob/living/simple_animal/parrot/Poly/ghost/parrot
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
stage4 = list("<span class='danger'>Your skin feels very loose.</span>", "<span class='danger'>You can feel... something...inside you.</span>")
|
||||
stage5 = list("<span class='danger'>Your skin feels as if it's about to burst off!</span>")
|
||||
new_form = /mob/living/silicon/robot
|
||||
infectable_hosts = list(SPECIES_ORGANIC, SPECIES_UNDEAD, SPECIES_ROBOTIC)
|
||||
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD, MOB_ROBOTIC)
|
||||
|
||||
/datum/disease/transformation/robot/stage_act()
|
||||
..()
|
||||
@@ -263,4 +263,4 @@
|
||||
stage4 = list("<span class='danger'>You're ravenous.</span>")
|
||||
stage5 = list("<span class='danger'>You have become a morph.</span>")
|
||||
new_form = /mob/living/simple_animal/hostile/morph
|
||||
infectable_hosts = list(SPECIES_ORGANIC, SPECIES_INORGANIC, SPECIES_UNDEAD) //magic!
|
||||
infectable_biotypes = list(MOB_ORGANIC, MOB_INORGANIC, MOB_UNDEAD) //magic!
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
/datum/mood_event/Destroy()
|
||||
remove_effects()
|
||||
return ..()
|
||||
|
||||
/datum/mood_event/proc/add_effects(param)
|
||||
return
|
||||
|
||||
@@ -56,13 +56,13 @@ GLOBAL_LIST_EMPTY(mutations_list)
|
||||
|
||||
/datum/mutation/human/proc/on_acquiring(mob/living/carbon/human/owner)
|
||||
if(!owner || !istype(owner) || owner.stat == DEAD || (src in owner.dna.mutations))
|
||||
return 1
|
||||
return TRUE
|
||||
if(species_allowed.len && !species_allowed.Find(owner.dna.species.id))
|
||||
return 1
|
||||
return TRUE
|
||||
if(health_req && owner.health < health_req)
|
||||
return 1
|
||||
return TRUE
|
||||
if(limb_req && !owner.get_bodypart(limb_req))
|
||||
return 1
|
||||
return TRUE
|
||||
owner.dna.mutations.Add(src)
|
||||
if(text_gain_indication)
|
||||
to_chat(owner, text_gain_indication)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//Used in storage.
|
||||
/datum/numbered_display
|
||||
var/obj/item/sample_object
|
||||
var/number
|
||||
|
||||
/datum/numbered_display/New(obj/item/sample, _number = 1)
|
||||
if(!istype(sample))
|
||||
qdel(src)
|
||||
sample_object = sample
|
||||
number = _number
|
||||
@@ -21,6 +21,20 @@
|
||||
mappath = "[prefix][shuttle_id].dmm"
|
||||
. = ..()
|
||||
|
||||
/datum/map_template/shuttle/load(turf/T, centered)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
var/list/turfs = block( locate(.[MAP_MINX], .[MAP_MINY], .[MAP_MINZ]),
|
||||
locate(.[MAP_MAXX], .[MAP_MAXY], .[MAP_MAXZ]))
|
||||
for(var/i in 1 to turfs.len)
|
||||
var/turf/place = turfs[i]
|
||||
if(istype(place, /turf/open/space)) // This assumes all shuttles are loaded in a single spot then moved to their real destination.
|
||||
continue
|
||||
if(length(place.baseturfs) < 2) // Some snowflake shuttle shit
|
||||
continue
|
||||
place.baseturfs.Insert(3, /turf/baseturf_skipover/shuttle)
|
||||
|
||||
//Whatever special stuff you want
|
||||
/datum/map_template/shuttle/proc/on_bought()
|
||||
return
|
||||
@@ -60,7 +74,21 @@
|
||||
port_id = "infiltrator"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/aux_base
|
||||
port_id = "aux_base"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/escape_pod
|
||||
port_id = "escape_pod"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/assault_pod
|
||||
port_id = "assault_pod"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/pirate
|
||||
port_id = "pirate"
|
||||
can_be_bought = FALSE
|
||||
|
||||
// Shuttles start here:
|
||||
|
||||
@@ -355,3 +383,27 @@
|
||||
/datum/map_template/shuttle/arrival/pubby
|
||||
suffix = "pubby"
|
||||
name = "arrival shuttle (Pubby)"
|
||||
|
||||
/datum/map_template/shuttle/arrival/omega
|
||||
suffix = "omega"
|
||||
name = "arrival shuttle (Omega)"
|
||||
|
||||
/datum/map_template/shuttle/aux_base/default
|
||||
suffix = "default"
|
||||
name = "auxilliary base (Default)"
|
||||
|
||||
/datum/map_template/shuttle/escape_pod/default
|
||||
suffix = "default"
|
||||
name = "escape pod (Default)"
|
||||
|
||||
/datum/map_template/shuttle/escape_pod/large
|
||||
suffix = "large"
|
||||
name = "escape pod (Large)"
|
||||
|
||||
/datum/map_template/shuttle/assault_pod/default
|
||||
suffix = "default"
|
||||
name = "assault pod (Default)"
|
||||
|
||||
/datum/map_template/shuttle/pirate/default
|
||||
suffix = "default"
|
||||
name = "pirate ship (Default)"
|
||||
|
||||
@@ -53,9 +53,7 @@
|
||||
if(!where)
|
||||
where = "at your feet"
|
||||
if(where == "in your backpack")
|
||||
var/obj/item/storage/B = H.back
|
||||
B.orient2hud(trait_holder)
|
||||
B.show_to(trait_holder)
|
||||
H.back.SendSignal(COMSIG_TRY_STORAGE_SHOW, H)
|
||||
where_text = "<span class='boldnotice'>There is a precious family [heirloom.name] [where], passed down from generation to generation. Keep it safe!</span>"
|
||||
|
||||
/datum/trait/family_heirloom/post_add()
|
||||
|
||||
Reference in New Issue
Block a user