mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 15:17:01 +01:00
Renews Maintenance Drones (#58249)
It's the second try! (First: #48456) Drones are little robots inspired by Keepers from the Mass Effect games. With laws to maintain both the station, and their distance from the matters of others, they were a great ghost role that let you fix up the station when you were otherwise out of the round. They were in the game for quite a while, but were abused. The abusive players completely ignored the laws and did whatever they wanted. Being tiny ventcrawlers, this became a huge issue for admins. I attempted to bring them back, this time with some gameplay restrictions to enforce their laws a bit better. It seemed to go well, but I required headmin approval, and this all happened near a headmin election, so the project died. Recently, some people have wanted to bring drones back. So, they gave me a ring, and I started a discussion with the admin team to see what other changes they would want in addition to the previous ones. Here are those changes: They can't interact at all when close to another being, living or dead Their binary chat has been removed to separate them from AI and borgs They can only hold a whitelist of items necessary to do their job They can only interact with machines necessary to do their job The drone satchel is gone, and drones now have built in basic tools They also can't interact in some blacklisted high risk areas Finally, you must play 40 hours total as a Silicon role in order to play as a drone Additionally, the drone dispenser is not mapped, and the drones must be researched to be constructed. Why It's Good For The Game Drones are a fun way to pass the time, and this time they have a lot less freedom. You can still perform the basic function of maintaining the station, but not without difficulty and tedium. This will allow other station roles to perform much better than the drones, while still letting them chug along at their slower pace.
This commit is contained in:
+46700
-46654
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+34451
-34434
File diff suppressed because it is too large
Load Diff
+1176
-1170
File diff suppressed because it is too large
Load Diff
+1450
-1443
File diff suppressed because it is too large
Load Diff
@@ -290,8 +290,15 @@
|
||||
#define COMSIG_LIVING_START_PULL "living_start_pull"
|
||||
///called on /living when someone is pulled (mob/living/puller)
|
||||
#define COMSIG_LIVING_GET_PULLED "living_start_pulled"
|
||||
///called on /living, when pull is attempted, but before it completes, from base of [/mob/living/start_pulling]: (atom/movable/thing, force)
|
||||
#define COMSIG_LIVING_TRY_PULL "living_try_pull"
|
||||
#define COMSIG_LIVING_CANCEL_PULL (1 << 0)
|
||||
///from base of [/atom/proc/interact]: (mob/user)
|
||||
#define COMSIG_ATOM_UI_INTERACT "atom_ui_interact"
|
||||
///called on /living when attempting to pick up an item, from base of /mob/living/put_in_hand_check(): (obj/item/I)
|
||||
#define COMSIG_LIVING_TRY_PUT_IN_HAND "living_try_put_in_hand"
|
||||
/// Can't pick up
|
||||
#define COMPONENT_LIVING_CANT_PUT_IN_HAND (1<<0)
|
||||
|
||||
/// from /datum/component/singularity/proc/can_move(), as well as /obj/energy_ball/proc/can_move()
|
||||
/// if a callback returns `SINGULARITY_TRY_MOVE_BLOCK`, then the singularity will not move to that turf
|
||||
@@ -575,6 +582,15 @@
|
||||
///from end of fully_heal(): (admin_revive)
|
||||
#define COMSIG_LIVING_POST_FULLY_HEAL "living_post_fully_heal"
|
||||
|
||||
///Called on user, from base of /datum/strippable_item/try_(un)equip() (atom/target, obj/item/equipping?)
|
||||
///also from /mob/living/stripPanel(Un)equip)()
|
||||
#define COMSIG_TRY_STRIP "try_strip"
|
||||
#define COMPONENT_CANT_STRIP (1<<0)
|
||||
|
||||
///Called on user, from base of /datum/strippable_item/alternate_action() (atom/target)
|
||||
#define COMSIG_TRY_ALT_ACTION "try_alt_action"
|
||||
#define COMPONENT_CANT_ALT_ACTION (1<<0)
|
||||
|
||||
///From /datum/component/creamed/Initialize()
|
||||
#define COMSIG_MOB_CREAMED "mob_creamed"
|
||||
///From /obj/item/gun/proc/check_botched()
|
||||
@@ -669,6 +685,10 @@
|
||||
///from /obj/machinery/computer/arcade/prizevend(mob/user, prizes = 1)
|
||||
#define COMSIG_ARCADE_PRIZEVEND "arcade_prizevend"
|
||||
|
||||
///from /obj/machinery/can_interact(mob/user): Called on user when attempting to interact with a machine (obj/machinery/machine)
|
||||
#define COMSIG_TRY_USE_MACHINE "try_use_machine"
|
||||
#define COMPONENT_CANT_USE_MACHINE (1<<0)
|
||||
|
||||
///from obj/machinery/iv_drip/IV_attach(target, usr) : (attachee)
|
||||
#define COMSIG_IV_ATTACH "iv_attach"
|
||||
///from obj/machinery/iv_drip/IV_detach() : (detachee)
|
||||
@@ -701,6 +721,9 @@
|
||||
|
||||
///from base of obj/item/equipped(): (/mob/equipper, slot)
|
||||
#define COMSIG_ITEM_EQUIPPED "item_equip"
|
||||
///called on [/obj/item] before unequip from base of [mob/proc/doUnEquip]: (force, atom/newloc, no_move, invdrop, silent)
|
||||
#define COMSIG_ITEM_PRE_UNEQUIP "item_pre_unequip"
|
||||
#define COMPONENT_ITEM_BLOCK_UNEQUIP (1<<0)
|
||||
///from base of obj/item/on_grind(): ())
|
||||
#define COMSIG_ITEM_ON_GRIND "on_grind"
|
||||
///from base of obj/item/on_juice(): ()
|
||||
@@ -1166,9 +1189,11 @@
|
||||
#define COMSIG_MOB_CTRL_CLICKED "mob_ctrl_clicked"
|
||||
///From base of mob/update_movespeed():area
|
||||
#define COMSIG_MOB_MOVESPEED_UPDATED "mob_update_movespeed"
|
||||
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
|
||||
///(NOT on humans) from mob/living/*/UnarmedAttack(): (atom/target, proximity, modifiers)
|
||||
#define COMSIG_LIVING_UNARMED_ATTACK "living_unarmed_attack"
|
||||
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers)
|
||||
#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
|
||||
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
|
||||
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers)
|
||||
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack"
|
||||
|
||||
|
||||
|
||||
@@ -594,6 +594,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// Self-explainatory.
|
||||
#define BEAUTY_ELEMENT_TRAIT "beauty_element"
|
||||
#define MOOD_COMPONENT_TRAIT "mood_component"
|
||||
#define DRONE_SHY_TRAIT "drone_shy"
|
||||
|
||||
/**
|
||||
* Trait granted by [/mob/living/carbon/Initialize] and
|
||||
|
||||
+50
-37
@@ -1,3 +1,14 @@
|
||||
/// Checks for RIGHT_CLICK in modifiers and runs attack_hand_secondary if so. Returns TRUE if normal chain blocked
|
||||
/mob/living/proc/right_click_attack_chain(atom/target, list/modifiers)
|
||||
if (!LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
return
|
||||
var/secondary_result = target.attack_hand_secondary(src, modifiers)
|
||||
|
||||
if (secondary_result == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || secondary_result == SECONDARY_ATTACK_CONTINUE_CHAIN)
|
||||
return TRUE
|
||||
else if (secondary_result != SECONDARY_ATTACK_CALL_NORMAL)
|
||||
CRASH("attack_hand_secondary did not return a SECONDARY_ATTACK_* define.")
|
||||
|
||||
/*
|
||||
Humans:
|
||||
Adds an exception for gloves, to allow special glove types like the ninja ones.
|
||||
@@ -32,15 +43,10 @@
|
||||
if(dna?.species?.spec_unarmedattack(src, A, modifiers)) //Because species like monkeys dont use attack hand
|
||||
return
|
||||
|
||||
if (LAZYACCESS(modifiers, RIGHT_CLICK))
|
||||
var/secondary_result = A.attack_hand_secondary(src, modifiers)
|
||||
if(!right_click_attack_chain(A, modifiers))
|
||||
A.attack_hand(src, modifiers)
|
||||
|
||||
if (secondary_result == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || secondary_result == SECONDARY_ATTACK_CONTINUE_CHAIN)
|
||||
return
|
||||
else if (secondary_result != SECONDARY_ATTACK_CALL_NORMAL)
|
||||
CRASH("attack_hand_secondary did not return a SECONDARY_ATTACK_* define.")
|
||||
|
||||
A.attack_hand(src, modifiers)
|
||||
|
||||
/// Return TRUE to cancel other attack hand effects that respect it. Modifiers is the assoc list for click info such as if it was a right click.
|
||||
/atom/proc/attack_hand(mob/user, list/modifiers)
|
||||
@@ -114,10 +120,15 @@
|
||||
/*
|
||||
Animals & All Unspecified
|
||||
*/
|
||||
/mob/living/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
|
||||
// If the UnarmedAttack chain is blocked
|
||||
#define LIVING_UNARMED_ATTACK_BLOCKED(target_atom) (HAS_TRAIT(src, TRAIT_HANDS_BLOCKED) \
|
||||
|| SEND_SIGNAL(src, COMSIG_LIVING_UNARMED_ATTACK, target_atom, proximity_flag, modifiers) & COMPONENT_CANCEL_ATTACK_CHAIN)
|
||||
|
||||
/mob/living/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
A.attack_animal(src, modifiers)
|
||||
attack_target.attack_animal(src, modifiers)
|
||||
|
||||
/atom/proc/attack_animal(mob/user, list/modifiers)
|
||||
SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_ANIMAL, user)
|
||||
@@ -133,10 +144,10 @@
|
||||
Aliens
|
||||
Defaults to same as monkey in most places
|
||||
*/
|
||||
/mob/living/carbon/alien/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
/mob/living/carbon/alien/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
A.attack_alien(src, modifiers)
|
||||
attack_target.attack_alien(src, modifiers)
|
||||
|
||||
/atom/proc/attack_alien(mob/living/carbon/alien/user, list/modifiers)
|
||||
attack_paw(user, modifiers)
|
||||
@@ -144,10 +155,10 @@
|
||||
|
||||
|
||||
// Babby aliens
|
||||
/mob/living/carbon/alien/larva/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
/mob/living/carbon/alien/larva/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
A.attack_larva(src)
|
||||
attack_target.attack_larva(src)
|
||||
|
||||
/atom/proc/attack_larva(mob/user)
|
||||
return
|
||||
@@ -157,12 +168,12 @@
|
||||
Slimes
|
||||
Nothing happening here
|
||||
*/
|
||||
/mob/living/simple_animal/slime/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
/mob/living/simple_animal/slime/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
if(isturf(A))
|
||||
if(isturf(attack_target))
|
||||
return ..()
|
||||
A.attack_slime(src)
|
||||
attack_target.attack_slime(src)
|
||||
|
||||
/atom/proc/attack_slime(mob/user)
|
||||
return
|
||||
@@ -171,20 +182,22 @@
|
||||
/*
|
||||
Drones
|
||||
*/
|
||||
/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
/mob/living/simple_animal/drone/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
A.attack_drone(src)
|
||||
attack_target.attack_drone(src, modifiers)
|
||||
|
||||
/atom/proc/attack_drone(mob/living/simple_animal/drone/user)
|
||||
attack_hand(user) //defaults to attack_hand. Override it when you don't want drones to do same stuff as humans.
|
||||
/// Defaults to attack_hand or attack_hand_secondary. Override it when you don't want drones to do same stuff as humans.
|
||||
/atom/proc/attack_drone(mob/living/simple_animal/drone/user, list/modifiers)
|
||||
if(!user.right_click_attack_chain(src, modifiers))
|
||||
attack_hand(user, modifiers)
|
||||
|
||||
|
||||
/*
|
||||
Brain
|
||||
*/
|
||||
|
||||
/mob/living/brain/UnarmedAttack(atom/A, proximity_flag, list/modifiers)//Stops runtimes due to attack_animal being the default
|
||||
/mob/living/brain/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)//Stops runtimes due to attack_animal being the default
|
||||
return
|
||||
|
||||
|
||||
@@ -192,7 +205,7 @@
|
||||
pAI
|
||||
*/
|
||||
|
||||
/mob/living/silicon/pai/UnarmedAttack(atom/A, proximity_flag, list/modifiers)//Stops runtimes due to attack_animal being the default
|
||||
/mob/living/silicon/pai/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)//Stops runtimes due to attack_animal being the default
|
||||
return
|
||||
|
||||
|
||||
@@ -200,11 +213,11 @@
|
||||
Simple animals
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
/mob/living/simple_animal/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
if(dextrous && (isitem(A) || !combat_mode))
|
||||
A.attack_hand(src, modifiers)
|
||||
if(dextrous && (isitem(attack_target) || !combat_mode))
|
||||
attack_target.attack_hand(src, modifiers)
|
||||
update_inv_hands()
|
||||
else
|
||||
return ..()
|
||||
@@ -214,16 +227,16 @@
|
||||
Hostile animals
|
||||
*/
|
||||
|
||||
/mob/living/simple_animal/hostile/UnarmedAttack(atom/A, proximity_flag, list/modifiers)
|
||||
if(HAS_TRAIT(src, TRAIT_HANDS_BLOCKED))
|
||||
/mob/living/simple_animal/hostile/UnarmedAttack(atom/attack_target, proximity_flag, list/modifiers)
|
||||
if(LIVING_UNARMED_ATTACK_BLOCKED(attack_target))
|
||||
return
|
||||
target = A
|
||||
if(dextrous && (isitem(A) || !combat_mode))
|
||||
target = attack_target
|
||||
if(dextrous && (isitem(attack_target) || !combat_mode))
|
||||
..()
|
||||
else
|
||||
AttackingTarget(A)
|
||||
|
||||
AttackingTarget(attack_target)
|
||||
|
||||
#undef LIVING_UNARMED_ATTACK_BLOCKED
|
||||
|
||||
/*
|
||||
New Players:
|
||||
|
||||
@@ -405,3 +405,11 @@
|
||||
min_val = 0
|
||||
|
||||
/datum/config_entry/flag/dynamic_config_enabled
|
||||
|
||||
/datum/config_entry/string/drone_required_role
|
||||
config_entry_value = "Silicon"
|
||||
|
||||
/datum/config_entry/number/drone_role_playtime
|
||||
config_entry_value = 40
|
||||
min_val = 0
|
||||
integer = FALSE // It is in hours, but just in case one wants to specify minutes.
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/** Holder Loving Component
|
||||
*
|
||||
* This component is assigned to an [/obj/item], and also keeps track of a [holder].
|
||||
* The [parent] is 'bound' to [holder]. [parent] will be kept either directly
|
||||
* inside [holder], or in the inventory of a [/mob] that is itself holding [holder].
|
||||
*
|
||||
* If [parent] is placed in a [loc] that is not [holder] or [holder].[loc]
|
||||
* (if it's a mob), it is placed back inside [holder].
|
||||
*
|
||||
* This is intended for items that are a 'part' of another item.
|
||||
*
|
||||
* It can also delete [parent] when [holder] is deleted.
|
||||
*
|
||||
*/
|
||||
/datum/component/holderloving
|
||||
can_transfer = TRUE
|
||||
/** Item that parent is bound to.
|
||||
* We try to keep parent either directly in holder, or in holder's loc if loc is a mob,
|
||||
* and warp parent into holder if they go anywhere else.
|
||||
*/
|
||||
var/atom/holder
|
||||
/// If parent is deleted when the holder gets deleted
|
||||
var/del_parent_with_holder = FALSE
|
||||
|
||||
/datum/component/holderloving/Initialize(holder, del_parent_with_holder)
|
||||
if(!isitem(parent) || !holder)
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.holder = holder
|
||||
if(del_parent_with_holder)
|
||||
src.del_parent_with_holder = del_parent_with_holder
|
||||
|
||||
/datum/component/holderloving/RegisterWithParent()
|
||||
RegisterSignal(holder, COMSIG_MOVABLE_MOVED, .proc/check_my_loc)
|
||||
RegisterSignal(holder, COMSIG_PARENT_QDELETING, .proc/holder_deleting)
|
||||
RegisterSignal(parent, list(
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_ITEM_EQUIPPED,
|
||||
COMSIG_STORAGE_ENTERED,
|
||||
COMSIG_STORAGE_EXITED,
|
||||
), .proc/check_my_loc)
|
||||
|
||||
/datum/component/holderloving/UnregisterFromParent()
|
||||
UnregisterSignal(holder, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_ITEM_EQUIPPED,
|
||||
COMSIG_STORAGE_ENTERED,
|
||||
COMSIG_STORAGE_EXITED,
|
||||
))
|
||||
|
||||
/datum/component/holderloving/PostTransfer()
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/holderloving/InheritComponent(datum/component/holderloving/friend, i_am_original, list/arguments)
|
||||
if(i_am_original)
|
||||
holder = friend.holder
|
||||
|
||||
/datum/component/holderloving/proc/check_valid_loc(atom/location)
|
||||
return (location == holder || ( location == holder.loc && ismob(holder.loc) ))
|
||||
|
||||
/datum/component/holderloving/proc/holder_deleting(datum/source, force)
|
||||
SIGNAL_HANDLER
|
||||
if(del_parent_with_holder)
|
||||
qdel(parent)
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/datum/component/holderloving/proc/check_my_loc(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
var/obj/item/item_parent = parent
|
||||
if(!check_valid_loc(item_parent.loc))
|
||||
item_parent.forceMove(holder)
|
||||
@@ -0,0 +1,35 @@
|
||||
/// You can only hold whitelisted items
|
||||
/datum/component/itempicky
|
||||
can_transfer = TRUE
|
||||
/// Typecache of items you can hold
|
||||
var/whitelist
|
||||
/// Message shown if you try to pick up an item not in the whitelist
|
||||
var/message = "You don't like %TARGET, why would you hold it?"
|
||||
|
||||
/datum/component/itempicky/Initialize(whitelist, message)
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.whitelist = whitelist
|
||||
if(message)
|
||||
src.message = message
|
||||
|
||||
/datum/component/itempicky/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_LIVING_TRY_PUT_IN_HAND, .proc/particularly)
|
||||
|
||||
/datum/component/itempicky/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_LIVING_TRY_PUT_IN_HAND)
|
||||
|
||||
/datum/component/itempicky/PostTransfer()
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/itempicky/InheritComponent(datum/component/itempicky/friend, i_am_original, list/arguments)
|
||||
if(i_am_original)
|
||||
whitelist = friend.whitelist
|
||||
message = friend.message
|
||||
|
||||
/datum/component/itempicky/proc/particularly(datum/source, obj/item/pickingup)
|
||||
SIGNAL_HANDLER
|
||||
if(!is_type_in_typecache(pickingup, whitelist))
|
||||
to_chat(source, "<span class='warning'>[replacetext(message, "%TARGET", pickingup)]</span>")
|
||||
return COMPONENT_LIVING_CANT_PUT_IN_HAND
|
||||
@@ -0,0 +1,103 @@
|
||||
#define SHY_COMPONENT_CACHE_TIME 0.5 SECONDS
|
||||
|
||||
/// You can't use items on anyone other than yourself if there are other living mobs around you
|
||||
/datum/component/shy
|
||||
can_transfer = TRUE
|
||||
/// How close you are before you get shy
|
||||
var/shy_range = 4
|
||||
/// Typecache of mob types you are okay around
|
||||
var/list/whitelist
|
||||
/// Message shown when you are is_shy
|
||||
var/message = "You find yourself too shy to do that around %TARGET!"
|
||||
/// Are you shy around a dead body?
|
||||
var/dead_shy = FALSE
|
||||
/// Invalidate last_result at this time
|
||||
COOLDOWN_DECLARE(result_cooldown)
|
||||
/// What was our last result?
|
||||
var/last_result = FALSE
|
||||
|
||||
/datum/component/shy/Initialize(whitelist, shy_range, message, dead_shy)
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.whitelist = whitelist
|
||||
if(shy_range)
|
||||
src.shy_range = shy_range
|
||||
if(message)
|
||||
src.message = message
|
||||
if(dead_shy)
|
||||
src.dead_shy = dead_shy
|
||||
|
||||
/datum/component/shy/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOB_CLICKON, .proc/on_clickon)
|
||||
RegisterSignal(parent, COMSIG_LIVING_TRY_PULL, .proc/on_try_pull)
|
||||
RegisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK), .proc/on_unarmed_attack)
|
||||
RegisterSignal(parent, COMSIG_TRY_STRIP, .proc/on_try_strip)
|
||||
RegisterSignal(parent, COMSIG_TRY_ALT_ACTION, .proc/on_try_alt_action)
|
||||
|
||||
/datum/component/shy/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_MOB_CLICKON,
|
||||
COMSIG_LIVING_TRY_PULL,
|
||||
COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK,
|
||||
COMSIG_TRY_STRIP,
|
||||
COMSIG_TRY_ALT_ACTION,
|
||||
))
|
||||
|
||||
/datum/component/shy/PostTransfer()
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/shy/InheritComponent(datum/component/shy/friend, i_am_original, list/arguments)
|
||||
if(i_am_original)
|
||||
shy_range = friend.shy_range
|
||||
whitelist = friend.whitelist
|
||||
message = friend.message
|
||||
|
||||
/// Returns TRUE or FALSE if you are within shy_range tiles from a /mob/living
|
||||
/datum/component/shy/proc/is_shy(atom/target)
|
||||
var/result = FALSE
|
||||
var/mob/owner = parent
|
||||
|
||||
if(target in owner.DirectAccess())
|
||||
return
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, result_cooldown))
|
||||
return last_result
|
||||
|
||||
var/list/strangers = view(shy_range, get_turf(owner))
|
||||
|
||||
if(length(strangers) && locate(/mob/living) in strangers)
|
||||
for(var/mob/living/person in strangers)
|
||||
if(person != owner && !is_type_in_typecache(person, whitelist) && (person.stat != DEAD || dead_shy))
|
||||
to_chat(owner, "<span class='warning'>[replacetext(message, "%TARGET", person)]</span>")
|
||||
result = TRUE
|
||||
break
|
||||
|
||||
last_result = result
|
||||
COOLDOWN_START(src, result_cooldown, SHY_COMPONENT_CACHE_TIME)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
/datum/component/shy/proc/on_clickon(datum/source, atom/target, params)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMSIG_MOB_CANCEL_CLICKON
|
||||
|
||||
/datum/component/shy/proc/on_try_pull(datum/source, atom/movable/target, force)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMSIG_LIVING_CANCEL_PULL
|
||||
|
||||
/datum/component/shy/proc/on_unarmed_attack(datum/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/component/shy/proc/on_try_strip(datum/source, atom/target, obj/item/equipping)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMPONENT_CANT_STRIP
|
||||
|
||||
/datum/component/shy/proc/on_try_alt_action(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMPONENT_CANT_ALT_ACTION
|
||||
|
||||
#undef SHY_COMPONENT_CACHE_TIME
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/// You can't use items on anyone other than yourself if you stand in a blacklisted room
|
||||
/datum/component/shy_in_room
|
||||
can_transfer = TRUE
|
||||
/// Typecache of areas you can't stand
|
||||
var/list/blacklist
|
||||
/// Message shown when you are in a blacklisted room
|
||||
var/message = "%ROOM is too creepy to do that!"
|
||||
|
||||
/// _blacklist, and _message map to vars
|
||||
/datum/component/shy_in_room/Initialize(blacklist, message)
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.blacklist = blacklist
|
||||
if(message)
|
||||
src.message = message
|
||||
|
||||
/datum/component/shy_in_room/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOB_CLICKON, .proc/on_clickon)
|
||||
RegisterSignal(parent, COMSIG_LIVING_TRY_PULL, .proc/on_try_pull)
|
||||
RegisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HUMAN_EARLY_UNARMED_ATTACK), .proc/on_unarmed_attack)
|
||||
RegisterSignal(parent, COMSIG_TRY_STRIP, .proc/on_try_strip)
|
||||
RegisterSignal(parent, COMSIG_TRY_ALT_ACTION, .proc/on_try_alt_action)
|
||||
|
||||
|
||||
/datum/component/shy_in_room/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(
|
||||
COMSIG_MOB_CLICKON,
|
||||
COMSIG_LIVING_TRY_PULL,
|
||||
COMSIG_LIVING_UNARMED_ATTACK,
|
||||
COMSIG_HUMAN_EARLY_UNARMED_ATTACK,
|
||||
COMSIG_TRY_STRIP,
|
||||
COMSIG_TRY_ALT_ACTION,
|
||||
))
|
||||
|
||||
/datum/component/shy_in_room/PostTransfer()
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/shy_in_room/InheritComponent(datum/component/shy_in_room/friend, i_am_original, list/arguments)
|
||||
if(i_am_original)
|
||||
blacklist = friend.blacklist
|
||||
message = friend.message
|
||||
|
||||
/// Returns TRUE or FALSE if you are in a blacklisted area
|
||||
/datum/component/shy_in_room/proc/is_shy(atom/target)
|
||||
var/mob/owner = parent
|
||||
if(!length(blacklist) || (target in owner.DirectAccess()))
|
||||
return
|
||||
|
||||
var/area/room = get_area(owner)
|
||||
if(is_type_in_typecache(room, blacklist))
|
||||
to_chat(owner, "<span class='warning'>[replacetext(message, "%ROOM", room)]</span>")
|
||||
return TRUE
|
||||
|
||||
/datum/component/shy_in_room/proc/on_clickon(datum/source, atom/target, params)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMSIG_MOB_CANCEL_CLICKON
|
||||
|
||||
/datum/component/shy_in_room/proc/on_try_pull(datum/source, atom/movable/target, force)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMSIG_LIVING_CANCEL_PULL
|
||||
|
||||
/datum/component/shy_in_room/proc/on_unarmed_attack(datum/source, atom/target, proximity, modifiers)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/datum/component/shy_in_room/proc/on_try_strip(datum/source, atom/target, obj/item/equipping)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMPONENT_CANT_STRIP
|
||||
|
||||
/datum/component/shy_in_room/proc/on_try_alt_action(datum/source, atom/target)
|
||||
SIGNAL_HANDLER
|
||||
return is_shy(target) && COMPONENT_CANT_ALT_ACTION
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/// You can't use machines unless they are in a whitelist
|
||||
/datum/component/technointrovert
|
||||
can_transfer = TRUE
|
||||
/// Typecache of allowed machinery
|
||||
var/list/whitelist
|
||||
/// Message presented when
|
||||
var/message = "That %TARGET is strange! Let's avoid it."
|
||||
|
||||
/datum/component/technointrovert/Initialize(whitelist, message)
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.whitelist = whitelist
|
||||
if(message)
|
||||
src.message = message
|
||||
|
||||
/datum/component/technointrovert/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_TRY_USE_MACHINE, .proc/is_in_whitelist)
|
||||
|
||||
/datum/component/technointrovert/UnregisterFromParent()
|
||||
UnregisterSignal(parent, COMSIG_TRY_USE_MACHINE)
|
||||
|
||||
/datum/component/technointrovert/PostTransfer()
|
||||
if(!ismob(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/technointrovert/InheritComponent(datum/component/technointrovert/friend, i_am_original, list/arguments)
|
||||
if(i_am_original)
|
||||
whitelist = friend.whitelist
|
||||
message = friend.message
|
||||
|
||||
/datum/component/technointrovert/proc/is_in_whitelist(datum/source, obj/machinery/machine)
|
||||
SIGNAL_HANDLER
|
||||
if(!is_type_in_typecache(machine, whitelist))
|
||||
to_chat(source, "<span class='warning'>[replacetext(message, "%TARGET", machine)]</span>")
|
||||
return COMPONENT_CANT_USE_MACHINE
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
/// This should be used for checking if an item CAN be equipped.
|
||||
/// It should not perform the equipping itself.
|
||||
/datum/strippable_item/proc/try_equip(atom/source, obj/item/equipping, mob/user)
|
||||
if(SEND_SIGNAL(user, COMSIG_TRY_STRIP, source, equipping) & COMPONENT_CANT_STRIP)
|
||||
return FALSE
|
||||
if (HAS_TRAIT(equipping, TRAIT_NODROP))
|
||||
to_chat(user, "<span class='warning'>You can't put [equipping] on [source], it's stuck to your hand!</span>")
|
||||
return FALSE
|
||||
@@ -128,6 +130,8 @@
|
||||
return FALSE
|
||||
|
||||
if (ismob(source))
|
||||
if(SEND_SIGNAL(user, COMSIG_TRY_STRIP, source, item) & COMPONENT_CANT_STRIP)
|
||||
return FALSE
|
||||
var/mob/mob_source = source
|
||||
if (!item.canStrip(user, mob_source))
|
||||
return FALSE
|
||||
@@ -177,7 +181,12 @@
|
||||
|
||||
/// Performs an alternative action on this strippable_item.
|
||||
/// `has_alternate_action` needs to be TRUE.
|
||||
/// Returns FALSE if blocked by signal, TRUE otherwise.
|
||||
/datum/strippable_item/proc/alternate_action(atom/source, mob/user)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(SEND_SIGNAL(user, COMSIG_TRY_ALT_ACTION, source) & COMPONENT_CANT_ALT_ACTION)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// Returns whether or not this item should show.
|
||||
/datum/strippable_item/proc/should_show(atom/source, mob/user)
|
||||
|
||||
@@ -846,6 +846,11 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
|
||||
sound_environment = SOUND_AREA_SMALL_ENCLOSED
|
||||
|
||||
/area/engineering/supermatter/room
|
||||
name = "Supermatter Engine Room"
|
||||
icon_state = "engine_sm_room"
|
||||
sound_environment = SOUND_AREA_LARGE_ENCLOSED
|
||||
|
||||
/area/engineering/break_room
|
||||
name = "Engineering Foyer"
|
||||
icon_state = "engine_break"
|
||||
|
||||
@@ -342,6 +342,9 @@
|
||||
if(!isliving(user))
|
||||
return FALSE //no ghosts in the machine allowed, sorry
|
||||
|
||||
if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE)
|
||||
return FALSE
|
||||
|
||||
var/mob/living/living_user = user
|
||||
|
||||
var/is_dextrous = FALSE
|
||||
@@ -352,7 +355,7 @@
|
||||
|
||||
if(!issilicon(user) && !is_dextrous && !user.can_hold_items())
|
||||
return FALSE //spiders gtfo
|
||||
|
||||
|
||||
if(issilicon(user)) // If we are a silicon, make sure the machine allows silicons to interact with it
|
||||
if(!(interaction_flags_machine & INTERACT_MACHINE_ALLOW_SILICON))
|
||||
return FALSE
|
||||
@@ -477,6 +480,8 @@
|
||||
/obj/machinery/_try_interact(mob/user)
|
||||
if((interaction_flags_machine & INTERACT_MACHINE_WIRES_IF_OPEN) && panel_open && (attempt_wire_interaction(user) == WIRE_INTERACTION_BLOCK))
|
||||
return TRUE
|
||||
if(SEND_SIGNAL(user, COMSIG_TRY_USE_MACHINE, src) & COMPONENT_CANT_USE_MACHINE)
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/machinery/CheckParts(list/parts_list)
|
||||
|
||||
@@ -96,6 +96,12 @@
|
||||
starting_amount = 0
|
||||
cooldownTime = 600
|
||||
|
||||
/obj/machinery/drone_dispenser/classic
|
||||
name = "classic drone shell dispenser"
|
||||
desc = "A hefty machine that, when supplied with iron and glass, will periodically create a classic drone shell. Does not need to be manually operated."
|
||||
dispense_type = /obj/effect/mob_spawn/drone/classic
|
||||
end_create_message = "dispenses a classic drone shell."
|
||||
|
||||
// An example of a custom drone dispenser.
|
||||
// This one requires no materials and creates basic hivebots
|
||||
/obj/machinery/drone_dispenser/hivebot
|
||||
|
||||
@@ -481,7 +481,7 @@
|
||||
while(length(candidates) && teamsize)
|
||||
chosen_candidate = pick(candidates)
|
||||
candidates -= chosen_candidate
|
||||
nerd = new /mob/living/simple_animal/drone(spawnpoint)
|
||||
nerd = new /mob/living/simple_animal/drone/classic(spawnpoint)
|
||||
nerd.key = chosen_candidate.key
|
||||
log_game("[key_name(nerd)] has been selected as a Nanotrasen emergency response drone")
|
||||
teamsize--
|
||||
|
||||
@@ -244,8 +244,7 @@ Key procs
|
||||
/datum/language/narsie = list(LANGUAGE_ATOM))
|
||||
|
||||
/datum/language_holder/drone
|
||||
understood_languages = list(/datum/language/drone = list(LANGUAGE_ATOM),
|
||||
/datum/language/machine = list(LANGUAGE_ATOM))
|
||||
understood_languages = list(/datum/language/drone = list(LANGUAGE_ATOM))
|
||||
spoken_languages = list(/datum/language/drone = list(LANGUAGE_ATOM))
|
||||
blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
|
||||
|
||||
|
||||
@@ -186,7 +186,8 @@
|
||||
return FALSE //nonliving mobs don't have hands
|
||||
|
||||
/mob/living/put_in_hand_check(obj/item/I)
|
||||
if(istype(I) && ((mobility_flags & MOBILITY_PICKUP) || (I.item_flags & ABSTRACT)))
|
||||
if(istype(I) && ((mobility_flags & MOBILITY_PICKUP) || (I.item_flags & ABSTRACT)) \
|
||||
&& !(SEND_SIGNAL(src, COMSIG_LIVING_TRY_PUT_IN_HAND, I) & COMPONENT_LIVING_CANT_PUT_IN_HAND))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -306,6 +307,9 @@
|
||||
if(HAS_TRAIT(I, TRAIT_NODROP) && !force)
|
||||
return FALSE
|
||||
|
||||
if((SEND_SIGNAL(I, COMSIG_ITEM_PRE_UNEQUIP, force, newloc, no_move, invdrop, silent) & COMPONENT_ITEM_BLOCK_UNEQUIP) && !force)
|
||||
return FALSE
|
||||
|
||||
var/hand_index = get_held_index_of_item(I)
|
||||
if(hand_index)
|
||||
held_items[hand_index] = null
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
return get_strippable_alternate_action_internals(get_item(source), source)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/back/alternate_action(atom/source, mob/user)
|
||||
return strippable_alternate_action_internals(get_item(source), source, user)
|
||||
if(!..())
|
||||
return
|
||||
strippable_alternate_action_internals(get_item(source), source, user)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/mask
|
||||
key = STRIPPABLE_ITEM_MASK
|
||||
|
||||
@@ -52,6 +52,8 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list(
|
||||
return jumpsuit?.can_adjust ? "adjust_jumpsuit" : null
|
||||
|
||||
/datum/strippable_item/mob_item_slot/jumpsuit/alternate_action(atom/source, mob/user)
|
||||
if (!..())
|
||||
return
|
||||
var/obj/item/clothing/under/jumpsuit = get_item(source)
|
||||
if (!istype(jumpsuit))
|
||||
return null
|
||||
@@ -94,6 +96,8 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list(
|
||||
return "unknot"
|
||||
|
||||
/datum/strippable_item/mob_item_slot/feet/alternate_action(atom/source, mob/user)
|
||||
if(!..())
|
||||
return
|
||||
var/obj/item/clothing/shoes/shoes = get_item(source)
|
||||
if (!istype(shoes))
|
||||
return
|
||||
@@ -108,7 +112,9 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list(
|
||||
return get_strippable_alternate_action_internals(get_item(source), source)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/suit_storage/alternate_action(atom/source, mob/user)
|
||||
return strippable_alternate_action_internals(get_item(source), source, user)
|
||||
if (!..())
|
||||
return
|
||||
strippable_alternate_action_internals(get_item(source), source, user)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/id
|
||||
key = STRIPPABLE_ITEM_ID
|
||||
@@ -122,7 +128,9 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list(
|
||||
return get_strippable_alternate_action_internals(get_item(source), source)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/belt/alternate_action(atom/source, mob/user)
|
||||
return strippable_alternate_action_internals(get_item(source), source, user)
|
||||
if (!..())
|
||||
return
|
||||
strippable_alternate_action_internals(get_item(source), source, user)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/pocket
|
||||
/// Which pocket we're referencing. Used for visible text.
|
||||
|
||||
@@ -263,6 +263,8 @@
|
||||
return FALSE
|
||||
if(throwing || !(mobility_flags & MOBILITY_PULL))
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(src, COMSIG_LIVING_TRY_PULL, AM, force) & COMSIG_LIVING_CANCEL_PULL)
|
||||
return FALSE
|
||||
|
||||
AM.add_fingerprint(src)
|
||||
|
||||
@@ -990,6 +992,8 @@
|
||||
// The src mob is trying to strip an item from someone
|
||||
// Override if a certain type of mob should be behave differently when stripping items (can't, for example)
|
||||
/mob/living/stripPanelUnequip(obj/item/what, mob/who, where)
|
||||
if(SEND_SIGNAL(src, COMSIG_TRY_STRIP, who, what) & COMPONENT_CANT_STRIP)
|
||||
return
|
||||
if(!what.canStrip(who))
|
||||
to_chat(src, "<span class='warning'>You can't remove \the [what.name], it appears to be stuck!</span>")
|
||||
return
|
||||
@@ -1016,7 +1020,9 @@
|
||||
// Override if a certain mob should be behave differently when placing items (can't, for example)
|
||||
/mob/living/stripPanelEquip(obj/item/what, mob/who, where)
|
||||
what = src.get_active_held_item()
|
||||
if(what && (HAS_TRAIT(what, TRAIT_NODROP)))
|
||||
if(!what || (SEND_SIGNAL(src, COMSIG_TRY_STRIP, who, what) & COMPONENT_CANT_STRIP))
|
||||
return
|
||||
if(HAS_TRAIT(what, TRAIT_NODROP))
|
||||
to_chat(src, "<span class='warning'>You can't put \the [what.name] on [who], it's stuck to your hand!</span>")
|
||||
return
|
||||
if(what)
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
/// Headwear slot
|
||||
var/obj/item/head
|
||||
/// Default [/mob/living/simple_animal/drone/var/internal_storage] item
|
||||
var/obj/item/default_storage = /obj/item/storage/backpack/duffelbag/drone
|
||||
var/obj/item/default_storage = /obj/item/storage/drone_tools
|
||||
/// Default [/mob/living/simple_animal/drone/var/head] item
|
||||
var/obj/item/default_hatmask
|
||||
/**
|
||||
@@ -111,6 +111,8 @@
|
||||
var/visualAppearance = MAINTDRONE
|
||||
/// Hacked state, see [/mob/living/simple_animal/drone/proc/update_drone_hack]
|
||||
var/hacked = FALSE
|
||||
/// If we have laws to minimize bothering others. Enables or disables drone laws enforcement components (use [/mob/living/simple_animal/drone/proc/set_shy] to set)
|
||||
var/shy = TRUE
|
||||
/// Flavor text announced to drones on [/mob/proc/Login]
|
||||
var/flavortext = \
|
||||
"\n<big><span class='warning'>DO NOT INTERFERE WITH THE ROUND AS A DRONE OR YOU WILL BE DRONE BANNED</span></big>\n"+\
|
||||
@@ -121,6 +123,52 @@
|
||||
"<span class='notice'> - Interacting with non-living beings (dragging bodies, looting bodies, etc.)</span>\n"+\
|
||||
"<span class='warning'>These rules are at admin discretion and will be heavily enforced.</span>\n"+\
|
||||
"<span class='warning'><u>If you do not have the regular drone laws, follow your laws to the best of your ability.</u></span>"
|
||||
/// blacklisted drone areas, direct
|
||||
var/list/drone_area_blacklist_flat = list(/area/engineering/atmos, /area/engineering/atmospherics_engine)
|
||||
/// blacklisted drone areas, recursive/includes descendants
|
||||
var/list/drone_area_blacklist_recursive = list(/area/engineering/supermatter)
|
||||
/// whitelisted drone machines, direct
|
||||
var/list/drone_machinery_whitelist_flat
|
||||
/// whitelisted drone machines, recursive/includes descendants
|
||||
var/list/drone_machinery_whitelist_recursive = list(
|
||||
/obj/machinery/atmospherics,
|
||||
/obj/machinery/autolathe,
|
||||
/obj/machinery/cell_charger,
|
||||
/obj/machinery/disposal,
|
||||
/obj/machinery/drone_dispenser,
|
||||
/obj/machinery/light,
|
||||
/obj/machinery/pipedispenser,
|
||||
/obj/machinery/recharger,
|
||||
/obj/machinery/rnd/production,
|
||||
)
|
||||
/// whitelisted drone items, direct
|
||||
var/list/drone_item_whitelist_flat = list(
|
||||
/obj/item/crowbar/drone,
|
||||
/obj/item/screwdriver/drone,
|
||||
/obj/item/wrench/drone,
|
||||
/obj/item/weldingtool/drone,
|
||||
/obj/item/wirecutters/drone,
|
||||
)
|
||||
/// whitelisted drone items, recursive/includes descendants
|
||||
var/list/drone_item_whitelist_recursive = list(
|
||||
/obj/item/airlock_painter,
|
||||
/obj/item/circuitboard,
|
||||
/obj/item/conveyor_switch_construct,
|
||||
/obj/item/electronics,
|
||||
/obj/item/light,
|
||||
/obj/item/pipe_meter,
|
||||
/obj/item/stack/cable_coil,
|
||||
/obj/item/stack/circuit_stack,
|
||||
/obj/item/stack/conveyor,
|
||||
/obj/item/stack/pipe_cleaner_coil,
|
||||
/obj/item/stack/rods,
|
||||
/obj/item/stack/sheet,
|
||||
/obj/item/stack/tile,
|
||||
/obj/item/stock_parts,
|
||||
/obj/item/toner,
|
||||
/obj/item/clothing/head,
|
||||
/obj/item/clothing/mask,
|
||||
)
|
||||
|
||||
/mob/living/simple_animal/drone/Initialize()
|
||||
. = ..()
|
||||
@@ -140,6 +188,8 @@
|
||||
|
||||
ADD_TRAIT(access_card, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
|
||||
|
||||
shy_update()
|
||||
|
||||
alert_drones(DRONE_NET_CONNECT)
|
||||
|
||||
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
|
||||
@@ -274,7 +324,7 @@
|
||||
for(var/areaname in our_sort)
|
||||
if (areaname == home.name)
|
||||
var/list/alarm = our_sort[areaname]
|
||||
var/list/sources = alarm[3]
|
||||
var/list/sources = alarm[2]
|
||||
if (!(source in sources))
|
||||
sources += source
|
||||
return TRUE
|
||||
@@ -310,6 +360,30 @@
|
||||
if(cleared)
|
||||
to_chat(src, "--- [class] alarm in [A.name] has been cleared.")
|
||||
|
||||
/mob/living/simple_animal/drone/proc/set_shy(new_shy)
|
||||
shy = new_shy
|
||||
shy_update()
|
||||
|
||||
/mob/living/simple_animal/drone/proc/shy_update()
|
||||
var/list/drone_bad_areas = make_associative(drone_area_blacklist_flat) + typecacheof(drone_area_blacklist_recursive)
|
||||
var/list/drone_good_machines = make_associative(drone_machinery_whitelist_flat) + typecacheof(drone_machinery_whitelist_recursive)
|
||||
var/list/drone_good_items = make_associative(drone_item_whitelist_flat) + typecacheof(drone_item_whitelist_recursive)
|
||||
if(shy)
|
||||
ADD_TRAIT(src, TRAIT_PACIFISM, DRONE_SHY_TRAIT)
|
||||
LoadComponent(/datum/component/shy, typecacheof(/mob/living/simple_animal/drone), 4, "Your laws prevent this action near %TARGET.", TRUE)
|
||||
LoadComponent(/datum/component/shy_in_room, drone_bad_areas, "Touching anything in %ROOM could break your laws.")
|
||||
LoadComponent(/datum/component/technointrovert, drone_good_machines, "Using %TARGET could break your laws.")
|
||||
LoadComponent(/datum/component/itempicky, drone_good_items, "Using %TARGET could break your laws.")
|
||||
else
|
||||
REMOVE_TRAIT(src, TRAIT_PACIFISM, DRONE_SHY_TRAIT)
|
||||
qdel(GetComponent(/datum/component/shy))
|
||||
qdel(GetComponent(/datum/component/shy_in_room))
|
||||
qdel(GetComponent(/datum/component/technointrovert))
|
||||
qdel(GetComponent(/datum/component/itempicky))
|
||||
|
||||
/mob/living/simple_animal/drone/handle_temperature_damage()
|
||||
return
|
||||
|
||||
/mob/living/simple_animal/drone/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /atom/movable/screen/fullscreen/flash, length = 25)
|
||||
if(affect_silicon)
|
||||
return ..()
|
||||
|
||||
@@ -41,6 +41,3 @@
|
||||
*/
|
||||
/mob/living/simple_animal/drone/proc/drone_chat(msg)
|
||||
alert_drones("<i>Drone Chat: <span class='name'>[name]</span> <span class='message'>[say_quote(msg)]</span></i>", TRUE)
|
||||
|
||||
/mob/living/simple_animal/drone/binarycheck()
|
||||
return TRUE
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/obj/item/storage/drone_tools
|
||||
name = "built-in tools"
|
||||
desc = "Access your built-in tools."
|
||||
icon = 'icons/hud/screen_drone.dmi'
|
||||
icon_state = "tool_storage"
|
||||
item_flags = ABSTRACT
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
/obj/item/storage/drone_tools/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
|
||||
|
||||
/obj/item/storage/drone_tools/ComponentInitialize()
|
||||
. = ..()
|
||||
var/static/list/drone_builtins = list(
|
||||
/obj/item/crowbar/drone,
|
||||
/obj/item/screwdriver/drone,
|
||||
/obj/item/wrench/drone,
|
||||
/obj/item/weldingtool/drone,
|
||||
/obj/item/wirecutters/drone,
|
||||
)
|
||||
var/datum/component/storage/storage_component = GetComponent(/datum/component/storage)
|
||||
storage_component.max_combined_w_class = 40
|
||||
storage_component.max_w_class = WEIGHT_CLASS_NORMAL
|
||||
storage_component.max_items = 5
|
||||
storage_component.rustle_sound = FALSE
|
||||
storage_component.set_holdable(drone_builtins)
|
||||
|
||||
|
||||
/obj/item/storage/drone_tools/PopulateContents()
|
||||
var/list/builtintools = list()
|
||||
builtintools += new /obj/item/crowbar/drone(src)
|
||||
builtintools += new /obj/item/screwdriver/drone(src)
|
||||
builtintools += new /obj/item/wrench/drone(src)
|
||||
builtintools += new /obj/item/weldingtool/drone(src)
|
||||
builtintools += new /obj/item/wirecutters/drone(src)
|
||||
|
||||
for(var/obj/item/tool as anything in builtintools)
|
||||
tool.AddComponent(/datum/component/holderloving, src, TRUE)
|
||||
|
||||
|
||||
/obj/item/crowbar/drone
|
||||
name = "built-in crowbar"
|
||||
desc = "A crowbar built into your chassis."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "crowbar_cyborg"
|
||||
inhand_icon_state = "crowbar"
|
||||
|
||||
/obj/item/screwdriver/drone
|
||||
name = "built-in screwdriver"
|
||||
desc = "A screwdriver built into your chassis."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "screwdriver_cyborg"
|
||||
inhand_icon_state = "screwdriver"
|
||||
random_color = FALSE
|
||||
|
||||
|
||||
/obj/item/screwdriver/drone/worn_overlays(isinhands = FALSE, icon_file)
|
||||
. = list()
|
||||
if(isinhands)
|
||||
var/mutable_appearance/head = mutable_appearance(icon_file, "screwdriver_head")
|
||||
head.appearance_flags = RESET_COLOR
|
||||
. += head
|
||||
|
||||
/obj/item/wrench/drone
|
||||
name = "built-in wrench"
|
||||
desc = "A wrench built into your chassis."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "wrench_cyborg"
|
||||
inhand_icon_state = "wrench"
|
||||
|
||||
/obj/item/weldingtool/drone
|
||||
name = "built-in welding tool"
|
||||
desc = "A welding tool built into your chassis."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "indwelder_cyborg"
|
||||
|
||||
/obj/item/wirecutters/drone
|
||||
name = "built-in wirecutters"
|
||||
desc = "Wirecutters built into your chassis."
|
||||
icon = 'icons/obj/items_cyborg.dmi'
|
||||
icon_state = "wirecutters_cyborg"
|
||||
inhand_icon_state = "cutters"
|
||||
random_color = FALSE
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#define DRONE_MINIMUM_AGE 14
|
||||
|
||||
///////////////////
|
||||
//DRONES AS ITEMS//
|
||||
///////////////////
|
||||
@@ -20,8 +18,14 @@
|
||||
density = FALSE
|
||||
death = FALSE
|
||||
roundstart = FALSE
|
||||
mob_name = "drone"
|
||||
///Type of drone that will be spawned
|
||||
mob_type = /mob/living/simple_animal/drone
|
||||
banType = ROLE_DRONE
|
||||
show_flavour = FALSE
|
||||
short_desc = "You are a Maintenance Drone."
|
||||
flavour_text = "Born out of science, your purpose is to maintain Space Station 13. Maintenance Drones can become the backbone of a healthy station."
|
||||
important_info = "You MUST read and follow your laws carefully."
|
||||
|
||||
/obj/effect/mob_spawn/drone/Initialize()
|
||||
. = ..()
|
||||
@@ -30,12 +34,19 @@
|
||||
notify_ghosts("A drone shell has been created in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = FALSE, ignore_key = POLL_IGNORE_DRONE, notify_suiciders = FALSE)
|
||||
AddElement(/datum/element/point_of_interest)
|
||||
|
||||
//ATTACK GHOST IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/mob_spawn/drone/attack_ghost(mob/user)
|
||||
if(CONFIG_GET(flag/use_age_restriction_for_jobs))
|
||||
if(!isnum(user.client.player_age)) //apparently what happens when there's no DB connected. just don't let anybody be a drone without admin intervention
|
||||
return
|
||||
if(user.client.player_age < DRONE_MINIMUM_AGE)
|
||||
to_chat(user, "<span class='danger'>You're too new to play as a drone! Please try again in [DRONE_MINIMUM_AGE - user.client.player_age] days.</span>")
|
||||
return
|
||||
. = ..()
|
||||
/obj/effect/mob_spawn/drone/allow_spawn(mob/user)
|
||||
var/client/user_client = user.client
|
||||
var/mob/living/simple_animal/drone/drone_type = mob_type
|
||||
if(!initial(drone_type.shy) || isnull(user_client) || !CONFIG_GET(flag/use_exp_restrictions_other))
|
||||
return ..()
|
||||
var/required_role = CONFIG_GET(string/drone_required_role)
|
||||
var/required_playtime = CONFIG_GET(number/drone_role_playtime) * 60
|
||||
if(required_playtime <= 0)
|
||||
return ..()
|
||||
var/current_playtime = user_client?.calc_exp_type(required_role)
|
||||
if (current_playtime < required_playtime)
|
||||
var/minutes_left = required_playtime - current_playtime
|
||||
var/playtime_left = DisplayTimeText(minutes_left * (1 MINUTES))
|
||||
to_chat(user, "<span class='danger'>You need to play [playtime_left] more as [required_role] to spawn as a Maintenance Drone!</span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
default_storage = /obj/item/uplink
|
||||
default_hatmask = /obj/item/clothing/head/helmet/space/hardsuit/syndi
|
||||
hacked = TRUE
|
||||
shy = FALSE
|
||||
flavortext = null
|
||||
|
||||
/mob/living/simple_animal/drone/syndrone/Initialize()
|
||||
@@ -61,11 +62,15 @@
|
||||
icon_state = "syndrone_item"
|
||||
mob_name = "syndrone"
|
||||
mob_type = /mob/living/simple_animal/drone/syndrone
|
||||
short_desc = "You are a Syndicate Maintenance Drone."
|
||||
flavour_text = "In a prior life, you maintained a Nanotrasen Research Station. Abducted from your home, you were given some upgrades... and now serve an enemy of your former masters."
|
||||
important_info = ""
|
||||
|
||||
/obj/effect/mob_spawn/drone/syndrone/badass
|
||||
name = "badass syndrone shell"
|
||||
mob_name = "badass syndrone"
|
||||
mob_type = /mob/living/simple_animal/drone/syndrone/badass
|
||||
flavour_text = "In a prior life, you maintained a Nanotrasen Research Station. Abducted from your home, you were given some BETTER upgrades... and now serve an enemy of your former masters."
|
||||
|
||||
/obj/effect/mob_spawn/drone/snowflake
|
||||
name = "snowflake drone shell"
|
||||
@@ -92,6 +97,14 @@
|
||||
icon_living = icon_state
|
||||
icon_dead = "[visualAppearance]_dead"
|
||||
|
||||
/obj/effect/mob_spawn/drone/classic
|
||||
mob_type = /mob/living/simple_animal/drone/classic
|
||||
|
||||
/mob/living/simple_animal/drone/classic
|
||||
name = "classic drone shell"
|
||||
shy = FALSE
|
||||
default_storage = /obj/item/storage/backpack/duffelbag/drone
|
||||
|
||||
/obj/effect/mob_spawn/drone/derelict
|
||||
name = "derelict drone shell"
|
||||
desc = "A long-forgotten drone shell. It seems kind of... Space Russian."
|
||||
@@ -126,4 +139,3 @@
|
||||
AddComponent(/datum/component/stationstuck, PUNISHMENT_GIB, "01000110 01010101 01000011 01001011 00100000 01011001 01001111 01010101<br>WARNING: Dereliction of KS13 detected. Self-destruct activated.")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@
|
||||
to_chat(src, laws)
|
||||
to_chat(src, "<i>Your onboard antivirus has initiated lockdown. Motor servos are impaired, ventilation access is denied, and your display reports that you are hacked to all nearby.</i>")
|
||||
hacked = TRUE
|
||||
set_shy(FALSE)
|
||||
mind.special_role = "hacked drone"
|
||||
REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
|
||||
speed = 1 //gotta go slow
|
||||
@@ -167,6 +168,7 @@
|
||||
to_chat(src, laws)
|
||||
to_chat(src, "<i>Having been restored, your onboard antivirus reports the all-clear and you are able to perform all actions again.</i>")
|
||||
hacked = FALSE
|
||||
set_shy(initial(shy))
|
||||
mind.special_role = null
|
||||
ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT)
|
||||
speed = initial(speed)
|
||||
@@ -186,6 +188,7 @@
|
||||
*/
|
||||
/mob/living/simple_animal/drone/proc/liberate()
|
||||
laws = "1. You are a Free Drone."
|
||||
set_shy(FALSE)
|
||||
to_chat(src, laws)
|
||||
|
||||
/**
|
||||
|
||||
@@ -851,3 +851,13 @@
|
||||
construction_time = 100
|
||||
build_path = /obj/item/assembly/flash/handheld
|
||||
category = list("Misc")
|
||||
|
||||
/datum/design/maint_drone
|
||||
name = "Maintenance Drone"
|
||||
desc = "\"Repairs the station without bothering you!\" is what the marketing says."
|
||||
id = "maint_drone"
|
||||
build_type = MECHFAB
|
||||
materials = list(/datum/material/iron = 800, /datum/material/glass = 350)
|
||||
construction_time = 150
|
||||
build_path = /obj/effect/mob_spawn/drone
|
||||
category = list("Misc")
|
||||
|
||||
@@ -304,6 +304,14 @@
|
||||
design_ids = list("exodrone_console","exoscanner_console","exoscanner","exodrone_launcher")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
/datum/techweb_node/dex_robotics
|
||||
id = "dex_robotics"
|
||||
display_name = "Dexterous Robotics Research"
|
||||
description = "The fine art of opposable thumbs."
|
||||
prereq_ids = list("adv_engi", "adv_robotics", "biotech")
|
||||
design_ids = list("maint_drone")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
|
||||
/datum/techweb_node/neural_programming
|
||||
id = "neural_programming"
|
||||
display_name = "Neural Programming"
|
||||
|
||||
@@ -563,3 +563,10 @@ RATCAP 64
|
||||
|
||||
## Maximum fine for a citation
|
||||
MAXFINE 2000
|
||||
|
||||
## Which role is required of playtime to be eligible for Maintenance Drones
|
||||
## See code/__DEFINES/preferences.dm for available options, use the string portion without quotes
|
||||
#DRONE_REQUIRED_ROLE Silicon
|
||||
|
||||
## How many played hours of DRONE_REQUIRED_ROLE required to be a Maintenance Done
|
||||
#DRONE_ROLE_PLAYTIME 40
|
||||
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 379 B |
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 42 KiB |
@@ -493,10 +493,12 @@
|
||||
#include "code\datums\components\grillable.dm"
|
||||
#include "code\datums\components\gunpoint.dm"
|
||||
#include "code\datums\components\heirloom.dm"
|
||||
#include "code\datums\components\holderloving.dm"
|
||||
#include "code\datums\components\honkspam.dm"
|
||||
#include "code\datums\components\hot_ice.dm"
|
||||
#include "code\datums\components\igniter.dm"
|
||||
#include "code\datums\components\infective.dm"
|
||||
#include "code\datums\components\itempicky.dm"
|
||||
#include "code\datums\components\jousting.dm"
|
||||
#include "code\datums\components\knockback.dm"
|
||||
#include "code\datums\components\knockoff.dm"
|
||||
@@ -527,6 +529,8 @@
|
||||
#include "code\datums\components\rotation.dm"
|
||||
#include "code\datums\components\shielded.dm"
|
||||
#include "code\datums\components\shrink.dm"
|
||||
#include "code\datums\components\shy.dm"
|
||||
#include "code\datums\components\shy_in_room.dm"
|
||||
#include "code\datums\components\singularity.dm"
|
||||
#include "code\datums\components\sitcomlaughter.dm"
|
||||
#include "code\datums\components\sizzle.dm"
|
||||
@@ -546,6 +550,7 @@
|
||||
#include "code\datums\components\swarming.dm"
|
||||
#include "code\datums\components\tackle.dm"
|
||||
#include "code\datums\components\tactical.dm"
|
||||
#include "code\datums\components\technointrovert.dm"
|
||||
#include "code\datums\components\tether.dm"
|
||||
#include "code\datums\components\thermite.dm"
|
||||
#include "code\datums\components\twohanded.dm"
|
||||
@@ -2657,6 +2662,7 @@
|
||||
#include "code\modules\mob\living\simple_animal\friendly\snake.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\drone\_drone.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\drone\drone_say.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\drone\drone_tools.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\drone\drones_as_items.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\drone\extra_drone_types.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\drone\interaction.dm"
|
||||
|
||||
Reference in New Issue
Block a user