mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-23 04:51:32 +01:00
Merge branch 'master' into placeholder
# Conflicts: # icons/obj/furniture.dmi
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#include "code\__defines\color.dm"
|
||||
#include "code\__defines\damage_organs.dm"
|
||||
#include "code\__defines\dna.dm"
|
||||
#include "code\__defines\drinks.dm"
|
||||
#include "code\__defines\dview.dm"
|
||||
#include "code\__defines\extools.dm"
|
||||
#include "code\__defines\flags.dm"
|
||||
@@ -84,6 +85,7 @@
|
||||
#include "code\_helpers\global_lists.dm"
|
||||
#include "code\_helpers\icon_smoothing.dm"
|
||||
#include "code\_helpers\icons.dm"
|
||||
#include "code\_helpers\images.dm"
|
||||
#include "code\_helpers\lists.dm"
|
||||
#include "code\_helpers\logging.dm"
|
||||
#include "code\_helpers\maths.dm"
|
||||
@@ -467,6 +469,7 @@
|
||||
#include "code\game\gamemodes\changeling\implements\powers\stings.dm"
|
||||
#include "code\game\gamemodes\changeling\implements\powers\suck.dm"
|
||||
#include "code\game\gamemodes\cult\cult.dm"
|
||||
#include "code\game\gamemodes\cult\cultist_datum.dm"
|
||||
#include "code\game\gamemodes\cult\hell_universe.dm"
|
||||
#include "code\game\gamemodes\cult\narsie.dm"
|
||||
#include "code\game\gamemodes\cult\cultify\mob.dm"
|
||||
@@ -1405,6 +1408,7 @@
|
||||
#include "code\modules\clothing\rings\material.dm"
|
||||
#include "code\modules\clothing\rings\rings.dm"
|
||||
#include "code\modules\clothing\sets\acting_captain.dm"
|
||||
#include "code\modules\clothing\sets\captain.dm"
|
||||
#include "code\modules\clothing\shoes\colour.dm"
|
||||
#include "code\modules\clothing\shoes\jobs.dm"
|
||||
#include "code\modules\clothing\shoes\leg_guard.dm"
|
||||
@@ -1585,6 +1589,7 @@
|
||||
#include "code\modules\events\grid_check.dm"
|
||||
#include "code\modules\events\infestation.dm"
|
||||
#include "code\modules\events\ion_storm.dm"
|
||||
#include "code\modules\events\maint_drones.dm"
|
||||
#include "code\modules\events\meteors.dm"
|
||||
#include "code\modules\events\money_hacker.dm"
|
||||
#include "code\modules\events\money_lotto.dm"
|
||||
@@ -1846,6 +1851,7 @@
|
||||
#include "code\modules\mining\mint.dm"
|
||||
#include "code\modules\mining\ore.dm"
|
||||
#include "code\modules\mining\ore_datum.dm"
|
||||
#include "code\modules\mining\ore_detector.dm"
|
||||
#include "code\modules\mining\ore_satchel.dm"
|
||||
#include "code\modules\mining\satchel_ore_boxdm.dm"
|
||||
#include "code\modules\mining\drilling\drill.dm"
|
||||
@@ -2143,6 +2149,7 @@
|
||||
#include "code\modules\mob\living\simple_animal\hostile\phoron_worm.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\pirate.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\pra.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\rogue_maint_drone.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\russian.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\sarlacc.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\spider_queen.dm"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#define NO_EMPTY_ICON 1 //does NOT have an iconstate_empty icon. If adding empty icons for a drink, make sure it does not have this flag
|
||||
#define UNIQUE_EMPTY_ICON 2 //Uses the empty_icon_state listed. Should really only be used when one trash state applies to multiple drinks. Remove if one is added
|
||||
#define UNIQUE_EMPTY_ICON_FILE 4 //Uses the empty_icon_state listed. also doesn't change its icon file, giving it a pseudo contained sprite status
|
||||
#define IS_GLASS 8 //Container is glass. Affects shattering, unacidable, etc.
|
||||
@@ -6,6 +6,7 @@
|
||||
#define SOUNDS_BULLET_METAL list('sound/effects/projectile_impact/bullet_metal1.ogg', 'sound/effects/projectile_impact/bullet_metal2.ogg', 'sound/effects/projectile_impact/bullet_metal3.ogg')
|
||||
#define SOUNDS_LASER_MEAT list('sound/effects/projectile_impact/energy_meat1.ogg','sound/effects/projectile_impact/energy_meat2.ogg')
|
||||
#define SOUNDS_LASER_METAL list('sound/effects/projectile_impact/energy_metal1.ogg','sound/effects/projectile_impact/energy_metal2.ogg')
|
||||
#define SOUNDS_ION_ANY list('sound/effects/projectile_impact/ion_any.ogg')
|
||||
|
||||
//Used in determining the currently permissable firemodes of wireless-control firing pins.
|
||||
#define WIRELESS_PIN_AUTOMATIC 1
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#define NOSLIP 0x8 // Prevents from slipping on wet floors, in space, etc.
|
||||
#define BLOCK_GAS_SMOKE_EFFECT 0x10 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
|
||||
#define FLEXIBLEMATERIAL 0x20 // At the moment, masks with this flag will not prevent eating even if they are covering your face.
|
||||
#define SOUNDPROTECTION 0x40 // whether wearing this item will protect you from loud noises such as flashbangs | this only works for ear slots or the head slot
|
||||
|
||||
// Flags for pass_flags.
|
||||
#define PASSTABLE 0x1
|
||||
@@ -95,6 +96,7 @@
|
||||
#define slot_w_uniform_str "slot_w_uniform"
|
||||
#define slot_head_str "slot_head"
|
||||
#define slot_wear_suit_str "slot_suit"
|
||||
#define slot_shoes_str "slot_shoes"
|
||||
|
||||
//itemstate suffixes. Used for containedsprite worn items
|
||||
#define WORN_LHAND "_lh"
|
||||
|
||||
@@ -133,6 +133,4 @@ var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret
|
||||
#define M_NO_PROCESS 27
|
||||
|
||||
// This controls how much power the AME generates per unit of fuel.
|
||||
// Assuming 100% efficency, use this equation to figure out power output.
|
||||
// power_generated = (fuel**2) * AM_POWER_FACTOR
|
||||
#define AM_POWER_FACTOR 50000
|
||||
#define AM_POWER_FACTOR 1000000
|
||||
@@ -64,3 +64,8 @@
|
||||
#define MATERIAL_CLOTH_BEIGE "beige"
|
||||
#define MATERIAL_CLOTH_LIME "lime"
|
||||
|
||||
#define MATERIAL_ALTERATION_NONE 0
|
||||
#define MATERIAL_ALTERATION_NAME 1
|
||||
#define MATERIAL_ALTERATION_DESC 2
|
||||
#define MATERIAL_ALTERATION_COLOR 4
|
||||
#define MATERIAL_ALTERATION_ALL (~MATERIAL_ALTERATION_NONE)
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
#define I_GRAB "grab"
|
||||
#define I_HURT "harm"
|
||||
|
||||
//movement intents
|
||||
#define M_WALK "walk"
|
||||
#define M_RUN "run"
|
||||
|
||||
// Limbs and robotic stuff.
|
||||
#define BP_L_FOOT "l_foot"
|
||||
#define BP_R_FOOT "r_foot"
|
||||
@@ -100,6 +104,10 @@
|
||||
#define BP_ALL_LIMBS list(BP_CHEST, BP_GROIN, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG, BP_L_FOOT, BP_R_FOOT)
|
||||
#define BP_IS_ROBOTIC(org) (org.status & ORGAN_ROBOT)
|
||||
|
||||
#define ROBOTIC_NONE 0
|
||||
#define ROBOTIC_ASSISTED 1
|
||||
#define ROBOTIC_MECHANICAL 2
|
||||
|
||||
//Generic organs
|
||||
#define BP_MOUTH "mouth"
|
||||
#define BP_EYES "eyes"
|
||||
@@ -204,6 +212,7 @@
|
||||
#define INV_W_UNIFORM_DEF_ICON 'icons/mob/uniform.dmi'
|
||||
#define INV_ACCESSORIES_DEF_ICON 'icons/mob/ties.dmi'
|
||||
#define INV_SUIT_DEF_ICON 'icons/mob/suit.dmi'
|
||||
#define INV_SHOES_DEF_ICON 'icons/mob/feet.dmi'
|
||||
|
||||
// IPC tags
|
||||
#define IPC_OWNERSHIP_SELF "Self Owned"
|
||||
|
||||
+275
-105
@@ -1,179 +1,349 @@
|
||||
//tgstation-server DMAPI
|
||||
// tgstation-server DMAPI
|
||||
|
||||
//All functions and datums outside this document are subject to change with any version and should not be relied on
|
||||
#define TGS_DMAPI_VERSION "5.2.2"
|
||||
|
||||
//CONFIGURATION
|
||||
// All functions and datums outside this document are subject to change with any version and should not be relied on.
|
||||
|
||||
//create this define if you want to do configuration outside of this file
|
||||
// CONFIGURATION
|
||||
|
||||
/// Create this define if you want to do TGS configuration outside of this file.
|
||||
#ifndef TGS_EXTERNAL_CONFIGURATION
|
||||
|
||||
//Comment this out once you've filled in the below
|
||||
// Comment this out once you've filled in the below.
|
||||
//#error TGS API unconfigured
|
||||
|
||||
//Required interfaces (fill in with your codebase equivalent):
|
||||
// Uncomment this if you wish to allow the game to interact with TGS 3.
|
||||
// This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()()
|
||||
//#define TGS_V3_API
|
||||
|
||||
//create a global variable named `Name` and set it to `Value`
|
||||
//These globals must not be modifiable from anywhere outside of the server tools
|
||||
// Required interfaces (fill in with your codebase equivalent):
|
||||
|
||||
/// Create a global variable named `Name` and set it to `Value`.
|
||||
#define TGS_DEFINE_AND_SET_GLOBAL(Name, Value) var/global/_tgs_##Name = ##Value
|
||||
|
||||
//Read the value in the global variable `Name`
|
||||
/// Read the value in the global variable `Name`.
|
||||
#define TGS_READ_GLOBAL(Name) global._tgs_##Name
|
||||
|
||||
//Set the value in the global variable `Name` to `Value`
|
||||
/// Set the value in the global variable `Name` to `Value`.
|
||||
#define TGS_WRITE_GLOBAL(Name, Value) global._tgs_##Name = ##Value
|
||||
|
||||
//Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game priveledge escalation
|
||||
/// Disallow ANYONE from reflecting a given `path`, security measure to prevent in-game use of DD -> TGS capabilities.
|
||||
#define TGS_PROTECT_DATUM(Path)
|
||||
|
||||
//display an announcement `message` from the server to all players
|
||||
#define TGS_WORLD_ANNOUNCE(message) world << "[html_encode(##message)]"
|
||||
/// Display an announcement `message` from the server to all players.
|
||||
#define TGS_WORLD_ANNOUNCE(message) world << "<b>TGS Notification</b>: [html_encode(##message)]"
|
||||
|
||||
//Notify current in-game administrators of a string `event`
|
||||
/// Notify current in-game administrators of a string `event`.
|
||||
#define TGS_NOTIFY_ADMINS(event) message_admins(##event)
|
||||
|
||||
//Write an info `message` to a server log
|
||||
/// Write an info `message` to a server log.
|
||||
#define TGS_INFO_LOG(message) log_tgs("[##message]")
|
||||
|
||||
//Write an error `message` to a server log
|
||||
/// Write an warning `message` to a server log.
|
||||
#define TGS_WARNING_LOG(message) log_tgs("[##message]", SEVERITY_WARNING)
|
||||
|
||||
/// Write an error `message` to a server log.
|
||||
#define TGS_ERROR_LOG(message) log_tgs("[##message]", SEVERITY_ERROR)
|
||||
|
||||
//Get the number of connected /clients
|
||||
/// Get the number of connected /clients.
|
||||
#define TGS_CLIENT_COUNT clients.len
|
||||
|
||||
#endif
|
||||
|
||||
//EVENT CODES
|
||||
// EVENT CODES
|
||||
|
||||
//TODO
|
||||
/// Before a reboot mode change, extras parameters are the current and new reboot mode enums
|
||||
#define TGS_EVENT_REBOOT_MODE_CHANGE -1
|
||||
/// Before a port change is about to happen, extra parameters is new port
|
||||
#define TGS_EVENT_PORT_SWAP -2
|
||||
/// Before the instance is renamed, extra parameter is the new name
|
||||
#define TGS_EVENT_INSTANCE_RENAMED -3
|
||||
/// After the watchdog reattaches to DD, extra parameter is the new [/datum/tgs_version] of the server
|
||||
#define TGS_EVENT_WATCHDOG_REATTACH -4
|
||||
|
||||
/// When the repository is reset to its origin reference. Parameters: Reference name, Commit SHA
|
||||
#define TGS_EVENT_REPO_RESET_ORIGIN 0
|
||||
/// When the repository performs a checkout. Parameters: Checkout git object
|
||||
#define TGS_EVENT_REPO_CHECKOUT 1
|
||||
/// When the repository performs a fetch operation. No parameters
|
||||
#define TGS_EVENT_REPO_FETCH 2
|
||||
/// When the repository merges a pull request. Parameters: PR Number, PR Sha, (Nullable) Comment made by TGS user
|
||||
#define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3
|
||||
/// Before the repository makes a sychronize operation. Parameters: Absolute repostiory path
|
||||
#define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4
|
||||
/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND
|
||||
#define TGS_EVENT_BYOND_INSTALL_START 5
|
||||
/// When a BYOND install operation fails. Parameters: Error message
|
||||
#define TGS_EVENT_BYOND_INSTALL_FAIL 6
|
||||
/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND
|
||||
#define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7
|
||||
/// When the compiler starts running. Parameters: Game directory path, origin commit SHA
|
||||
#define TGS_EVENT_COMPILE_START 8
|
||||
/// When a compile is cancelled. No parameters
|
||||
#define TGS_EVENT_COMPILE_CANCELLED 9
|
||||
/// When a compile fails. Parameters: Game directory path, [TRUE]/[FALSE] based on if the cause for failure was DMAPI validation
|
||||
#define TGS_EVENT_COMPILE_FAILURE 10
|
||||
/// When a compile operation completes. Note, this event fires before the new .dmb is loaded into the watchdog. Consider using the [TGS_EVENT_DEPLOYMENT_COMPLETE] instead. Parameters: Game directory path
|
||||
#define TGS_EVENT_COMPILE_COMPLETE 11
|
||||
/// When an automatic update for the current instance begins. No parameters
|
||||
#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
|
||||
/// When the repository encounters a merge conflict: Parameters: Base SHA, target SHA, base reference, target reference
|
||||
#define TGS_EVENT_REPO_MERGE_CONFLICT 13
|
||||
/// When a deployment completes. No Parameters
|
||||
#define TGS_EVENT_DEPLOYMENT_COMPLETE 14
|
||||
/// Before the watchdog shuts down. Not sent for graceful shutdowns. No parameters.
|
||||
#define TGS_EVENT_WATCHDOG_SHUTDOWN 15
|
||||
/// Before the watchdog detaches for a TGS update/restart. No parameters.
|
||||
#define TGS_EVENT_WATCHDOG_DETACH 16
|
||||
// We don't actually implement this value as the DMAPI can never receive it
|
||||
// #define TGS_EVENT_WATCHDOG_LAUNCH 17
|
||||
|
||||
// OTHER ENUMS
|
||||
|
||||
/// The server will reboot normally.
|
||||
#define TGS_REBOOT_MODE_NORMAL 0
|
||||
/// The server will stop running on reboot.
|
||||
#define TGS_REBOOT_MODE_SHUTDOWN 1
|
||||
/// The watchdog will restart on reboot.
|
||||
#define TGS_REBOOT_MODE_RESTART 2
|
||||
|
||||
/// DreamDaemon Trusted security level.
|
||||
#define TGS_SECURITY_TRUSTED 0
|
||||
/// DreamDaemon Safe security level.
|
||||
#define TGS_SECURITY_SAFE 1
|
||||
/// DreamDaemon Ultrasafe security level.
|
||||
#define TGS_SECURITY_ULTRASAFE 2
|
||||
|
||||
//REQUIRED HOOKS
|
||||
|
||||
//Call this somewhere in /world/New() that is always run
|
||||
//event_handler: optional user defined event handler. The default behaviour is to broadcast the event in english to all connected admin channels
|
||||
/world/proc/TgsNew(datum/tgs_event_handler/event_handler)
|
||||
/**
|
||||
* Call this somewhere in [/world/proc/New] that is always run. This function may sleep!
|
||||
*
|
||||
* * event_handler - Optional user defined [/datum/tgs_event_handler].
|
||||
* * minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated. Can be one of [TGS_SECURITY_ULTRASAFE], [TGS_SECURITY_SAFE], or [TGS_SECURITY_TRUSTED].
|
||||
*/
|
||||
/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE)
|
||||
return
|
||||
|
||||
//Call this when your initializations are complete and your game is ready to play before any player interactions happen
|
||||
//This may use world.sleep_offline to make this happen so ensure no changes are made to it while this call is running
|
||||
/**
|
||||
* Call this when your initializations are complete and your game is ready to play before any player interactions happen.
|
||||
*
|
||||
* This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running.
|
||||
* Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184
|
||||
* Before this point, note that any static files or directories may be in use by another server. Your code should account for this.
|
||||
* This function should not be called before ..() in [/world/proc/New].
|
||||
*/
|
||||
/world/proc/TgsInitializationComplete()
|
||||
return
|
||||
|
||||
//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified
|
||||
#define TGS_TOPIC var/tgs_topic_return = TgsTopic(T); if(tgs_topic_return) return tgs_topic_return
|
||||
/// Put this at the start of [/world/proc/Topic].
|
||||
#define TGS_TOPIC var/tgs_topic_return = TgsTopic(args[1]); if(tgs_topic_return) return tgs_topic_return
|
||||
|
||||
//Call this at the beginning of world/Reboot(reason)
|
||||
/**
|
||||
* Call this at the beginning of [world/proc/Reboot].
|
||||
*/
|
||||
/world/proc/TgsReboot()
|
||||
return
|
||||
|
||||
//DATUM DEFINITIONS
|
||||
//unless otherwise specified all datums defined here should be considered read-only, warranty void if written
|
||||
// DATUM DEFINITIONS
|
||||
// All datums defined here should be considered read-only
|
||||
|
||||
//represents git revision information about the current world build
|
||||
/// Represents git revision information.
|
||||
/datum/tgs_revision_information
|
||||
var/commit //full sha of compiled commit
|
||||
var/origin_commit //full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch
|
||||
/// Full SHA of the commit.
|
||||
var/commit
|
||||
/// Full sha of last known remote commit. This may be null if the TGS repository is not currently tracking a remote branch.
|
||||
var/origin_commit
|
||||
|
||||
//represents a merge of a GitHub pull request
|
||||
/datum/tgs_revision_information/test_merge
|
||||
var/number //pull request number
|
||||
var/title //pull request title
|
||||
var/body //pull request body
|
||||
var/author //pull request github author
|
||||
var/url //link to pull request html
|
||||
var/pull_request_commit //commit of the pull request when it was merged
|
||||
var/time_merged //timestamp of when the merge commit for the pull request was created
|
||||
var/comment //optional comment left by the one who initiated the test merge
|
||||
/// Represents a version.
|
||||
/datum/tgs_version
|
||||
/// The suite/major version number
|
||||
var/suite
|
||||
|
||||
//represents a connected chat channel
|
||||
/datum/tgs_chat_channel
|
||||
var/id //internal channel representation
|
||||
var/friendly_name //user friendly channel name
|
||||
var/server_name //server name the channel resides on
|
||||
var/provider_name //chat provider for the channel
|
||||
var/is_admin_channel //if the server operator has marked this channel for game admins only
|
||||
var/is_private_channel //if this is a private chat channel
|
||||
// This group of variables can be null to represent a wild card
|
||||
/// The minor version number. null for wildcards
|
||||
var/minor
|
||||
/// The patch version number. null for wildcards
|
||||
var/patch
|
||||
|
||||
//represents a chat user
|
||||
/datum/tgs_chat_user
|
||||
var/id //Internal user representation
|
||||
var/friendly_name //The user's public name
|
||||
var/mention //The text to use to ping this user in a message
|
||||
var/datum/tgs_chat_channel/channel //The /datum/tgs_chat_channel this user was from
|
||||
/// Legacy version number. Generally null
|
||||
var/deprecated_patch
|
||||
|
||||
//user definable callback for handling events
|
||||
/datum/tgs_event_handler/proc/HandleEvent(event_code)
|
||||
/// Unparsed string value
|
||||
var/raw_parameter
|
||||
/// String value minus prefix
|
||||
var/deprefixed_parameter
|
||||
|
||||
/**
|
||||
* Returns [TRUE]/[FALSE] based on if the [/datum/tgs_version] contains wildcards.
|
||||
*/
|
||||
/datum/tgs_version/proc/Wildcard()
|
||||
return
|
||||
|
||||
//user definable chat command
|
||||
/datum/tgs_chat_command
|
||||
var/name = "" //the string to trigger this command on a chat bot. e.g. TGS3_BOT: do_this_command
|
||||
var/help_text = "" //help text for this command
|
||||
var/admin_only = FALSE //set to TRUE if this command should only be usable by registered chat admins
|
||||
/**
|
||||
* Returns [TRUE]/[FALSE] based on if the [/datum/tgs_version] equals some other version.
|
||||
*
|
||||
* other_version - The [/datum/tgs_version] to compare against.
|
||||
*/
|
||||
/datum/tgs_version/proc/Equals(datum/tgs_version/other_version)
|
||||
return
|
||||
|
||||
//override to implement command
|
||||
//sender: The tgs_chat_user who send to command
|
||||
//params: The trimmed string following the command name
|
||||
//The return value will be stringified and sent to the appropriate chat
|
||||
/// Represents a merge of a GitHub pull request.
|
||||
/datum/tgs_revision_information/test_merge
|
||||
/// The pull request number.
|
||||
var/number
|
||||
/// The pull request title when it was merged.
|
||||
var/title
|
||||
/// The pull request body when it was merged.
|
||||
var/body
|
||||
/// The GitHub username of the pull request's author.
|
||||
var/author
|
||||
/// An http URL to the pull request.
|
||||
var/url
|
||||
/// The SHA of the pull request when that was merged.
|
||||
var/pull_request_commit
|
||||
/// ISO 8601 timestamp of when the pull request was merged.
|
||||
var/time_merged
|
||||
/// (Nullable) Comment left by the TGS user who initiated the merge..
|
||||
var/comment
|
||||
|
||||
/// Represents a connected chat channel.
|
||||
/datum/tgs_chat_channel
|
||||
/// TGS internal channel ID.
|
||||
var/id
|
||||
/// User friendly name of the channel.
|
||||
var/friendly_name
|
||||
/// Name of the chat connection. This is the IRC server address or the Discord guild.
|
||||
var/connection_name
|
||||
/// [TRUE]/[FALSE] based on if the server operator has marked this channel for game admins only.
|
||||
var/is_admin_channel
|
||||
/// [TRUE]/[FALSE] if the channel is a private message channel for a [/datum/tgs_chat_user].
|
||||
var/is_private_channel
|
||||
/// Tag string associated with the channel in TGS
|
||||
var/custom_tag
|
||||
|
||||
// Represents a chat user
|
||||
/datum/tgs_chat_user
|
||||
/// TGS internal user ID.
|
||||
var/id
|
||||
// The user's display name.
|
||||
var/friendly_name
|
||||
// The string to use to ping this user in a message.
|
||||
var/mention
|
||||
/// The [/datum/tgs_chat_channel] the user was from
|
||||
var/datum/tgs_chat_channel/channel
|
||||
|
||||
/**
|
||||
* User definable callback for handling TGS events.
|
||||
*
|
||||
* event_code - One of the TGS_EVENT_ defines. Extra parameters will be documented in each
|
||||
*/
|
||||
/datum/tgs_event_handler/proc/HandleEvent(event_code, ...)
|
||||
set waitfor = FALSE
|
||||
return
|
||||
|
||||
/// User definable chat command
|
||||
/datum/tgs_chat_command
|
||||
/// The string to trigger this command on a chat bot. e.g `@bot name ...` or `!tgs name ...`
|
||||
var/name = ""
|
||||
/// The help text displayed for this command
|
||||
var/help_text = ""
|
||||
/// If this command should be available to game administrators only
|
||||
var/admin_only = FALSE
|
||||
|
||||
/**
|
||||
* Process command activation. Should return a string to respond to the issuer with.
|
||||
*
|
||||
* sender - The [/datum/tgs_chat_user] who issued the command.
|
||||
* params - The trimmed string following the command `/datum/tgs_chat_command/var/name].
|
||||
*/
|
||||
/datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params)
|
||||
CRASH("[type] has no implementation for Run()")
|
||||
|
||||
//FUNCTIONS
|
||||
// API FUNCTIONS
|
||||
|
||||
//Returns the respective string version of the API
|
||||
/// Returns the maximum supported [/datum/tgs_version] of the DMAPI.
|
||||
/world/proc/TgsMaximumAPIVersion()
|
||||
return
|
||||
|
||||
/// Returns the minimum supported [/datum/tgs_version] of the DMAPI.
|
||||
/world/proc/TgsMinimumAPIVersion()
|
||||
return
|
||||
|
||||
//Gets the current version of the server tools running the server
|
||||
/world/proc/TgsVersion()
|
||||
return
|
||||
|
||||
//Returns TRUE if the world was launched under the server tools and the API matches, FALSE otherwise
|
||||
//No function below this succeeds if it returns FALSE
|
||||
/**
|
||||
* Returns [TRUE] if DreamDaemon was launched under TGS, the API matches, and was properly initialized. [FALSE] will be returned otherwise.
|
||||
*/
|
||||
/world/proc/TgsAvailable()
|
||||
return
|
||||
|
||||
/world/proc/TgsInstanceName()
|
||||
return
|
||||
// No function below this succeeds if it TgsAvailable() returns FALSE or if TgsNew() has yet to be called.
|
||||
|
||||
//Get the current `/datum/tgs_revision_information`
|
||||
/world/proc/TgsRevision()
|
||||
return
|
||||
|
||||
//Gets a list of active `/datum/tgs_revision_information/test_merge`s
|
||||
/world/proc/TgsTestMerges()
|
||||
return
|
||||
|
||||
//Forces a hard reboot of BYOND by ending the process
|
||||
//unlike del(world) clients will try to reconnect
|
||||
//If the service has not requested a shutdown, the next server will take over
|
||||
/**
|
||||
* Forces a hard reboot of DreamDaemon by ending the process.
|
||||
*
|
||||
* Unlike del(world) clients will try to reconnect.
|
||||
* If TGS has not requested a [TGS_REBOOT_MODE_SHUTDOWN] DreamDaemon will be launched again
|
||||
*/
|
||||
/world/proc/TgsEndProcess()
|
||||
return
|
||||
|
||||
//Gets a list of connected tgs_chat_channel
|
||||
/world/proc/TgsChatChannelInfo()
|
||||
/**
|
||||
* Send a message to connected chats.
|
||||
*
|
||||
* message - The string to send.
|
||||
* admin_only: If [TRUE], message will be sent to admin connected chats. Vice-versa applies.
|
||||
*/
|
||||
/world/proc/TgsTargetedChatBroadcast(message, admin_only = FALSE)
|
||||
return
|
||||
|
||||
//Sends a message to connected game chats
|
||||
//message: The message to send
|
||||
//channels: optional channels to limit the broadcast to
|
||||
/world/proc/TgsChatBroadcast(message, list/channels)
|
||||
return
|
||||
|
||||
//Send a message to non-admin connected chats
|
||||
//message: The message to send
|
||||
//admin_only: If TRUE, message will instead be sent to only admin connected chats
|
||||
/world/proc/TgsTargetedChatBroadcast(message, admin_only)
|
||||
return
|
||||
|
||||
//Send a private message to a specific user
|
||||
//message: The message to send
|
||||
//user: The /datum/tgs_chat_user to send to
|
||||
/**
|
||||
* Send a private message to a specific user.
|
||||
*
|
||||
* message - The string to send.
|
||||
* user: The [/datum/tgs_chat_user] to PM.
|
||||
*/
|
||||
/world/proc/TgsChatPrivateMessage(message, datum/tgs_chat_user/user)
|
||||
return
|
||||
|
||||
// The following functions will sleep if a call to TgsNew() is sleeping
|
||||
|
||||
/**
|
||||
* Send a message to connected chats that are flagged as game-related in TGS.
|
||||
*
|
||||
* message - The string to send.
|
||||
* channels - Optional list of [/datum/tgs_chat_channel]s to restrict the message to.
|
||||
*/
|
||||
/world/proc/TgsChatBroadcast(message, list/channels = null)
|
||||
return
|
||||
|
||||
/// Returns the current [/datum/tgs_version] of TGS if it is running the server, null otherwise.
|
||||
/world/proc/TgsVersion()
|
||||
return
|
||||
|
||||
/// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise.
|
||||
/world/proc/TgsApiVersion()
|
||||
return
|
||||
|
||||
/// Returns the name of the TGS instance running the game if TGS is present, null otherwise.
|
||||
/world/proc/TgsInstanceName()
|
||||
return
|
||||
|
||||
/// Return the current [/datum/tgs_revision_information] of the running server if TGS is present, null otherwise.
|
||||
/world/proc/TgsRevision()
|
||||
return
|
||||
|
||||
/// Returns the current BYOND security level as a TGS_SECURITY_ define if TGS is present, null otherwise.
|
||||
/world/proc/TgsSecurityLevel()
|
||||
return
|
||||
|
||||
/// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise.
|
||||
/world/proc/TgsTestMerges()
|
||||
return
|
||||
|
||||
/// Returns a list of connected [/datum/tgs_chat_channel]s if TGS is present, null otherwise.
|
||||
/world/proc/TgsChatChannelInfo()
|
||||
return
|
||||
|
||||
/*
|
||||
The MIT License
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
/proc/pixel_shift_to_turf(var/image/I, var/turf/source_turf, var/turf/target_turf)
|
||||
var/y_shift = (target_turf.y - source_turf.y) * world.icon_size
|
||||
var/x_shift = (target_turf.x - source_turf.x) * world.icon_size
|
||||
I.pixel_y += y_shift
|
||||
I.pixel_x += x_shift
|
||||
@@ -546,6 +546,11 @@
|
||||
t = replacetext(t, "</I>", "\[/i\]")
|
||||
t = replacetext(t, "<U>", "\[u\]")
|
||||
t = replacetext(t, "</U>", "\[/u\]")
|
||||
t = replacetext(t, "<BR>", "\[br\]")
|
||||
t = replacetext(t, "<HR>", "\[hr\]")
|
||||
t = replacetext(t, "<ul>", "\[list\]")
|
||||
t = replacetext(t, "</ul>", "\[/list\]")
|
||||
t = replacetext(t, "<li>", "\[*\]")
|
||||
t = replacetext(t, "<font size=\"4\">", "\[large\]")
|
||||
t = replacetext(t, "</font>", "\[/large\]")
|
||||
t = replacetext(t, "<font size = \"1\">", "\[small\]")
|
||||
@@ -632,4 +637,4 @@
|
||||
var/ending = copytext(string, length(string), (length(string) + 1))
|
||||
if(ending && !correct_punctuation[ending])
|
||||
string += "."
|
||||
return string
|
||||
return string
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
|
||||
/obj/screen/fullscreen/flash/noise
|
||||
icon_state = "noise"
|
||||
alpha = 127
|
||||
|
||||
/obj/screen/fullscreen/noise
|
||||
icon = 'icons/effects/static.dmi'
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
if(hud_data.has_m_intent)
|
||||
using = new /obj/screen/movement_intent()
|
||||
using.icon = ui_style
|
||||
using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
|
||||
using.icon_state = (mymob.m_intent == M_RUN ? "running" : "walking")
|
||||
using.color = ui_color
|
||||
using.alpha = ui_alpha
|
||||
src.adding += using
|
||||
@@ -296,6 +296,14 @@
|
||||
mymob.bodytemp.screen_loc = ui_temp
|
||||
hud_elements |= mymob.bodytemp
|
||||
|
||||
if(hud_data.has_cell)
|
||||
mymob.cells = new /obj/screen()
|
||||
mymob.cells.icon = 'icons/mob/screen/robot.dmi'
|
||||
mymob.cells.icon_state = "charge-empty"
|
||||
mymob.cells.name = "cell"
|
||||
mymob.cells.screen_loc = ui_nutrition
|
||||
hud_elements |= target.cells
|
||||
|
||||
if(hud_data.has_nutrition)
|
||||
mymob.nutrition_icon = new /obj/screen/food()
|
||||
mymob.nutrition_icon.icon = 'icons/mob/status_hunger.dmi'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var/obj/screen/mov_intent = new /obj/screen/movement_intent()
|
||||
mov_intent.set_dir(SOUTHWEST)
|
||||
mov_intent.icon = 'icons/mob/screen/morph.dmi'
|
||||
mov_intent.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
|
||||
mov_intent.icon_state = (mymob.m_intent == M_RUN ? "running" : "walking")
|
||||
move_intent = mov_intent
|
||||
|
||||
mymob.healths = new /obj/screen()
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
using = new /obj/screen/movement_intent()
|
||||
using.set_dir(SOUTHWEST)
|
||||
using.icon = 'icons/mob/screen/alien.dmi'
|
||||
using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
|
||||
using.icon_state = (mymob.m_intent == M_RUN ? "running" : "walking")
|
||||
src.adding += using
|
||||
move_intent = using
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
/obj/screen/vampire/blood/Click(var/location, var/control, var/params)
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
to_chat(H, SPAN_NOTICE("You have [H.mind.vampire.blood_usable]u of blood to use for vampiric powers."))
|
||||
to_chat(H, SPAN_WARNING("If it drops too low, you will go into a blood frenzy. You can only store a maximum of [VAMPIRE_MAX_USABLE_BLOOD]u."))
|
||||
var/datum/vampire/vampire = usr.mind.antag_datums[MODE_VAMPIRE]
|
||||
to_chat(usr, SPAN_NOTICE("You have [vampire.blood_usable]u of blood to use for vampiric powers."))
|
||||
to_chat(usr, SPAN_WARNING("If it drops too low, you will go into a blood frenzy. You can only store a maximum of [VAMPIRE_MAX_USABLE_BLOOD]u."))
|
||||
|
||||
/obj/screen/vampire/frenzy
|
||||
name = "frenzy count"
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
/obj/screen/vampire/frenzy/Click(var/location, var/control, var/params)
|
||||
if(ishuman(usr))
|
||||
var/mob/living/carbon/human/H = usr
|
||||
to_chat(H, SPAN_WARNING("Your frenzy counter is at [H.mind.vampire.frenzy]."))
|
||||
to_chat(H, SPAN_WARNING("If it raises too high, you will gain incredible power, but they will be very unsubtle. You can lower your frenzy counter by getting out of holy areas and by obtaining usable blood."))
|
||||
var/datum/vampire/vampire = usr.mind.antag_datums[MODE_VAMPIRE]
|
||||
to_chat(usr, SPAN_WARNING("Your frenzy counter is at [vampire.frenzy]."))
|
||||
to_chat(usr, SPAN_WARNING("If it raises too high, you will gain incredible power, but they will be very unsubtle. You can lower your frenzy counter by getting out of holy areas and by obtaining usable blood."))
|
||||
|
||||
/obj/screen/vampire/suck
|
||||
name = "blood_suck"
|
||||
|
||||
@@ -417,7 +417,7 @@
|
||||
|
||||
user.stamina_bar.update(user.stamina)
|
||||
|
||||
if (user.m_intent == "run")
|
||||
if (user.m_intent == M_RUN)
|
||||
icon_state = "running"
|
||||
else
|
||||
icon_state = "walking"
|
||||
@@ -435,21 +435,21 @@
|
||||
|
||||
if(C.legcuffed)
|
||||
to_chat(C, "<span class='notice'>You are legcuffed! You cannot run until you get [C.legcuffed] removed!</span>")
|
||||
C.m_intent = "walk" //Just incase
|
||||
C.m_intent = M_WALK //Just incase
|
||||
C.hud_used.move_intent.icon_state = "walking"
|
||||
return 1
|
||||
switch(usr.m_intent)
|
||||
if("run")
|
||||
usr.m_intent = "walk"
|
||||
if("walk")
|
||||
usr.m_intent = "run"
|
||||
if(M_RUN)
|
||||
usr.m_intent = M_WALK
|
||||
if(M_WALK)
|
||||
usr.m_intent = M_RUN
|
||||
else if(istype(usr, /mob/living/simple_animal/hostile/morph))
|
||||
var/mob/living/simple_animal/hostile/morph/M = usr
|
||||
switch(usr.m_intent)
|
||||
if("run")
|
||||
usr.m_intent = "walk"
|
||||
if("walk")
|
||||
usr.m_intent = "run"
|
||||
if(M_RUN)
|
||||
usr.m_intent = M_WALK
|
||||
if(M_WALK)
|
||||
usr.m_intent = M_RUN
|
||||
M.update_speed()
|
||||
update_move_icon(usr)
|
||||
|
||||
|
||||
@@ -64,22 +64,41 @@ avoid code duplication. This includes items that may sometimes act as a standard
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/attackby(obj/item/I, mob/living/user)
|
||||
if(I.damtype == PAIN)
|
||||
playsound(loc, 'sound/weapons/tap.ogg', I.get_clamped_volume(), 1, -1)
|
||||
else
|
||||
return ..()
|
||||
|
||||
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
|
||||
// Click parameters is the params string from byond Click() code, see that documentation.
|
||||
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
return
|
||||
|
||||
/obj/item/proc/get_clamped_volume()
|
||||
if(w_class)
|
||||
if(force)
|
||||
return Clamp((force + w_class) * 4, 30, 100)// Add the item's force to its weight class and multiply by 4, then clamp the value between 30 and 100
|
||||
else
|
||||
return Clamp(w_class * 6, 10, 100) // Multiply the item's weight class by 6, then clamp the value between 10 and 100
|
||||
|
||||
//I would prefer to rename this attack_as_weapon(), but that would involve touching hundreds of files.
|
||||
/obj/item/proc/attack(mob/living/M, mob/living/user, var/target_zone = BP_CHEST)
|
||||
|
||||
if(!force || (flags & NOBLUDGEON))
|
||||
if(flags & NOBLUDGEON)
|
||||
return 0
|
||||
if(M == user && user.a_intent != I_HURT)
|
||||
return 0
|
||||
|
||||
if(user.is_pacified())
|
||||
if(force && user.is_pacified())
|
||||
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
|
||||
return 0
|
||||
|
||||
if(!force)
|
||||
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
|
||||
else if(hitsound)
|
||||
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
|
||||
|
||||
/////////////////////////
|
||||
user.lastattacked = M
|
||||
M.lastattacker = user
|
||||
@@ -103,9 +122,6 @@ avoid code duplication. This includes items that may sometimes act as a standard
|
||||
|
||||
//Called when a weapon is used to make a successful melee attack on a mob. Returns the blocked result
|
||||
/obj/item/proc/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||
if(hitsound)
|
||||
playsound(loc, hitsound, 50, 1, -1)
|
||||
|
||||
var/power = force
|
||||
if(HULK in user.mutations)
|
||||
power *= 2
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
runes_by_name[R.name] = rune
|
||||
tome_data += "<div class='rune-block'>"
|
||||
tome_data += "<b>[capitalize_first_letters(R.name)]</b>: <i>[R.desc]</i><br>"
|
||||
tome_data += "This rune <b><i>[R.can_be_talisman() ? "can" : "cannot"]</i></b> be turned into a talisman.<br><hr>"
|
||||
tome_data += "This rune <b><i>[R.can_be_talisman() ? "can" : "cannot"]</i></b> be turned into a talisman.<br>"
|
||||
tome_data += "This rune <b><i>[R.can_memorize() ? "can" : "cannot"]</i></b> be memorized to be scribed without a tome.<br><hr>"
|
||||
tome_data += "</div>"
|
||||
|
||||
/datum/controller/subsystem/cult/proc/add_rune(var/datum/rune/R)
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
// fall_collateral if the next turf is not open space.
|
||||
if (isopenturf(victim.loc) && victim.loc:is_hole)
|
||||
victim.forceMove(below)
|
||||
if(victim.pulledby)
|
||||
if(victim.pulledby && victim.pulledby.z != victim.z)
|
||||
var/mob/M = victim.pulledby
|
||||
M.stop_pulling()
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ var/datum/controller/subsystem/atoms/SSatoms
|
||||
var/initialized = INITIALIZATION_INSSATOMS
|
||||
var/old_initialized
|
||||
|
||||
var/list/late_misc_firers // this is a list of things that fire when late misc init is called
|
||||
|
||||
var/list/late_loaders
|
||||
var/list/created_atoms
|
||||
var/list/late_qdel
|
||||
|
||||
@@ -37,8 +37,14 @@
|
||||
populate_code_phrases()
|
||||
|
||||
// this covers mapped in drone fabs
|
||||
for(var/obj/machinery/drone_fabricator/DF in SSmachinery.all_machines)
|
||||
DF.enable_drone_spawn()
|
||||
for(var/thing in SSatoms.late_misc_firers)
|
||||
if(istype(thing, /obj/machinery/drone_fabricator))
|
||||
var/obj/machinery/drone_fabricator/DF = thing
|
||||
DF.enable_drone_spawn()
|
||||
else if(istype(thing, /mob/living/silicon/robot/drone/mining))
|
||||
var/mob/living/silicon/robot/drone/mining/MD = thing
|
||||
MD.request_player()
|
||||
LAZYREMOVE(SSatoms.late_misc_firers, thing)
|
||||
|
||||
if (config.use_forumuser_api)
|
||||
update_admins_from_api(TRUE)
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
/datum/brain_trauma/mild/muscle_weakness/on_life()
|
||||
var/fall_chance = 5
|
||||
if(owner.m_intent == "run")
|
||||
if(owner.m_intent == M_RUN)
|
||||
fall_chance += 15
|
||||
if(prob(fall_chance) && !owner.lying && !owner.buckled)
|
||||
to_chat(owner, "<span class='warning'>Your leg gives out!</span>")
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
if(owner.stat == UNCONSCIOUS || owner.sleeping > 0)
|
||||
return
|
||||
var/sleep_chance = 5
|
||||
if(owner.m_intent == "run")
|
||||
if(owner.m_intent == M_RUN)
|
||||
sleep_chance += 15
|
||||
if(owner.drowsyness)
|
||||
sleep_chance += owner.drowsyness + 5
|
||||
|
||||
+5
-5
@@ -54,9 +54,7 @@
|
||||
var/has_been_rev = 0//Tracks if this mind has been a rev or not
|
||||
|
||||
var/datum/faction/faction //associated faction
|
||||
var/datum/changeling/changeling //changeling holder
|
||||
|
||||
var/datum/vampire/vampire //vampire holder
|
||||
var/list/antag_datums = list()
|
||||
|
||||
var/rev_cooldown = 0
|
||||
|
||||
@@ -88,6 +86,8 @@
|
||||
/datum/mind/proc/transfer_to(mob/living/new_character)
|
||||
if(!istype(new_character))
|
||||
world.log << "## DEBUG: transfer_to(): Some idiot has tried to transfer_to( a non mob/living mob. Please inform Carn"
|
||||
var/datum/changeling/changeling = antag_datums[MODE_CHANGELING]
|
||||
var/datum/vampire/vampire = antag_datums[MODE_VAMPIRE]
|
||||
if(current) //remove ourself from our old body's mind variable
|
||||
if(changeling)
|
||||
current.remove_changeling_powers()
|
||||
@@ -485,8 +485,8 @@
|
||||
role_alt_title = null
|
||||
assigned_job = null
|
||||
//faction = null //Uncommenting this causes a compile error due to 'undefined type', fucked if I know.
|
||||
changeling = null
|
||||
vampire = null
|
||||
for(var/thing in antag_datums)
|
||||
QDEL_NULL(thing)
|
||||
initial_account = null
|
||||
objectives = list()
|
||||
special_verbs = list()
|
||||
|
||||
@@ -60,7 +60,7 @@ var/global/datum/repository/crew/crew_repository = new()
|
||||
if(isipc(H) && H.internal_organs_by_name[BP_IPCTAG]) // Don't make untagged IPCs obvious
|
||||
var/obj/item/organ/internal/cell/cell = H.internal_organs_by_name[BP_CELL]
|
||||
if(cell)
|
||||
crewmemberData["cellCharge"] = Floor(100*H.nutrition / H.max_nutrition)
|
||||
crewmemberData["cellCharge"] = cell.percent()
|
||||
|
||||
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
|
||||
crewmemberData["pressure"] = "N/A"
|
||||
|
||||
@@ -206,4 +206,10 @@
|
||||
name = "Optical Material Scanner"
|
||||
desc = "These glasses make use of scanning technology to allow the wearer to see objects through solid walls and floors."
|
||||
item_cost = 2
|
||||
path = /obj/item/clothing/glasses/material
|
||||
path = /obj/item/clothing/glasses/material
|
||||
|
||||
/datum/uplink_item/item/tools/earmuff_headset
|
||||
name = "Earmuff Headset"
|
||||
desc = "This set of earmuffs has a secret compartment housing radio gear, allowing it to function as a standard headset."
|
||||
item_cost = 2
|
||||
path = /obj/item/device/radio/headset/earmuff
|
||||
@@ -327,18 +327,6 @@
|
||||
pixel_x = rand(-16,16)
|
||||
pixel_y = rand(-16,16)
|
||||
|
||||
/obj/item/legcuffs
|
||||
name = "legcuffs"
|
||||
desc = "Use this to keep prisoners in line."
|
||||
gender = PLURAL
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "handcuff"
|
||||
flags = CONDUCT
|
||||
throwforce = 0
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
origin_tech = list(TECH_MATERIAL = 1)
|
||||
var/breakouttime = 300 //Deciseconds = 30s = 0.5 minute
|
||||
|
||||
/obj/item/SWF_uplink
|
||||
name = "station-bounced radio"
|
||||
desc = "used to comunicate it appears."
|
||||
|
||||
@@ -4,6 +4,7 @@ the HUD updates properly! */
|
||||
|
||||
//HUD image type used to properly clear client.images precisely
|
||||
/image/hud_overlay
|
||||
appearance_flags = RESET_COLOR|RESET_ALPHA
|
||||
|
||||
//Medical HUD outputs. Called by the Life() proc of the mob using it, usually.
|
||||
proc/process_med_hud(var/mob/M, var/local_scanner, var/mob/Alt)
|
||||
|
||||
@@ -17,7 +17,7 @@ var/datum/antagonist/burglar/burglars
|
||||
|
||||
hard_cap = 2
|
||||
hard_cap_round = 3
|
||||
initial_spawn_req = 1
|
||||
initial_spawn_req = 2
|
||||
initial_spawn_target = 2
|
||||
|
||||
faction = "syndicate"
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
faction = "Changeling"
|
||||
|
||||
/datum/antagonist/changeling/get_special_objective_text(var/datum/mind/player)
|
||||
return "<br><b>Changeling ID:</b> [player.changeling.changelingID].<br><b>Genomes Absorbed:</b> [player.changeling.absorbedcount]"
|
||||
var/datum/changeling/changeling = player.antag_datums[MODE_CHANGELING]
|
||||
return "<br><b>Changeling ID:</b> [changeling.changelingID].<br><b>Genomes Absorbed:</b> [changeling.absorbedcount]"
|
||||
|
||||
/datum/antagonist/changeling/update_antag_mob(var/datum/mind/player)
|
||||
..()
|
||||
|
||||
@@ -87,11 +87,19 @@ var/datum/antagonist/cultist/cult
|
||||
if(player.current && !istype(player.current, /mob/living/simple_animal/construct))
|
||||
player.current.add_language(LANGUAGE_CULT)
|
||||
player.current.verbs |= /datum/antagonist/cultist/proc/appraise_offering
|
||||
player.current.verbs |= /datum/cultist/proc/memorize_rune
|
||||
player.current.verbs |= /datum/cultist/proc/forget_rune
|
||||
player.current.verbs |= /datum/cultist/proc/scribe_rune
|
||||
player.antag_datums[MODE_CULTIST] = new /datum/cultist()
|
||||
|
||||
|
||||
/datum/antagonist/cultist/remove_antagonist(var/datum/mind/player)
|
||||
. = ..()
|
||||
|
||||
player.current.verbs -= /datum/antagonist/cultist/proc/appraise_offering
|
||||
player.current.verbs -= /datum/cultist/proc/memorize_rune
|
||||
player.current.verbs -= /datum/cultist/proc/forget_rune
|
||||
player.current.verbs -= /datum/cultist/proc/scribe_rune
|
||||
|
||||
/datum/antagonist/cultist/can_become_antag(var/datum/mind/player, ignore_role = 1)
|
||||
if(!..())
|
||||
@@ -104,7 +112,7 @@ var/datum/antagonist/cultist/cult
|
||||
/datum/antagonist/cultist/proc/appraise_offering()
|
||||
set name = "Appraise Offering"
|
||||
set desc = "Find out if someone close-by can be converted to join the cult, or not."
|
||||
set category = "IC"
|
||||
set category = "Cultist"
|
||||
|
||||
var/list/targets = list()
|
||||
for(var/mob/living/carbon/target in view(5, usr))
|
||||
|
||||
@@ -25,6 +25,19 @@ var/datum/antagonist/thrall/thralls = null
|
||||
|
||||
thralls = src
|
||||
|
||||
/datum/antagonist/thrall/handle_latelogin(var/mob/user)
|
||||
var/datum/mind/M = user.mind
|
||||
if(!M)
|
||||
return
|
||||
var/datum/vampire/vampire = M.antag_datums[MODE_VAMPIRE]
|
||||
if(vampire.master_image)
|
||||
user.client.images += vampire.master_image
|
||||
|
||||
/datum/antagonist/thrall/update_antag_mob(var/datum/mind/player)
|
||||
..()
|
||||
player.current.vampire_make_thrall()
|
||||
|
||||
/datum/antagonist/thrall/remove_antagonist(datum/mind/player, show_message, implanted)
|
||||
var/datum/vampire/vampire = player.antag_datums[MODE_VAMPIRE]
|
||||
vampire.lose_master(player.current)
|
||||
return ..()
|
||||
@@ -67,26 +67,36 @@ var/datum/antagonist/vampire/vamp = null
|
||||
/datum/antagonist/vampire/remove_antagonist(var/datum/mind/player, var/show_message = TRUE, var/implanted)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/datum/vampire/vampire = player.antag_datums[MODE_VAMPIRE]
|
||||
if(player.current.client)
|
||||
player.current.client.screen -= player.vampire.blood_hud
|
||||
player.current.client.screen -= player.vampire.frenzy_hud
|
||||
player.current.client.screen -= vampire.blood_hud
|
||||
player.current.client.screen -= vampire.frenzy_hud
|
||||
player.current.verbs -= /datum/antagonist/vampire/proc/vampire_help
|
||||
for(var/datum/power/vampire/P in vampirepowers)
|
||||
player.current.verbs -= P.verbpath
|
||||
QDEL_NULL(player.vampire)
|
||||
QDEL_NULL(vampire)
|
||||
|
||||
/datum/antagonist/vampire/handle_latelogin(var/mob/user)
|
||||
var/datum/mind/M = user.mind
|
||||
if(!M)
|
||||
return
|
||||
if(M.vampire.status & VAMP_ISTHRALL)
|
||||
var/datum/vampire/vampire = M.antag_datums[MODE_VAMPIRE]
|
||||
if(vampire.master_image)
|
||||
user.client.images += vampire.master_image
|
||||
if(vampire.status & VAMP_ISTHRALL)
|
||||
return
|
||||
M.vampire.blood_hud = new /obj/screen/vampire/blood()
|
||||
M.vampire.frenzy_hud = new /obj/screen/vampire/frenzy()
|
||||
M.vampire.blood_suck_hud = new /obj/screen/vampire/suck()
|
||||
user.client.screen += M.vampire.blood_hud
|
||||
user.client.screen += M.vampire.frenzy_hud
|
||||
user.client.screen += M.vampire.blood_suck_hud
|
||||
vampire.blood_hud = new /obj/screen/vampire/blood()
|
||||
vampire.frenzy_hud = new /obj/screen/vampire/frenzy()
|
||||
vampire.blood_suck_hud = new /obj/screen/vampire/suck()
|
||||
user.client.screen += vampire.blood_hud
|
||||
user.client.screen += vampire.frenzy_hud
|
||||
user.client.screen += vampire.blood_suck_hud
|
||||
|
||||
for(var/thrall in vampire.thralls)
|
||||
var/mob/T = thrall
|
||||
var/datum/vampire/T_vampire = T.mind.antag_datums[MODE_VAMPIRE]
|
||||
if(T_vampire.thrall_image)
|
||||
user.client.images += T_vampire.thrall_image
|
||||
|
||||
/datum/antagonist/vampire/proc/vampire_help()
|
||||
set category = "Vampire"
|
||||
|
||||
@@ -320,7 +320,7 @@ var/list/mob/living/forced_ambiance_list = new
|
||||
L.lastarea = get_area(L.loc)
|
||||
var/area/newarea = get_area(L.loc)
|
||||
var/area/oldarea = L.lastarea
|
||||
if((oldarea.has_gravity() == 0) && (newarea.has_gravity() == 1) && (L.m_intent == "run")) // Being ready when you change areas gives you a chance to avoid falling all together.
|
||||
if((oldarea.has_gravity() == 0) && (newarea.has_gravity() == 1) && (L.m_intent == M_RUN)) // Being ready when you change areas gives you a chance to avoid falling all together.
|
||||
thunk(L)
|
||||
L.update_floating( L.Check_Dense_Object() )
|
||||
|
||||
@@ -375,7 +375,7 @@ var/list/mob/living/forced_ambiance_list = new
|
||||
if(H.Check_Shoegrip(FALSE))
|
||||
return
|
||||
|
||||
if(H.m_intent == "run")
|
||||
if(H.m_intent == M_RUN)
|
||||
H.AdjustStunned(2)
|
||||
H.AdjustWeakened(2)
|
||||
else
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
name = "burglars"
|
||||
config_tag = "burglars"
|
||||
max_players = 15
|
||||
required_enemies = 1
|
||||
required_enemies = 2
|
||||
required_players = 4
|
||||
round_description = "Something tiny is on the horizon! Is it the distance, or...?"
|
||||
extended_round_description = "Two of the Orion Spur's best and brightest (or so they were told) have been tasked with burglarizing a station that will change the way capitalism grips this galaxy forever (or so they were told). It is up to the crew to repel them, and up to them to survive and possibly thrive."
|
||||
|
||||
@@ -40,8 +40,8 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
|
||||
/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA)
|
||||
var/datum/changeling/changeling = null
|
||||
if(src.mind && src.mind.changeling)
|
||||
changeling = src.mind.changeling
|
||||
if(mind)
|
||||
changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
@@ -58,8 +58,8 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
|
||||
if(!mind)
|
||||
return
|
||||
if(!mind.changeling)
|
||||
mind.changeling = new /datum/changeling(gender)
|
||||
if(!mind.antag_datums[MODE_CHANGELING])
|
||||
mind.antag_datums[MODE_CHANGELING] = new /datum/changeling(gender)
|
||||
|
||||
verbs += /datum/changeling/proc/EvolutionMenu
|
||||
add_language("Changeling")
|
||||
@@ -70,34 +70,39 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
for(var/P in powers)
|
||||
powerinstances += new P()
|
||||
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
|
||||
// Code to auto-purchase free powers.
|
||||
for(var/datum/power/changeling/P in powerinstances)
|
||||
if(!P.genomecost) // Is it free?
|
||||
if(!(P in mind.changeling.purchasedpowers)) // Do we not have it already?
|
||||
mind.changeling.purchasePower(mind, P.name, 0) // Purchase it. Don't remake our verbs, we're doing it after this.
|
||||
if(!(P in changeling.purchasedpowers)) // Do we not have it already?
|
||||
changeling.purchasePower(mind, P.name, 0) // Purchase it. Don't remake our verbs, we're doing it after this.
|
||||
|
||||
for(var/datum/power/changeling/P in mind.changeling.purchasedpowers)
|
||||
for(var/datum/power/changeling/P in changeling.purchasedpowers)
|
||||
if(P.isVerb)
|
||||
if(lesser_form && !P.allowduringlesserform) continue
|
||||
if(!(P in src.verbs))
|
||||
src.verbs += P.verbpath
|
||||
|
||||
for(var/language in languages)
|
||||
mind.changeling.absorbed_languages |= language
|
||||
changeling.absorbed_languages |= language
|
||||
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(istype(H))
|
||||
var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.get_cloning_variant(), H.languages)
|
||||
absorbDNA(newDNA)
|
||||
mind.changeling.mimiced_accent = H.accent
|
||||
changeling.mimiced_accent = H.accent
|
||||
|
||||
return TRUE
|
||||
|
||||
//removes our changeling verbs
|
||||
/mob/proc/remove_changeling_powers()
|
||||
if(!mind || !mind.changeling)
|
||||
var/datum/changeling/changeling
|
||||
if(mind)
|
||||
changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
if(!changeling)
|
||||
return
|
||||
for(var/datum/power/changeling/P in mind.changeling.purchasedpowers)
|
||||
for(var/datum/power/changeling/P in changeling.purchasedpowers)
|
||||
if(P.isVerb)
|
||||
verbs -= P.verbpath
|
||||
|
||||
@@ -110,7 +115,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
if(!iscarbon(src))
|
||||
return
|
||||
|
||||
var/datum/changeling/changeling = src.mind.changeling
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
if(!changeling)
|
||||
log_and_message_admins("has the changeling_transform() verb but is not a changeling.", src, get_turf(src))
|
||||
return
|
||||
|
||||
@@ -220,9 +220,10 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
set category = "Changeling"
|
||||
set desc = "Buy new abilities with the genomes we obtained."
|
||||
|
||||
if(!usr || !usr.mind || !usr.mind.changeling)
|
||||
var/datum/changeling/changeling = usr.mind.antag_datums[MODE_CHANGELING]
|
||||
if(!usr || !usr.mind || !changeling)
|
||||
return
|
||||
src = usr.mind.changeling
|
||||
src = changeling
|
||||
|
||||
if(!powerinstances.len)
|
||||
for(var/P in powers)
|
||||
@@ -480,7 +481,8 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
|
||||
|
||||
/datum/changeling/proc/purchasePower(var/datum/mind/M, var/power_name, var/remake_verbs = 1)
|
||||
if(!M || !M.changeling)
|
||||
var/datum/changeling/changeling = M.antag_datums[MODE_CHANGELING]
|
||||
if(!M || !changeling)
|
||||
return
|
||||
|
||||
var/datum/power/changeling/power = power_name
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#define CHECK_STING(holder, target) \
|
||||
if(isliving(target) && holder.a_intent == I_HURT && holder.mind && holder.mind.changeling && holder.mind.changeling.prepared_sting) { \
|
||||
if(holder.mind.changeling.prepared_sting.can_sting(A)) { \
|
||||
holder.mind.changeling.prepared_sting.do_sting(A); \
|
||||
QDEL_NULL(holder.mind.changeling.prepared_sting); \
|
||||
return; \
|
||||
if(isliving(target) && holder.a_intent == I_HURT && holder.mind) { \
|
||||
var/datum/changeling/changeling = holder.mind.antag_datums[MODE_CHANGELING]; \
|
||||
if(changeling && changeling.prepared_sting) { \
|
||||
if(changeling.prepared_sting.can_sting(A)) { \
|
||||
changeling.prepared_sting.do_sting(A); \
|
||||
QDEL_NULL(changeling.prepared_sting); \
|
||||
return; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
set desc = "Relinquish your life and enter the land of the dead."
|
||||
|
||||
announce_ghost_joinleave(ghostize(1, 0))
|
||||
changeling_mob.mind.changeling.hivemind_members -= src
|
||||
var/datum/changeling/changeling = changeling_mob.mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.hivemind_members -= src
|
||||
relay_hivemind(SPAN_NOTICE("[src] has left our hivemind to join the living dead."), changeling_mob)
|
||||
|
||||
/mob/abstract/hivemind/proc/add_to_hivemind(var/mob/original_body, var/mob/living/carbon/human/ling)
|
||||
@@ -28,7 +29,8 @@
|
||||
ckey = original_body.ckey
|
||||
changeling_mob = ling
|
||||
if(changeling_mob)
|
||||
changeling_mob.mind.changeling.hivemind_members[name] = src
|
||||
var/datum/changeling/changeling = changeling_mob.mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.hivemind_members[name] = src
|
||||
introduction(changeling_mob)
|
||||
|
||||
/mob/abstract/hivemind/proc/introduction(var/mob/living/carbon/human/ling)
|
||||
@@ -62,7 +64,8 @@
|
||||
var/mob/living/simple_animal/hostile/morph/M = new /mob/living/simple_animal/hostile/morph(get_turf(changeling_mob))
|
||||
M.stop_thinking = TRUE // prevent the AI from taking over when the player ghosts
|
||||
M.ckey = ckey
|
||||
changeling_mob.mind.changeling.hivemind_members -= src
|
||||
var/datum/changeling/changeling = changeling_mob.mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.hivemind_members -= src
|
||||
|
||||
to_chat(M, SPAN_DANGER(FONT_LARGE("You are a morph, released by [changeling_mob]!")))
|
||||
to_chat(M, SPAN_DANGER("As a morph, you can disguise as objects by alt-clicking on them."))
|
||||
|
||||
@@ -287,8 +287,8 @@
|
||||
C.digitalcamo = !C.digitalcamo
|
||||
|
||||
spawn(0)
|
||||
while(C && C.digitalcamo && C.mind && C.mind.changeling)
|
||||
C.mind.changeling.chem_charges = max(C.mind.changeling.chem_charges - 1, 0)
|
||||
while(C && C.digitalcamo && C.mind && changeling)
|
||||
changeling.chem_charges = max(changeling.chem_charges - 1, 0)
|
||||
sleep(40)
|
||||
|
||||
src.verbs -= /mob/proc/changeling_digitalcamo
|
||||
@@ -305,7 +305,7 @@
|
||||
var/datum/changeling/changeling = changeling_power(30, 0, 100, UNCONSCIOUS)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
src.mind.changeling.chem_charges -= 30
|
||||
changeling.chem_charges -= 30
|
||||
|
||||
var/mob/living/carbon/human/C = src
|
||||
spawn(0)
|
||||
@@ -366,11 +366,11 @@
|
||||
feedback_add_details("changeling_powers","MV")
|
||||
|
||||
spawn(0)
|
||||
while(src && src.mind && src.mind.changeling && src.mind.changeling.mimicing)
|
||||
src.mind.changeling.chem_charges = max(src.mind.changeling.chem_charges - 1, 0)
|
||||
while(src?.mind && changeling?.mimicing)
|
||||
changeling.chem_charges = max(changeling.chem_charges - 1, 0)
|
||||
sleep(40)
|
||||
if(src && src.mind && src.mind.changeling)
|
||||
src.mind.changeling.mimicing = ""
|
||||
if(changeling)
|
||||
changeling.mimicing = ""
|
||||
|
||||
/mob/proc/armblades()
|
||||
set category = "Changeling"
|
||||
@@ -380,7 +380,7 @@
|
||||
var/datum/changeling/changeling = changeling_power(20, 0, 0)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
src.mind.changeling.chem_charges -= 20
|
||||
changeling.chem_charges -= 20
|
||||
|
||||
var/mob/living/carbon/M = src
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
var/datum/changeling/changeling = changeling_power(20,0,0)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
src.mind.changeling.chem_charges -= 20
|
||||
changeling.chem_charges -= 20
|
||||
|
||||
var/mob/living/carbon/M = src
|
||||
|
||||
@@ -465,7 +465,7 @@
|
||||
if(alert("Are we sure we wish to reveal ourselves? This will only revert after ten minutes.", , "Yes", "No") == "No") //Changelings have to confirm whether they want to go full horrorform
|
||||
return
|
||||
|
||||
src.mind.changeling.chem_charges -= 40
|
||||
changeling.chem_charges -= 40
|
||||
|
||||
M.visible_message("<span class='danger'>[M] writhes and contorts, their body expanding to inhuman proportions!</span>", \
|
||||
"<span class='danger'>We begin our transformation to our true form!</span>")
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
set name = "Hivemind Eject"
|
||||
set desc = "Ejects a member of our internal hivemind."
|
||||
|
||||
if(!(mind?.changeling))
|
||||
var/datum/changeling/changeling = changeling_power()
|
||||
if(!changeling)
|
||||
return
|
||||
if(!mind.changeling.hivemind_members.len)
|
||||
return
|
||||
var/chosen_player = input("Choose a hivemind member to eject.", "Eject") as null|anything in mind.changeling.hivemind_members
|
||||
var/chosen_player = input("Choose a hivemind member to eject.", "Eject") as null|anything in changeling.hivemind_members
|
||||
if(!chosen_player)
|
||||
return
|
||||
var/mob/abstract/hivemind/M = mind.changeling.hivemind_members[chosen_player]
|
||||
var/mob/abstract/hivemind/M = changeling.hivemind_members[chosen_player]
|
||||
M.ghost() //Deuces
|
||||
return TRUE
|
||||
|
||||
@@ -27,9 +26,10 @@
|
||||
return TRUE
|
||||
|
||||
/mob/proc/relay_hivemind(var/message, var/mob/ling)
|
||||
if(ling.mind?.changeling)
|
||||
for(var/H in ling.mind.changeling.hivemind_members) // tell the others in the hivemind
|
||||
var/mob/M = ling.mind.changeling.hivemind_members[H]
|
||||
var/datum/changeling/changeling = ling.mind.antag_datums[MODE_CHANGELING]
|
||||
if(changeling)
|
||||
for(var/H in changeling.hivemind_members) // tell the others in the hivemind
|
||||
var/mob/M = changeling.hivemind_members[H]
|
||||
to_chat(M, message)
|
||||
to_chat(ling, message)
|
||||
|
||||
@@ -41,17 +41,18 @@
|
||||
set name = "Hivemind Release Morph"
|
||||
set desc = "Releases a member of our internal hivemind as a morph, at the cost of one of our limbs."
|
||||
|
||||
if(!mind?.changeling)
|
||||
var/datum/changeling/changeling = changeling_power()
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
if(!length(mind.changeling.hivemind_members))
|
||||
if(!length(changeling.hivemind_members))
|
||||
to_chat(src, SPAN_WARNING("We have no internal hivemind members to release!"))
|
||||
return
|
||||
|
||||
var/chosen_player = input("Choose a hivemind member to release as a morph.", "Hivemind Morph") as null|anything in mind.changeling.hivemind_members
|
||||
var/chosen_player = input("Choose a hivemind member to release as a morph.", "Hivemind Morph") as null|anything in changeling.hivemind_members
|
||||
if(!chosen_player)
|
||||
return
|
||||
|
||||
var/mob/abstract/hivemind/M = mind.changeling.hivemind_members[chosen_player]
|
||||
var/mob/abstract/hivemind/M = changeling.hivemind_members[chosen_player]
|
||||
M.release_as_morph()
|
||||
return TRUE
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
//Speeds up chemical regeneration
|
||||
/mob/proc/changeling_fastchemical()
|
||||
src.mind.changeling.chem_recharge_rate *= 2.5
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.chem_recharge_rate *= 2.5
|
||||
return TRUE
|
||||
|
||||
//Increases maximum chemical storage
|
||||
/mob/proc/changeling_engorgedglands()
|
||||
src.mind.changeling.chem_storage += 50
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.chem_storage += 50
|
||||
return TRUE
|
||||
|
||||
// HIVE MIND UPLOAD/DOWNLOAD DNA
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
stealthy = set_stealthy
|
||||
|
||||
/datum/changeling_sting/proc/can_sting(var/mob/living/target)
|
||||
if(!target)
|
||||
if(!target || !owner.mind)
|
||||
return FALSE
|
||||
if(!(target in view(owner.mind.changeling.sting_range)))
|
||||
var/datum/changeling/changeling = owner.mind.antag_datums[MODE_CHANGELING]
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
if(!owner.sting_can_reach(target, owner.mind.changeling.sting_range))
|
||||
if(!(target in view(changeling.sting_range)))
|
||||
return FALSE
|
||||
if(!owner.sting_can_reach(target, changeling.sting_range))
|
||||
to_chat(owner, SPAN_WARNING("Our sting can't reach here!"))
|
||||
return FALSE
|
||||
if(!owner.changeling_power(required_chems))
|
||||
@@ -30,8 +33,9 @@
|
||||
return TRUE
|
||||
|
||||
/datum/changeling_sting/proc/do_sting(var/mob/living/target)
|
||||
owner.mind.changeling.chem_charges -= required_chems
|
||||
owner.mind.changeling.sting_range = 1
|
||||
var/datum/changeling/changeling = owner.mind.antag_datums[MODE_CHANGELING]
|
||||
changeling.chem_charges -= required_chems
|
||||
changeling.sting_range = 1
|
||||
owner.verbs -= verb_path
|
||||
ADD_VERB_IN(owner, 10, verb_path)
|
||||
|
||||
@@ -53,17 +57,18 @@
|
||||
feedback_add_details("changeling_powers", feedback_tag)
|
||||
|
||||
/mob/proc/changeling_sting(var/required_chems = 0, var/verb_path, var/datum_path, var/stealthy = FALSE)
|
||||
if(istype(mind.changeling.prepared_sting, datum_path))
|
||||
to_chat(src, SPAN_NOTICE("You unprepare the <b>[mind.changeling.prepared_sting.name]</b>."))
|
||||
QDEL_NULL(mind.changeling.prepared_sting)
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
if(istype(changeling.prepared_sting, datum_path))
|
||||
to_chat(src, SPAN_NOTICE("You unprepare the <b>[changeling.prepared_sting.name]</b>."))
|
||||
QDEL_NULL(changeling.prepared_sting)
|
||||
return
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(required_chems)
|
||||
changeling = changeling_power(required_chems)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
|
||||
changeling.prepared_sting = new datum_path(src, verb_path, required_chems, stealthy)
|
||||
to_chat(src, SPAN_NOTICE("You prepare to fire the <b>[mind.changeling.prepared_sting.name]</b>."))
|
||||
to_chat(src, SPAN_NOTICE("You prepare to fire the <b>[changeling.prepared_sting.name]</b>."))
|
||||
return TRUE
|
||||
|
||||
/mob/proc/changeling_hallucinate_sting()
|
||||
@@ -153,8 +158,8 @@
|
||||
set name = "Transformation Sting (40)"
|
||||
set desc = "Causes the target to permanently transform into a collected DNA subject."
|
||||
|
||||
|
||||
if(!length(mind.changeling.absorbed_dna))
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
if(!length(changeling.absorbed_dna))
|
||||
to_chat(src, SPAN_WARNING("You have no DNA to load this sting with!"))
|
||||
return
|
||||
|
||||
@@ -163,23 +168,23 @@
|
||||
return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/thing in mind.changeling.absorbed_dna)
|
||||
for(var/thing in changeling.absorbed_dna)
|
||||
var/datum/absorbed_dna/DNA = thing
|
||||
names += "[DNA.name]"
|
||||
|
||||
var/S = input(src, "Select the target DNA:", "Target DNA") as null|anything in names
|
||||
if(!S)
|
||||
QDEL_NULL(mind.changeling.prepared_sting)
|
||||
QDEL_NULL(changeling.prepared_sting)
|
||||
to_chat(src, SPAN_NOTICE("With no DNA chosen, you unprepare the sting."))
|
||||
return
|
||||
|
||||
var/datum/absorbed_dna/chosen_dna = mind.changeling.GetDNA(S)
|
||||
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
QDEL_NULL(mind.changeling.prepared_sting)
|
||||
QDEL_NULL(changeling.prepared_sting)
|
||||
to_chat(src, SPAN_WARNING("Something went wrong, you do not possess the DNA of this person."))
|
||||
return
|
||||
|
||||
var/datum/changeling_sting/transformation/T = mind.changeling.prepared_sting
|
||||
var/datum/changeling_sting/transformation/T = changeling.prepared_sting
|
||||
T.dna_payload = chosen_dna
|
||||
|
||||
/datum/changeling_sting/transformation
|
||||
@@ -253,11 +258,12 @@
|
||||
set name = "Ranged Sting (10)"
|
||||
set desc = "Your next sting ability can be used against targets 2 squares away."
|
||||
|
||||
if(mind.changeling.sting_range > 1)
|
||||
var/datum/changeling/changeling = mind.antag_datums[MODE_CHANGELING]
|
||||
if(changeling.sting_range > 1)
|
||||
to_chat(src, SPAN_WARNING("The range of your sting has already been boosted!"))
|
||||
return
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(10, 0, 100)
|
||||
changeling = changeling_power(10, 0, 100)
|
||||
if(!changeling)
|
||||
return FALSE
|
||||
changeling.chem_charges -= 10
|
||||
@@ -266,4 +272,4 @@
|
||||
src.verbs -= /mob/proc/changeling_boost_range
|
||||
ADD_VERB_IN(src, 5, /mob/proc/changeling_boost_range)
|
||||
feedback_add_details("changeling_powers", "RS")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -80,17 +80,18 @@
|
||||
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.get_cloning_variant(), T.languages)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
if(T.mind && T.mind.changeling)
|
||||
if(T.mind.changeling.absorbed_dna)
|
||||
for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
|
||||
var/datum/changeling/changeling_check = T.mind.antag_datums[MODE_CHANGELING]
|
||||
if(changeling_check)
|
||||
if(changeling_check.absorbed_dna)
|
||||
for(var/datum/absorbed_dna/dna_data in changeling_check.absorbed_dna) //steal all their loot
|
||||
if(changeling.GetDNA(dna_data.name))
|
||||
continue
|
||||
absorbDNA(dna_data)
|
||||
changeling.absorbedcount++
|
||||
T.mind.changeling.absorbed_dna.len = TRUE
|
||||
changeling_check.absorbed_dna.len = TRUE
|
||||
|
||||
if(T.mind.changeling.purchasedpowers)
|
||||
for(var/datum/power/changeling/Tp in T.mind.changeling.purchasedpowers) //who the fuck named these variables?
|
||||
if(changeling_check.purchasedpowers)
|
||||
for(var/datum/power/changeling/Tp in changeling_check.purchasedpowers) //who the fuck named these variables?
|
||||
if(Tp in changeling.purchasedpowers)
|
||||
continue
|
||||
else
|
||||
@@ -100,11 +101,11 @@
|
||||
else
|
||||
src.make_changeling()
|
||||
|
||||
changeling.chem_charges += T.mind.changeling.chem_charges
|
||||
changeling.geneticpoints += T.mind.changeling.geneticpoints
|
||||
T.mind.changeling.chem_charges = 0
|
||||
T.mind.changeling.geneticpoints = 0
|
||||
T.mind.changeling.absorbedcount = 0
|
||||
changeling.chem_charges += changeling_check.chem_charges
|
||||
changeling.geneticpoints += changeling_check.geneticpoints
|
||||
changeling_check.chem_charges = 0
|
||||
changeling_check.geneticpoints = 0
|
||||
changeling_check.absorbedcount = 0
|
||||
|
||||
changeling.absorbedcount++
|
||||
changeling.isabsorbing = FALSE
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/datum/cultist
|
||||
var/list/memorized_runes
|
||||
|
||||
/datum/cultist/proc/memorize_rune()
|
||||
set name = "Memorize Rune"
|
||||
set desc = "Stand atop a rune and memorize it, allowing you to draw it without your tome."
|
||||
set category = "Cultist"
|
||||
|
||||
if(!ishuman(usr))
|
||||
to_chat(usr, SPAN_WARNING("Your form is too simple to memorize runes!"))
|
||||
return
|
||||
|
||||
if(usr.stat || usr.incapacitated())
|
||||
to_chat(usr, SPAN_WARNING("You are in no shape to do this."))
|
||||
return
|
||||
|
||||
var/datum/cultist/C = usr.mind.antag_datums[MODE_CULTIST]
|
||||
|
||||
if(LAZYLEN(C.memorized_runes) >= 3)
|
||||
to_chat(usr, SPAN_WARNING("You can only memorize up to three runes!"))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/effect/rune/R = locate() in get_turf(H)
|
||||
if(R)
|
||||
if(!R.rune.can_memorize())
|
||||
to_chat(H, SPAN_WARNING("This rune is too complex to be memorized!"))
|
||||
return
|
||||
if(LAZYISIN(C.memorized_runes, R.rune.name))
|
||||
to_chat(H, SPAN_WARNING("This rune is already memorized!"))
|
||||
return
|
||||
H.visible_message("<b>[H]</b> bends over and runs their hands across \the [src].", SPAN_NOTICE("You bend over and run your hands across the patterns of the rune, slowly memorizing it."))
|
||||
if(!do_after(H, 10 SECONDS, TRUE))
|
||||
return
|
||||
LAZYSET(C.memorized_runes, R.rune.name, R.rune.type)
|
||||
to_chat(H, SPAN_NOTICE("You memorize the [R.rune.name]! You will now be able to scribe it at will."))
|
||||
else
|
||||
to_chat(H, SPAN_WARNING("There was no rune beneath you to memorize."))
|
||||
|
||||
/datum/cultist/proc/forget_rune()
|
||||
set name = "Forget Rune"
|
||||
set desc = "Cleanse the knowledge of a rune from your memory, freeing up space for another."
|
||||
set category = "Cultist"
|
||||
|
||||
if(!ishuman(usr))
|
||||
to_chat(usr, SPAN_WARNING("Your form is too simple to memorize runes!"))
|
||||
return
|
||||
|
||||
if(usr.stat || usr.incapacitated())
|
||||
to_chat(usr, SPAN_WARNING("You are in no shape to do this."))
|
||||
return
|
||||
|
||||
var/datum/cultist/C = usr.mind.antag_datums[MODE_CULTIST]
|
||||
|
||||
if(!LAZYLEN(C.memorized_runes))
|
||||
to_chat(usr, SPAN_WARNING("You have no runes memorized!"))
|
||||
return
|
||||
|
||||
var/chosen_rune = input("Choose a rune to forget.") as null|anything in C.memorized_runes
|
||||
if(!chosen_rune)
|
||||
return
|
||||
LAZYREMOVE(C.memorized_runes, chosen_rune)
|
||||
|
||||
/datum/cultist/proc/scribe_rune()
|
||||
set name = "Scribe Rune"
|
||||
set desc = "Scribe a rune that you have memorized."
|
||||
set category = "Cultist"
|
||||
|
||||
if(!ishuman(usr))
|
||||
to_chat(usr, SPAN_WARNING("Your form is too simple to memorize runes!"))
|
||||
return
|
||||
|
||||
var/datum/cultist/C = usr.mind.antag_datums[MODE_CULTIST]
|
||||
|
||||
if(!LAZYLEN(C.memorized_runes))
|
||||
to_chat(usr, SPAN_WARNING("You have no runes memorized!"))
|
||||
return
|
||||
|
||||
if(usr.stat || usr.incapacitated())
|
||||
to_chat(usr, SPAN_WARNING("You are in no shape to do this."))
|
||||
return
|
||||
|
||||
var/chosen_rune = input("Choose a rune to scribe.") as null|anything in C.memorized_runes
|
||||
if(!chosen_rune)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/human/H = usr
|
||||
H.visible_message(SPAN_CULT("Blood flows out from \the [H]'s hands, taking shape beneath them..."))
|
||||
H.drip(4)
|
||||
|
||||
if(do_after(H, 15 SECONDS))
|
||||
create_rune(H, chosen_rune)
|
||||
|
||||
/proc/create_rune(var/mob/living/carbon/human/scribe, var/chosen_rune)
|
||||
if(scribe.stat || scribe.incapacitated())
|
||||
to_chat(scribe, SPAN_WARNING("You are in no shape to do this."))
|
||||
return
|
||||
|
||||
var/area/A = get_area(scribe)
|
||||
//prevents using multiple dialogs to layer runes.
|
||||
if(locate(/obj/effect/rune) in get_turf(scribe)) //This is check is done twice. once when choosing to scribe a rune, once here
|
||||
to_chat(scribe, SPAN_WARNING("There is already a rune in this location."))
|
||||
return
|
||||
|
||||
log_and_message_admins("created \an [chosen_rune] at \the [A.name] - [scribe.loc.x]-[scribe.loc.y]-[scribe.loc.z].") //only message if it's actually made
|
||||
|
||||
var/obj/effect/rune/R = new(get_turf(scribe), SScult.runes_by_name[chosen_rune])
|
||||
to_chat(scribe, SPAN_CULT("You finish drawing the Geometer's markings."))
|
||||
R.blood_DNA = list()
|
||||
R.blood_DNA[scribe.dna.unique_enzymes] = scribe.dna.b_type
|
||||
R.color = scribe.species.blood_color
|
||||
R.filters = filter(type="drop_shadow", x = 1, y = 1, size = 4, color = scribe.species.blood_color)
|
||||
@@ -95,23 +95,7 @@
|
||||
scribe.drip(4)
|
||||
|
||||
if(do_after(scribe, 50))
|
||||
var/area/A = get_area(scribe)
|
||||
if(use_check_and_message(scribe))
|
||||
return
|
||||
|
||||
//prevents using multiple dialogs to layer runes.
|
||||
if(locate(/obj/effect/rune) in get_turf(scribe)) //This is check is done twice. once when choosing to scribe a rune, once here
|
||||
to_chat(scribe, SPAN_WARNING("There is already a rune in this location."))
|
||||
return
|
||||
|
||||
log_and_message_admins("created \an [chosen_rune] at \the [A.name] - [user.loc.x]-[user.loc.y]-[user.loc.z].") //only message if it's actually made
|
||||
|
||||
var/obj/effect/rune/R = new(get_turf(scribe), SScult.runes_by_name[chosen_rune])
|
||||
to_chat(scribe, SPAN_CULT("You finish drawing the Geometer's markings."))
|
||||
R.blood_DNA = list()
|
||||
R.blood_DNA[scribe.dna.unique_enzymes] = scribe.dna.b_type
|
||||
R.color = scribe.species.blood_color
|
||||
R.filters = filter(type="drop_shadow", x = 1, y = 1, size = 4, color = scribe.species.blood_color)
|
||||
create_rune(scribe, chosen_rune)
|
||||
else
|
||||
to_chat(user, SPAN_CULT("The book seems full of illegible scribbles."))
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#define NO_TALISMAN 1
|
||||
#define HAS_SPECIAL_TALISMAN_ACTION 2
|
||||
#define CAN_MEMORIZE 2
|
||||
#define HAS_SPECIAL_TALISMAN_ACTION 4
|
||||
|
||||
/datum/rune
|
||||
var/name // The rune's name.
|
||||
@@ -42,3 +43,6 @@
|
||||
|
||||
/datum/rune/proc/can_be_talisman()
|
||||
return !(rune_flags & NO_TALISMAN)
|
||||
|
||||
/datum/rune/proc/can_memorize()
|
||||
return rune_flags & CAN_MEMORIZE
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/rune/communicate
|
||||
name = "communication rune"
|
||||
desc = "This rune is used to send a message to all acolytes."
|
||||
rune_flags = CAN_MEMORIZE
|
||||
|
||||
/datum/rune/communicate/do_rune_action(mob/living/user, atom/movable/A)
|
||||
var/input = input(user, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "")//sanitize() below, say() and whisper() have their own
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/convert
|
||||
name = "conversion rune"
|
||||
desc = "A rune used to convert the Unenlightened."
|
||||
rune_flags = NO_TALISMAN
|
||||
rune_flags = NO_TALISMAN | CAN_MEMORIZE
|
||||
|
||||
var/list/converting
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/talisman
|
||||
name = "talisman creation rune"
|
||||
desc = "This rune creates a talisman out of a rune around it."
|
||||
rune_flags = NO_TALISMAN
|
||||
rune_flags = NO_TALISMAN | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/talisman/do_rune_action(mob/living/user, atom/movable/A)
|
||||
var/obj/item/paper/new_talisman
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/deafen
|
||||
name = "deafening rune"
|
||||
desc = "This rune is used to deafen all unbelievers in a wide range around us."
|
||||
rune_flags = HAS_SPECIAL_TALISMAN_ACTION
|
||||
rune_flags = HAS_SPECIAL_TALISMAN_ACTION | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/deafen/do_rune_action(mob/living/user, atom/movable/A)
|
||||
do_deafen(user, A, 1, TRUE)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/ethereal
|
||||
name = "ethereal rune"
|
||||
desc = "This rune is used to temporarily send an acolyte into the afterlife."
|
||||
rune_flags = NO_TALISMAN
|
||||
rune_flags = NO_TALISMAN | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/ethereal/do_rune_action(mob/living/user, atom/movable/A) //some bits copypastaed from admin tools - Urist
|
||||
if(get_turf(user) == get_turf(A) && ishuman(user))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/rune/hide_runes
|
||||
name = "concealment rune"
|
||||
desc = "This rune is used to conceal other runes in an area around us."
|
||||
rune_flags = CAN_MEMORIZE
|
||||
|
||||
/datum/rune/hide_runes/do_rune_action(mob/living/user, atom/movable/A)
|
||||
var/rune_found
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/raise_dead
|
||||
name = "revival rune"
|
||||
desc = "This rune is used to revive a body in exchange for a dead sacrifice."
|
||||
rune_flags = NO_TALISMAN
|
||||
rune_flags = NO_TALISMAN | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/raise_dead/do_rune_action(mob/living/user, atom/movable/A)
|
||||
var/mob/living/carbon/human/corpse_to_raise
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/reveal_runes
|
||||
name = "revealing rune"
|
||||
desc = "This rune is used to reveal hidden runes in a radius around us."
|
||||
rune_flags = HAS_SPECIAL_TALISMAN_ACTION
|
||||
rune_flags = HAS_SPECIAL_TALISMAN_ACTION | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/reveal_runes/do_rune_action(mob/living/user, atom/movable/A)
|
||||
reveal(user, A, 6, SPAN_WARNING("\The [A] turns into red dust, reveaing the surrounding runes."))
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
if(iscultist(user) || isobserver(user))
|
||||
to_chat(user, rune.get_cultist_fluff_text())
|
||||
to_chat(user, "This rune [rune.can_be_talisman() ? "<span class='cult'><b><i>can</i></b></span>" : "<span class='warning'><b><i>cannot</i></b></span>"] be turned into a talisman.")
|
||||
to_chat(user, "This rune [rune.can_memorize() ? "<span class='cult'><b><i>can</i></b></span>" : "<span class='warning'><b><i>cannot</i></b></span>"] be memorized to be scribed without a tome.")
|
||||
else
|
||||
to_chat(user, rune.get_normal_fluff_text())
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/sacrifice
|
||||
name = "sacrificial rune"
|
||||
desc = "This rune is used to sacrifice an unbeliever."
|
||||
rune_flags = NO_TALISMAN
|
||||
rune_flags = NO_TALISMAN | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/sacrifice/do_rune_action(mob/living/user, atom/movable/A)
|
||||
var/list/mob/living/carbon/human/cultists_in_range = list()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/datum/rune/see_invisible
|
||||
name = "visibility rune"
|
||||
desc = "This rune is used to see the invisible."
|
||||
rune_flags = NO_TALISMAN
|
||||
rune_flags = NO_TALISMAN | CAN_MEMORIZE
|
||||
|
||||
/datum/rune/see_invisible/do_rune_action(mob/living/user, atom/movable/A)
|
||||
if(user.seer == TRUE)
|
||||
|
||||
@@ -62,5 +62,9 @@
|
||||
/obj/item/clothing/head/festive/santa
|
||||
name = "santa hat"
|
||||
icon_state = "santahat"
|
||||
desc = "A cheap fabric santa hat."
|
||||
|
||||
/obj/item/clothing/head/festive/santa/beard
|
||||
desc = "A cheap fabric santa hat, this one with a beard."
|
||||
body_parts_covered = HEAD
|
||||
desc = "A cheap fabric santa hat, with a fake beard and a little bell at the end."
|
||||
icon_state = "santahat_alt"
|
||||
@@ -636,20 +636,6 @@ var/global/list/additional_antag_types = list()
|
||||
candidates += player.mind
|
||||
players -= player
|
||||
|
||||
// If we don't have enough antags, draft people who voted for the round.
|
||||
if(candidates.len < required_enemies)
|
||||
var/initial_candidates = candidates.len
|
||||
|
||||
for(var/mob/abstract/new_player/player in players)
|
||||
if(player.ckey in SSvote.round_voters)
|
||||
log_debug("[player.key] voted for this round, so we are drafting them.")
|
||||
candidates += player.mind
|
||||
players -= player
|
||||
|
||||
if (candidates.len >= required_enemies)
|
||||
log_debug("Drafted [candidates.len - initial_candidates] new antags from voters.")
|
||||
break
|
||||
|
||||
return candidates // Returns: The number of people who had the antagonist role set to yes, regardless of recomended_enemies, if that number is greater than required_enemies
|
||||
// required_enemies if the number of people with that role set to yes is less than recomended_enemies,
|
||||
// Less if there are not enough valid players in the game entirely to make required_enemies.
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
extended_round_description = "Burglars and heisters spawn during this round."
|
||||
config_tag = "conflict"
|
||||
required_players = 15
|
||||
required_enemies = 5
|
||||
required_enemies = 6
|
||||
antag_tags = list(MODE_RAIDER, MODE_BURGLAR)
|
||||
require_all_templates = TRUE
|
||||
@@ -600,7 +600,8 @@ datum/objective/capture
|
||||
n_p ++
|
||||
else if (SSticker.current_state == GAME_STATE_PLAYING)
|
||||
for(var/mob/living/carbon/human/P in player_list)
|
||||
if(P.client && !(P.mind.changeling) && P.mind!=owner)
|
||||
var/datum/changeling/changeling = P.mind.antag_datums[MODE_CHANGELING]
|
||||
if(P.client && !changeling && P.mind != owner)
|
||||
n_p ++
|
||||
target_amount = min(target_amount, n_p)
|
||||
|
||||
@@ -608,7 +609,8 @@ datum/objective/capture
|
||||
return target_amount
|
||||
|
||||
check_completion()
|
||||
if(owner && owner.changeling && owner.changeling.absorbed_dna && (owner.changeling.absorbedcount >= target_amount))
|
||||
var/datum/changeling/changeling = owner.antag_datums[MODE_CHANGELING]
|
||||
if(owner && changeling?.absorbed_dna && (changeling.absorbedcount >= target_amount))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
var/obj/effect/dummy/veil_walk/holder = null // The veil_walk dummy.
|
||||
var/mob/living/carbon/human/master = null // The vampire/thrall's master.
|
||||
|
||||
var/image/master_image
|
||||
var/image/thrall_image
|
||||
|
||||
/datum/vampire/thrall
|
||||
status = VAMP_ISTHRALL
|
||||
|
||||
@@ -45,3 +48,19 @@
|
||||
return
|
||||
|
||||
blood_usable = max(0, blood_usable - blood_to_use)
|
||||
|
||||
/datum/vampire/proc/assign_master(var/mob/M, var/mob/set_master, var/datum/vampire/V)
|
||||
master = set_master
|
||||
V.thralls += M
|
||||
thrall_image = image('icons/mob/hud.dmi', M, "hudthrall")
|
||||
set_master.client.images += thrall_image
|
||||
master_image = image('icons/mob/hud.dmi', set_master, "hudvampire")
|
||||
M.client.images += master_image
|
||||
|
||||
/datum/vampire/proc/lose_master(var/mob/M)
|
||||
QDEL_NULL(thrall_image)
|
||||
QDEL_NULL(master_image)
|
||||
if(master)
|
||||
var/datum/vampire/master_vampire = master.mind.antag_datums[MODE_VAMPIRE]
|
||||
master_vampire.thralls -= M
|
||||
master = null
|
||||
@@ -2,26 +2,28 @@
|
||||
/mob/proc/make_vampire()
|
||||
if (!mind)
|
||||
return
|
||||
if (!mind.vampire)
|
||||
mind.vampire = new /datum/vampire()
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if(!vampire)
|
||||
mind.antag_datums[MODE_VAMPIRE] = new /datum/vampire()
|
||||
vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
// No powers to thralls. Ew.
|
||||
if (mind.vampire.status & VAMP_ISTHRALL)
|
||||
if(vampire.status & VAMP_ISTHRALL)
|
||||
return
|
||||
|
||||
mind.vampire.blood_usable += 30
|
||||
vampire.blood_usable += 30
|
||||
|
||||
if(client)
|
||||
mind.vampire.blood_hud = new /obj/screen/vampire/blood()
|
||||
mind.vampire.frenzy_hud = new /obj/screen/vampire/frenzy()
|
||||
client.screen += mind.vampire.blood_hud
|
||||
client.screen += mind.vampire.frenzy_hud
|
||||
vampire.blood_hud = new /obj/screen/vampire/blood()
|
||||
vampire.frenzy_hud = new /obj/screen/vampire/frenzy()
|
||||
client.screen += vampire.blood_hud
|
||||
client.screen += vampire.frenzy_hud
|
||||
|
||||
verbs += new /datum/antagonist/vampire/proc/vampire_help
|
||||
|
||||
for(var/datum/power/vampire/P in vampirepowers)
|
||||
if(!(P in mind.vampire.purchased_powers))
|
||||
if(!(P in vampire.purchased_powers))
|
||||
if(!P.blood_cost)
|
||||
mind.vampire.add_power(mind, P, 0)
|
||||
vampire.add_power(mind, P, 0)
|
||||
else if(P.isVerb && P.verbpath)
|
||||
verbs += P.verbpath
|
||||
|
||||
@@ -29,11 +31,10 @@
|
||||
|
||||
// Checks the vampire's bloodlevel and unlocks new powers based on that.
|
||||
/mob/proc/check_vampire_upgrade()
|
||||
if (!mind.vampire)
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if(!vampire)
|
||||
return
|
||||
|
||||
var/datum/vampire/vampire = mind.vampire
|
||||
|
||||
for (var/datum/power/vampire/P in vampirepowers)
|
||||
if (P.blood_cost <= vampire.blood_total)
|
||||
if (!(P in vampire.purchased_powers))
|
||||
@@ -50,7 +51,7 @@
|
||||
if (!ishuman(src))
|
||||
return
|
||||
|
||||
var/datum/vampire/vampire = mind.vampire
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if (!vampire)
|
||||
log_debug("[src] has a vampire power but is not a vampire.")
|
||||
return
|
||||
@@ -73,26 +74,30 @@
|
||||
/mob/proc/vampire_can_affect_target(var/mob/living/carbon/human/T, var/notify = 1, var/account_loyalty_implant = 0, var/ignore_thrall = FALSE, var/affect_ipc = TRUE)
|
||||
if (!T || !istype(T))
|
||||
return FALSE
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
// How did you even get here?
|
||||
if (!mind.vampire)
|
||||
if (!vampire)
|
||||
return FALSE
|
||||
if ((mind.vampire.status & VAMP_FULLPOWER) && !(T.mind && T.mind.vampire && (T.mind.vampire.status & VAMP_FULLPOWER)))
|
||||
return TRUE
|
||||
if (T.mind)
|
||||
if (T.mind.assigned_role == "Chaplain")
|
||||
if (notify)
|
||||
var/datum/vampire/vampire_check
|
||||
if(T.mind)
|
||||
if(T.mind.assigned_role == "Chaplain")
|
||||
if(notify)
|
||||
to_chat(src, "<span class='warning'>Your connection with the Veil is not strong enough to affect a man as devout as them.</span>")
|
||||
return FALSE
|
||||
else if (T.mind.vampire && (!(T.mind.vampire.status & VAMP_ISTHRALL) || ((T.mind.vampire.status & VAMP_ISTHRALL) && !ignore_thrall)))
|
||||
if (notify)
|
||||
to_chat(src, "<span class='warning'>You lack the power required to affect another creature of the Veil.</span>")
|
||||
return FALSE
|
||||
|
||||
vampire_check = T.mind.antag_datums[MODE_VAMPIRE]
|
||||
if(vampire_check)
|
||||
if(!(vampire_check.status & VAMP_ISTHRALL && ignore_thrall))
|
||||
if(notify)
|
||||
to_chat(src, "<span class='warning'>You lack the power required to affect another creature of the Veil.</span>")
|
||||
return FALSE
|
||||
if(vampire_check)
|
||||
if((vampire.status & VAMP_FULLPOWER) && !(vampire_check.status & VAMP_FULLPOWER))
|
||||
return TRUE
|
||||
if(!affect_ipc && isipc(T))
|
||||
if (notify)
|
||||
to_chat(src, SPAN_WARNING("You lack the power to interact with mechanical constructs."))
|
||||
return FALSE
|
||||
if(is_special_character(T) && (!(T.mind.vampire.status & VAMP_ISTHRALL)))
|
||||
if(is_special_character(T) && (!(vampire_check.status & VAMP_ISTHRALL)))
|
||||
if (notify)
|
||||
to_chat(src, "<span class='warning'>\The [T]'s mind is too strong to be affected by our powers!</span>")
|
||||
return FALSE
|
||||
@@ -123,13 +128,14 @@
|
||||
return
|
||||
|
||||
var/datum/vampire/thrall/thrall = new()
|
||||
mind.vampire = thrall
|
||||
mind.antag_datums[MODE_VAMPIRE] = thrall
|
||||
|
||||
/mob/proc/vampire_check_frenzy(var/force_frenzy = 0)
|
||||
if (!mind || !mind.vampire)
|
||||
if(!mind)
|
||||
return
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if(!vampire)
|
||||
return
|
||||
|
||||
var/datum/vampire/vampire = mind.vampire
|
||||
// Thralls don't frenzy.
|
||||
if (vampire.status & VAMP_ISTHRALL)
|
||||
return
|
||||
@@ -176,10 +182,9 @@
|
||||
vampire.last_frenzy_message = world.time
|
||||
|
||||
/mob/proc/vampire_start_frenzy(var/force_frenzy = 0)
|
||||
var/datum/vampire/vampire = mind.vampire
|
||||
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if (vampire.status & VAMP_FRENZIED)
|
||||
return
|
||||
return TRUE
|
||||
|
||||
var/probablity = force_frenzy ? 100 : vampire.frenzy * 0.5
|
||||
|
||||
@@ -194,12 +199,19 @@
|
||||
sight |= SEE_MOBS
|
||||
|
||||
verbs += /mob/living/carbon/human/proc/grapple
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/vampire_start_frenzy()
|
||||
. = ..()
|
||||
if(.)
|
||||
update_body()
|
||||
|
||||
/mob/proc/vampire_stop_frenzy(var/force_stop = 0)
|
||||
var/datum/vampire/vampire = mind.vampire
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
|
||||
if (!(vampire.status & VAMP_FRENZIED))
|
||||
return
|
||||
return TRUE
|
||||
|
||||
if (prob(force_stop ? 100 : vampire.blood_usable))
|
||||
vampire.status &= ~VAMP_FRENZIED
|
||||
@@ -214,60 +226,73 @@
|
||||
|
||||
verbs -= /mob/living/carbon/human/proc/grapple
|
||||
regenerate_icons()
|
||||
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/vampire_stop_frenzy()
|
||||
. = ..()
|
||||
if(.)
|
||||
update_body()
|
||||
|
||||
// Removes all vampire powers.
|
||||
/mob/proc/remove_vampire_powers()
|
||||
if (!mind || !mind.vampire)
|
||||
if(!mind)
|
||||
return
|
||||
|
||||
for (var/datum/power/vampire/P in mind.vampire.purchased_powers)
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if(!vampire)
|
||||
return
|
||||
for (var/datum/power/vampire/P in vampire.purchased_powers)
|
||||
if (P.isVerb)
|
||||
verbs -= P.verbpath
|
||||
|
||||
if (mind.vampire.status & VAMP_FRENZIED)
|
||||
if (vampire.status & VAMP_FRENZIED)
|
||||
vampire_stop_frenzy(1)
|
||||
|
||||
/mob/proc/handle_vampire()
|
||||
if(mind.vampire.status & VAMP_ISTHRALL)
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if(vampire.status & VAMP_ISTHRALL)
|
||||
return
|
||||
|
||||
// Apply frenzy while in the chapel.
|
||||
if (istype(get_area(loc), /area/chapel))
|
||||
mind.vampire.frenzy += 3
|
||||
vampire.frenzy += 3
|
||||
|
||||
if (mind.vampire.blood_usable < 10)
|
||||
mind.vampire.frenzy += 2
|
||||
else if (mind.vampire.frenzy > 0)
|
||||
mind.vampire.frenzy = max(0, mind.vampire.frenzy -= Clamp(mind.vampire.blood_usable * 0.1, 1, 10))
|
||||
if (vampire.blood_usable < 10)
|
||||
vampire.frenzy += 2
|
||||
else if (vampire.frenzy > 0)
|
||||
vampire.frenzy = max(0, vampire.frenzy -= Clamp(vampire.blood_usable * 0.1, 1, 10))
|
||||
|
||||
mind.vampire.frenzy = round(min(mind.vampire.frenzy, 450))
|
||||
vampire.frenzy = round(min(vampire.frenzy, 450))
|
||||
|
||||
vampire_check_frenzy()
|
||||
|
||||
if(client)
|
||||
if(!mind.vampire.blood_hud)
|
||||
mind.vampire.blood_hud = new /obj/screen/vampire/blood()
|
||||
client.screen += mind.vampire.blood_hud
|
||||
if(!mind.vampire.frenzy_hud)
|
||||
mind.vampire.frenzy_hud = new /obj/screen/vampire/frenzy()
|
||||
client.screen += mind.vampire.frenzy_hud
|
||||
if(!mind.vampire.blood_suck_hud)
|
||||
mind.vampire.blood_suck_hud = new /obj/screen/vampire/suck()
|
||||
client.screen += mind.vampire.blood_suck_hud
|
||||
if(!vampire.blood_hud)
|
||||
vampire.blood_hud = new /obj/screen/vampire/blood()
|
||||
client.screen += vampire.blood_hud
|
||||
if(!vampire.frenzy_hud)
|
||||
vampire.frenzy_hud = new /obj/screen/vampire/frenzy()
|
||||
client.screen += vampire.frenzy_hud
|
||||
if(!vampire.blood_suck_hud)
|
||||
vampire.blood_suck_hud = new /obj/screen/vampire/suck()
|
||||
client.screen += vampire.blood_suck_hud
|
||||
|
||||
mind.vampire.blood_hud.maptext = SMALL_FONTS(7, mind.vampire.blood_usable)
|
||||
if(mind.vampire.frenzy)
|
||||
if(!mind.vampire.frenzy_hud.alpha)
|
||||
animate(mind.vampire.frenzy_hud, 1 SECOND, alpha = 255, LINEAR_EASING)
|
||||
mind.vampire.frenzy_hud.maptext = SMALL_FONTS(7, mind.vampire.frenzy)
|
||||
vampire.blood_hud.maptext = SMALL_FONTS(7, vampire.blood_usable)
|
||||
if(vampire.frenzy)
|
||||
if(!vampire.frenzy_hud.alpha)
|
||||
animate(vampire.frenzy_hud, 1 SECOND, alpha = 255, LINEAR_EASING)
|
||||
vampire.frenzy_hud.maptext = SMALL_FONTS(7, vampire.frenzy)
|
||||
else
|
||||
if(mind.vampire.frenzy_hud.alpha)
|
||||
animate(mind.vampire.frenzy_hud, 1 SECOND, alpha = 0, LINEAR_EASING)
|
||||
mind.vampire.frenzy_hud.maptext = null
|
||||
if(vampire.frenzy_hud.alpha)
|
||||
animate(vampire.frenzy_hud, 1 SECOND, alpha = 0, LINEAR_EASING)
|
||||
vampire.frenzy_hud.maptext = null
|
||||
|
||||
/mob/living/carbon/human/proc/finish_vamp_timeout(vamp_flags = 0)
|
||||
if (!mind || !mind.vampire)
|
||||
if(!mind)
|
||||
return FALSE
|
||||
if (vamp_flags && !(mind.vampire.status & vamp_flags))
|
||||
var/datum/vampire/vampire = mind.antag_datums[MODE_VAMPIRE]
|
||||
if(!vampire)
|
||||
return FALSE
|
||||
if (vamp_flags && !(vampire.status & vamp_flags))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -56,8 +56,8 @@
|
||||
return
|
||||
|
||||
var/datum/vampire/draining_vamp = null
|
||||
if(T.mind?.vampire)
|
||||
draining_vamp = T.mind.vampire
|
||||
if(T.mind)
|
||||
draining_vamp = T.mind.antag_datums[MODE_VAMPIRE]
|
||||
|
||||
var/target_aware = !!T.client
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
playsound(src.loc, 'sound/effects/drain_blood_new.ogg', 50, 1)
|
||||
|
||||
while(do_mob(src, T, 50) && vampire.status & VAMP_DRAINING && vampire.blood_usable < VAMPIRE_MAX_USABLE_BLOOD)
|
||||
if(!mind.vampire)
|
||||
if(!vampire)
|
||||
to_chat(src, SPAN_DANGER("Your fangs have disappeared!"))
|
||||
return
|
||||
|
||||
@@ -342,7 +342,7 @@
|
||||
|
||||
var/list/victims = list()
|
||||
for(var/mob/living/carbon/human/T in hearers(4, src) - src)
|
||||
if(istype(T) && (T.l_ear || T.r_ear) && istype((T.l_ear || T.r_ear), /obj/item/clothing/ears/earmuffs))
|
||||
if(T.protected_from_sound())
|
||||
continue
|
||||
if(!vampire_can_affect_target(T, 0))
|
||||
continue
|
||||
@@ -498,7 +498,8 @@
|
||||
last_valid_turf = get_turf(owner.loc)
|
||||
owner.forceMove(src)
|
||||
|
||||
if(owner.mind.vampire.status & VAMP_FULLPOWER)
|
||||
var/datum/vampire/vampire = owner_mob.mind.antag_datums[MODE_VAMPIRE]
|
||||
if(vampire.status & VAMP_FULLPOWER)
|
||||
for(var/obj/item/grab/G in list(owner.l_hand, owner.r_hand))
|
||||
G.affecting.vampire_phase_out(get_turf(G))
|
||||
G.affecting.forceMove(src)
|
||||
@@ -748,9 +749,9 @@
|
||||
to_chat(T, SPAN_DANGER("Your mind blanks as you finish feeding from [src]'s wrist."))
|
||||
thralls.add_antagonist(T.mind, 1, 1, 0, 1, 1)
|
||||
|
||||
T.mind.vampire.master = src
|
||||
vampire.thralls += T
|
||||
to_chat(T, SPAN_NOTICE("You have been forced into a blood bond by [T.mind.vampire.master], and are thus their thrall. While a thrall may feel a myriad of emotions towards their master, ranging from fear, to hate, to love; the supernatural bond between them still forces the thrall to obey their master, and to listen to the master's commands.<br><br>You must obey your master's orders, you must protect them, you cannot harm them."))
|
||||
var/datum/vampire/T_vampire = T.mind.antag_datums[MODE_VAMPIRE]
|
||||
T_vampire.assign_master(T, src, vampire)
|
||||
to_chat(T, SPAN_NOTICE("You have been forced into a blood bond by [T_vampire.master], and are thus their thrall. While a thrall may feel a myriad of emotions towards their master, ranging from fear, to hate, to love; the supernatural bond between them still forces the thrall to obey their master, and to listen to the master's commands.<br><br>You must obey your master's orders, you must protect them, you cannot harm them."))
|
||||
to_chat(src, SPAN_NOTICE("You have completed the thralling process. They are now your slave and will obey your commands."))
|
||||
admin_attack_log(src, T, "enthralled [key_name(T)]", "was enthralled by [key_name(src)]", "successfully enthralled")
|
||||
|
||||
@@ -883,30 +884,30 @@
|
||||
to_chat(src, SPAN_WARNING("Your fangs are already sunk into a victim's neck!"))
|
||||
return
|
||||
|
||||
if(T.mind.vampire)
|
||||
var/datum/vampire/draining_vamp = T.mind.vampire
|
||||
if(T.mind)
|
||||
var/datum/vampire/draining_vamp = T.mind.antag_datums[MODE_VAMPIRE]
|
||||
if(draining_vamp)
|
||||
if(draining_vamp.status & VAMP_ISTHRALL)
|
||||
var/choice_text = ""
|
||||
var/denial_response = ""
|
||||
if(draining_vamp.master == src)
|
||||
choice_text = "[T] is your thrall. Do you wish to release them from the blood bond and give them the chance to become your equal?"
|
||||
denial_response = "You opt against giving [T] a chance to ascend, and choose to keep them as a servant."
|
||||
else
|
||||
choice_text = "You can feel the taint of another master running in the veins of [T]. Do you wish to release them of their blood bond, and convert them into a vampire, in spite of their master?"
|
||||
denial_response = "You choose not to continue with the Embrace, and permit [T] to keep serving their master."
|
||||
|
||||
if(draining_vamp.status & VAMP_ISTHRALL)
|
||||
var/choice_text = ""
|
||||
var/denial_response = ""
|
||||
if(draining_vamp.master == src)
|
||||
choice_text = "[T] is your thrall. Do you wish to release them from the blood bond and give them the chance to become your equal?"
|
||||
denial_response = "You opt against giving [T] a chance to ascend, and choose to keep them as a servant."
|
||||
if(alert(src, choice_text, "Choices", "Yes", "No") == "No")
|
||||
to_chat(src, SPAN_NOTICE("[denial_response]"))
|
||||
return
|
||||
|
||||
thralls.remove_antagonist(T.mind, 0, 0)
|
||||
qdel(draining_vamp)
|
||||
draining_vamp = null
|
||||
else
|
||||
choice_text = "You can feel the taint of another master running in the veins of [T]. Do you wish to release them of their blood bond, and convert them into a vampire, in spite of their master?"
|
||||
denial_response = "You choose not to continue with the Embrace, and permit [T] to keep serving their master."
|
||||
|
||||
if(alert(src, choice_text, "Choices", "Yes", "No") == "No")
|
||||
to_chat(src, SPAN_NOTICE("[denial_response]"))
|
||||
to_chat(src, SPAN_WARNING("You feel corruption running in [T]'s blood. Much like yourself, [T.get_pronoun("he")] is already a spawn of the Veil, and cannot be Embraced."))
|
||||
return
|
||||
|
||||
thralls.remove_antagonist(T.mind, 0, 0)
|
||||
qdel(draining_vamp)
|
||||
draining_vamp = null
|
||||
else
|
||||
to_chat(src, SPAN_WARNING("You feel corruption running in [T]'s blood. Much like yourself, [T.get_pronoun("he")] is already a spawn of the Veil, and cannot be Embraced."))
|
||||
return
|
||||
|
||||
vampire.status |= VAMP_DRAINING
|
||||
|
||||
visible_message(SPAN_DANGER("[src] bites [T]'s neck!"), SPAN_DANGER("You bite [T]'s neck and begin to drain their blood, as the first step of introducing the corruption of the Veil to them."), SPAN_NOTICE("You hear a soft puncture and a wet sucking noise."))
|
||||
@@ -915,7 +916,7 @@
|
||||
|
||||
var/drained_all_blood = FALSE
|
||||
while(do_mob(src, T, 50))
|
||||
if(!mind.vampire)
|
||||
if(!vampire)
|
||||
to_chat(src, SPAN_WARNING("Your fangs have disappeared!"))
|
||||
return
|
||||
if(!T.vessel.get_reagent_amount(/datum/reagent/blood))
|
||||
@@ -948,8 +949,9 @@
|
||||
to_chat(T, SPAN_DANGER("You awaken. Moments ago, you were dead, your conciousness still forced stuck inside your body. Now you live. You feel different, a strange, dark force now present within you. You have an insatiable desire to drain the blood of mortals, and to grow in power."))
|
||||
to_chat(src, SPAN_WARNING("You have corrupted another mortal with the taint of the Veil. Beware: they will awaken hungry and maddened; not bound to any master."))
|
||||
|
||||
T.mind.vampire.blood_usable = 0
|
||||
T.mind.vampire.frenzy = 250
|
||||
var/datum/vampire/T_vampire = T.mind.antag_datums[MODE_VAMPIRE]
|
||||
T_vampire.blood_usable = 0
|
||||
T_vampire.frenzy = 250
|
||||
T.vampire_check_frenzy()
|
||||
|
||||
vampire.status &= ~VAMP_DRAINING
|
||||
@@ -1016,4 +1018,4 @@
|
||||
G.synch()
|
||||
|
||||
verbs -= /mob/living/carbon/human/proc/grapple
|
||||
ADD_VERB_IN_IF(src, 800, /mob/living/carbon/human/proc/grapple, CALLBACK(src, .proc/finish_vamp_timeout, VAMP_FRENZIED))
|
||||
ADD_VERB_IN_IF(src, 800, /mob/living/carbon/human/proc/grapple, CALLBACK(src, .proc/finish_vamp_timeout, VAMP_FRENZIED))
|
||||
|
||||
@@ -157,9 +157,9 @@
|
||||
shoes = /obj/item/clothing/shoes/black
|
||||
headset = /obj/item/device/radio/headset/headset_sci
|
||||
bowman = /obj/item/device/radio/headset/headset_sci/alt
|
||||
tab_pda = /obj/item/modular_computer/handheld/pda/research
|
||||
wristbound = /obj/item/modular_computer/handheld/wristbound/preset/pda/research
|
||||
tablet = /obj/item/modular_computer/handheld/preset/research
|
||||
tab_pda = /obj/item/modular_computer/handheld/pda/research/robotics
|
||||
wristbound = /obj/item/modular_computer/handheld/wristbound/preset/advanced/research/robotics
|
||||
tablet = /obj/item/modular_computer/handheld/preset/research/robotics
|
||||
id = /obj/item/card/id/white
|
||||
belt = /obj/item/storage/belt/utility
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ update_flag
|
||||
..()
|
||||
|
||||
update_icon()
|
||||
SSnanoui.update_uis(src) // Update all NanoUIs attached to src
|
||||
SSvueui.check_uis_for_change(src) // Update all VueUIs attached to src
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob)
|
||||
if(!ai_can_interact(user))
|
||||
@@ -339,37 +339,36 @@ update_flag
|
||||
/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob)
|
||||
return src.ui_interact(user)
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
if (src.destroyed)
|
||||
/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user)
|
||||
if(src.destroyed)
|
||||
return
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
var/data[0]
|
||||
data["name"] = name
|
||||
data["canLabel"] = can_label ? 1 : 0
|
||||
data["portConnected"] = connected_port ? 1 : 0
|
||||
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
|
||||
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
|
||||
data["minReleasePressure"] = round(ONE_ATMOSPHERE/10)
|
||||
data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE)
|
||||
data["valveOpen"] = valve_open ? 1 : 0
|
||||
|
||||
data["hasHoldingTank"] = holding ? 1 : 0
|
||||
if (holding)
|
||||
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400)
|
||||
// when the ui is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
ui = new(user, src, "machinery-atmospherics-canister", 480, 400, "Canister", state = interactive_state)
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
ui.auto_update_content = TRUE
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/vueui_data_change(list/data, mob/user, datum/vueui/ui)
|
||||
data = ..() || list()
|
||||
|
||||
// this is the data which will be sent to the ui
|
||||
data["name"] = name
|
||||
data["canLabel"] = can_label
|
||||
data["portConnected"] = !!connected_port
|
||||
data["tankPressure"] = round(air_contents.return_pressure() || 0)
|
||||
data["releasePressure"] = round(release_pressure || 0)
|
||||
data["minReleasePressure"] = round(ONE_ATMOSPHERE/10)
|
||||
data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE)
|
||||
data["valveOpen"] = valve_open
|
||||
|
||||
data["hasHoldingTank"] = !!holding
|
||||
if (holding)
|
||||
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
|
||||
return data
|
||||
|
||||
/obj/machinery/portable_atmospherics/canister/Topic(href, href_list)
|
||||
|
||||
@@ -379,19 +378,20 @@ update_flag
|
||||
return 0
|
||||
|
||||
if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) // exploit protection -walter0o
|
||||
usr << browse(null, "window=canister")
|
||||
var/datum/vueui/ui = href_list["vueui"]
|
||||
ui?.close()
|
||||
onclose(usr, "canister")
|
||||
return
|
||||
|
||||
if(href_list["toggle"])
|
||||
if (valve_open)
|
||||
if (holding)
|
||||
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the [holding]<br>"
|
||||
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into [holding]<br>"
|
||||
else
|
||||
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the <span class='warning'><b>air</b></span><br>"
|
||||
else
|
||||
if (holding)
|
||||
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into the [holding]<br>"
|
||||
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into [holding]<br>"
|
||||
else
|
||||
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into the <span class='warning'><b>air</b></span><br>"
|
||||
log_open()
|
||||
@@ -401,18 +401,14 @@ update_flag
|
||||
if(holding)
|
||||
if (valve_open)
|
||||
valve_open = 0
|
||||
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the [holding]<br>"
|
||||
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into [holding]<br>"
|
||||
if(istype(holding, /obj/item/tank))
|
||||
holding.manipulated_by = usr.real_name
|
||||
usr.put_in_hands(holding)
|
||||
holding = null
|
||||
|
||||
if (href_list["pressure_adj"])
|
||||
var/diff = text2num(href_list["pressure_adj"])
|
||||
if(diff > 0)
|
||||
release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff)
|
||||
else
|
||||
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
|
||||
if (href_list["pressure_set"])
|
||||
release_pressure = between(ONE_ATMOSPHERE/10, text2num(href_list["pressure_set"]), 10*ONE_ATMOSPHERE)
|
||||
|
||||
if (href_list["relabel"])
|
||||
if (can_label)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
var/obj/item/organ/O = new new_organ(get_turf(src))
|
||||
|
||||
if(prints_prosthetics)
|
||||
O.robotic = 2
|
||||
O.robotic = ROBOTIC_MECHANICAL
|
||||
else if(loaded_dna)
|
||||
visible_message("<span class='notice'>The printer injects the stored DNA into the biomass.</span>.")
|
||||
O.transplant_data = list()
|
||||
|
||||
@@ -753,9 +753,9 @@
|
||||
for(var/obj/item/organ/internal/i in occ["internal_organs"])
|
||||
|
||||
var/mech = ""
|
||||
if(i.robotic == 1)
|
||||
if(i.robotic == ROBOTIC_ASSISTED)
|
||||
mech = "Assisted:"
|
||||
if(i.robotic == 2)
|
||||
if(i.robotic == ROBOTIC_MECHANICAL)
|
||||
mech = "Mechanical:"
|
||||
|
||||
var/infection = get_infection_level(i.germ_level)
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
/obj/machinery/button/switch/update_icon()
|
||||
icon_state = "light[active]"
|
||||
|
||||
/obj/machinery/button/switch/attack_hand()
|
||||
playsound(src, /decl/sound_category/switch_sound, 30)
|
||||
|
||||
//alternate button with the same functionality, except has a door control sprite instead
|
||||
/obj/machinery/button/alternate
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
|
||||
@@ -207,7 +207,7 @@
|
||||
if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items?
|
||||
var/obj/item/I = W
|
||||
if (I.hitsound)
|
||||
playsound(loc, I.hitsound, 50, 1, -1)
|
||||
playsound(loc, I.hitsound, I.get_clamped_volume(), 1, -1)
|
||||
take_damage(W.force)
|
||||
|
||||
else
|
||||
@@ -450,4 +450,3 @@
|
||||
wires.MendAll()
|
||||
update_icon()
|
||||
update_coverage()
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ for reference:
|
||||
src.health -= W.force * 0.75
|
||||
else
|
||||
animate_shake()
|
||||
playsound(src.loc, material.hitsound, 100, 1)
|
||||
playsound(src.loc, material.hitsound, W.get_clamped_volume(), 1)
|
||||
if (src.health <= 0)
|
||||
visible_message("<span class='danger'>The barricade is smashed apart!</span>")
|
||||
dismantle()
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
var/mob/M = AM
|
||||
if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent shock spam.
|
||||
M.last_bumped = world.time
|
||||
if(!M.restrained() && (!issmall(M) || ishuman(M)))
|
||||
if(!M.restrained() && (!issmall(M) || ishuman(M) || istype(M, /mob/living/silicon/robot/drone/mining)))
|
||||
bumpopen(M)
|
||||
return
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
user.visible_message("<span class='danger'>\The [user] hits \the [src] with \the [W] with no visible effect.</span>")
|
||||
else
|
||||
user.visible_message("<span class='danger'>\The [user] forcefully strikes \the [src] with \the [W]!</span>")
|
||||
playsound(src.loc, hitsound, 100, 1)
|
||||
playsound(src.loc, hitsound, W.get_clamped_volume(), 1)
|
||||
take_damage(W.force)
|
||||
return
|
||||
|
||||
|
||||
@@ -51,16 +51,13 @@
|
||||
on_icon = "surgery"
|
||||
////////////////////SWITCH///////////////////////////////////////
|
||||
|
||||
/obj/machinery/button/holosign
|
||||
/obj/machinery/button/switch/holosign
|
||||
name = "holosign switch"
|
||||
desc = "A remote control switch for holosign."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "holosign_switch"
|
||||
|
||||
/obj/machinery/button/holosign/update_icon()
|
||||
return
|
||||
|
||||
/obj/machinery/button/holosign/attack_hand(mob/user as mob)
|
||||
/obj/machinery/button/switch/holosign/attack_hand(mob/user as mob)
|
||||
if(..())
|
||||
return
|
||||
add_fingerprint(user)
|
||||
@@ -68,8 +65,7 @@
|
||||
use_power(5)
|
||||
|
||||
active = !active
|
||||
icon_state = "light[active]"
|
||||
|
||||
update_icon()
|
||||
for(var/obj/machinery/holosign/M in SSmachinery.all_machines)
|
||||
if (M.id == src.id)
|
||||
INVOKE_ASYNC(M, /obj/machinery/holosign/proc/toggle)
|
||||
|
||||
@@ -95,7 +95,7 @@ datum/track/New(var/title_name, var/audio)
|
||||
for(var/mob/living/carbon/M in ohearers(6, src))
|
||||
if(istype(M, /mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs))
|
||||
if(H.protected_from_sound())
|
||||
continue
|
||||
M.sleeping = 0
|
||||
M.stuttering += 20
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
/obj/machinery/light_switch/update_icon()
|
||||
cut_overlays()
|
||||
if(!(stat & NOPOWER))
|
||||
holographic_overlay(src, icon, "light_switch[on]-overlay")
|
||||
holographic_overlay(src, icon, "light[on]-overlay")
|
||||
if (!light_range || light_color != on ? "#82ff4c" : "#f86060")
|
||||
set_light(2, 0.3, on ? "#82ff4c" : "#f86060")
|
||||
else if (light_range)
|
||||
|
||||
@@ -76,40 +76,50 @@
|
||||
return ..()
|
||||
|
||||
if(!has_cell_power())
|
||||
return 0
|
||||
return FALSE
|
||||
if(src.use_power == 1)
|
||||
cell.use(idle_power_usage * CELLRATE)
|
||||
else if(src.use_power >= 2)
|
||||
cell.use(active_power_usage * CELLRATE)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//Processes the occupant, drawing from the internal power cell if needed.
|
||||
/obj/machinery/recharge_station/proc/process_occupant()
|
||||
if(!isrobot(occupant) && !ishuman(occupant))
|
||||
return
|
||||
|
||||
var/obj/item/cell/target
|
||||
if(isrobot(occupant))
|
||||
var/mob/living/silicon/robot/R = occupant
|
||||
|
||||
if(R.module)
|
||||
R.module.respawn_consumable(R, charging_power * CELLRATE / 250) //consumables are magical, apparently
|
||||
if(R.cell && !R.cell.fully_charged())
|
||||
var/diff = min(R.cell.maxcharge - R.cell.charge, charging_power * CELLRATE) // Capped by charging_power / tick
|
||||
var/charge_used = cell.use(diff)
|
||||
R.cell.give(charge_used*charging_efficiency)
|
||||
target = R.cell
|
||||
|
||||
//Lastly, attempt to repair the cyborg if enabled
|
||||
if(weld_rate && R.getBruteLoss() && cell.checked_use(weld_power_use * weld_rate * CELLRATE))
|
||||
R.adjustBruteLoss(-weld_rate)
|
||||
if(wire_rate && R.getFireLoss() && cell.checked_use(wire_power_use * wire_rate * CELLRATE))
|
||||
R.adjustFireLoss(-wire_rate)
|
||||
else if(ishuman(occupant))
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
if(!isnull(H.internal_organs_by_name[BP_CELL]) && H.nutrition < H.max_nutrition)
|
||||
H.adjustNutritionLoss(-10)
|
||||
cell.use(7000/H.max_nutrition*10)
|
||||
|
||||
if(ishuman(occupant))
|
||||
var/mob/living/carbon/human/H = occupant
|
||||
var/obj/item/organ/internal/cell/IC = H.internal_organs_by_name[BP_CELL]
|
||||
if(IC)
|
||||
target = IC.cell
|
||||
if((!target || target.percent() > 95) && istype(H.back, /obj/item/rig))
|
||||
var/obj/item/rig/R = H.back
|
||||
if(R.cell && !R.cell.fully_charged())
|
||||
target = R.cell
|
||||
|
||||
if(target && !target.fully_charged())
|
||||
var/diff = min(target.maxcharge - target.charge, charging_power * CELLRATE) // Capped by charging_power / tick
|
||||
var/charge_used = cell.use(diff)
|
||||
target.give(charge_used*charging_efficiency)
|
||||
|
||||
/obj/machinery/recharge_station/examine(mob/user)
|
||||
..(user)
|
||||
to_chat(user, "The charge meter reads: [round(chargepercentage())]%")
|
||||
to_chat(user, "The charge meter reads: [round(chargepercentage())]%.")
|
||||
|
||||
/obj/machinery/recharge_station/proc/chargepercentage()
|
||||
if(!cell)
|
||||
@@ -120,7 +130,6 @@
|
||||
if(user.stat)
|
||||
return
|
||||
go_out()
|
||||
return
|
||||
|
||||
/obj/machinery/recharge_station/emp_act(severity)
|
||||
if(occupant)
|
||||
@@ -220,12 +229,16 @@
|
||||
if(isrobot(M))
|
||||
var/mob/living/silicon/robot/R = M
|
||||
if(R.cell)
|
||||
return 1
|
||||
return TRUE
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(!isnull(H.internal_organs_by_name[BP_CELL]))
|
||||
return 1
|
||||
return 0
|
||||
return TRUE
|
||||
if(istype(H.back, /obj/item/rig))
|
||||
var/obj/item/rig/R = H.back
|
||||
if(R.get_cell())
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/recharge_station/proc/go_out()
|
||||
if(!occupant)
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
/obj/item/reagent_containers/glass/bottle/antitoxin = 4,
|
||||
/obj/item/reagent_containers/glass/bottle/inaprovaline = 4,
|
||||
/obj/item/reagent_containers/glass/bottle/perconol = 3,
|
||||
/obj/item/reagent_containers/glass/bottle/toxin = 4,
|
||||
/obj/item/reagent_containers/glass/bottle/toxin = 1,
|
||||
/obj/item/reagent_containers/glass/bottle/coughsyrup = 4,
|
||||
/obj/item/reagent_containers/syringe = 12,
|
||||
/obj/item/device/healthanalyzer = 5,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
layer = OBJ_LAYER + 0.9
|
||||
mouse_opacity = 0
|
||||
animate_movement = 0
|
||||
var/solid_time = 120
|
||||
var/amount = 3
|
||||
var/expand = 1
|
||||
var/metal = 0
|
||||
@@ -21,7 +22,7 @@
|
||||
metal = ismetal
|
||||
playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
|
||||
addtimer(CALLBACK(src, .proc/tick), 3 + metal * 3)
|
||||
addtimer(CALLBACK(src, .proc/post), 120)
|
||||
addtimer(CALLBACK(src, .proc/post), solid_time)
|
||||
|
||||
/obj/effect/effect/foam/proc/tick()
|
||||
process()
|
||||
@@ -81,6 +82,13 @@
|
||||
var/mob/living/M = AM
|
||||
M.slip("the foam", 6)
|
||||
|
||||
/obj/effect/effect/foam/spray
|
||||
amount = 1 // only spread a little bit
|
||||
solid_time = 3 SECONDS
|
||||
|
||||
/obj/effect/effect/foam/spray/initial
|
||||
amount = 0 // don't spread
|
||||
|
||||
/datum/effect/effect/system/foam_spread
|
||||
var/amount = 5 // the size of the foam spread.
|
||||
var/list/carried_reagents // the IDs of reagents present when the foam was mixed
|
||||
@@ -157,27 +165,72 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/foamedmetal/attack_hand(var/mob/user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user.do_attack_animation(src, FIST_ATTACK_ANIMATION)
|
||||
if ((HULK in user.mutations) || (prob(75 - metal * 25)))
|
||||
user.visible_message("<span class='warning'>[user] smashes through the foamed metal.</span>", "<span class='notice'>You smash through the metal foam wall.</span>")
|
||||
user.visible_message(SPAN_WARNING("[user] smashes through the foamed metal."), SPAN_NOTICE("You smash through the metal foam wall."))
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You hit the metal foam but bounce off it.</span>")
|
||||
return
|
||||
to_chat(user, SPAN_NOTICE("You hit the metal foam but bounce off it."))
|
||||
animate_shake()
|
||||
|
||||
/obj/structure/foamedmetal/attackby(var/obj/item/I, var/mob/user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
if(istype(I, /obj/item/grab))
|
||||
var/obj/item/grab/G = I
|
||||
if(G.state < GRAB_AGGRESSIVE)
|
||||
to_chat(user, SPAN_WARNING("You need a stronger grip to do that!"))
|
||||
return
|
||||
G.affecting.forceMove(src.loc)
|
||||
visible_message("<span class='warning'>[G.assailant] smashes [G.affecting] through the foamed metal wall.</span>")
|
||||
visible_message(SPAN_WARNING("[G.assailant] smashes [G.affecting] through the foamed metal wall."))
|
||||
G.affecting.take_overall_damage(15)
|
||||
qdel(I)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/stack/material))
|
||||
var/obj/item/stack/material/S = I
|
||||
if(S.get_amount() < 4)
|
||||
to_chat(user, SPAN_NOTICE("There isn't enough material here to construct a wall."))
|
||||
return
|
||||
|
||||
var/material/M = SSmaterials.get_material_by_name(S.default_type)
|
||||
if(!istype(M))
|
||||
return
|
||||
if(M.integrity < 50)
|
||||
to_chat(user, SPAN_NOTICE("This material is too soft for use in wall construction."))
|
||||
return
|
||||
user.visible_message("<b>[user]</b> starts slotting material into \the [src]...", SPAN_NOTICE("You start slotting material into \the [src], forming it into a wall..."))
|
||||
if(!do_after(user, 10 SECONDS) || !S.use(4))
|
||||
return
|
||||
var/turf/Tsrc = get_turf(src)
|
||||
var/original_type = Tsrc.type
|
||||
Tsrc.ChangeTurf(/turf/simulated/wall)
|
||||
var/turf/simulated/wall/T = Tsrc
|
||||
T.under_turf = original_type
|
||||
T.set_material(M)
|
||||
T.add_hiddenprint(usr)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/stack/tile/floor))
|
||||
var/turf/T = get_turf(src)
|
||||
if(T.type != /turf/space && !isopenturf(T)) // need to do a hard check here because transit turfs are also space turfs
|
||||
to_chat(user, SPAN_WARNING("The tile below \the [src] isn't an open space, or space itself!"))
|
||||
return
|
||||
var/obj/item/stack/tile/floor/S = I
|
||||
S.use(1)
|
||||
T.ChangeTurf(/turf/simulated/floor/airless)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
user.do_attack_animation(src, I)
|
||||
if(prob(I.force * 20 - metal * 25))
|
||||
user.visible_message("<span class='warning'>[user] smashes through the foamed metal.</span>", "<span class='notice'>You smash through the foamed metal with \the [I].</span>")
|
||||
user.visible_message(SPAN_WARNING("[user] smashes through the foamed metal."), SPAN_NOTICE("You smash through the foamed metal with \the [I]."))
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You hit the metal foam to no effect.</span>")
|
||||
to_chat(user, SPAN_NOTICE("You hit the metal foam to no effect."))
|
||||
animate_shake()
|
||||
|
||||
/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
|
||||
if(air_group)
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
amount *= 0.75
|
||||
|
||||
/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel
|
||||
icon_state = "mustard"
|
||||
anchored = 0
|
||||
|
||||
/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/Initialize(mapload, amt = 1, d = 0)
|
||||
@@ -55,17 +54,17 @@
|
||||
|
||||
/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/Spread()
|
||||
//The spread for flamethrower fuel is much more precise, to create a wide fire pattern.
|
||||
if(amount < 0.1) return
|
||||
if(amount < 1) return
|
||||
var/turf/simulated/S = loc
|
||||
if(!istype(S)) return
|
||||
|
||||
for(var/d in list(turn(dir,90),turn(dir,-90), dir))
|
||||
for(var/d in list(turn(dir, 45), turn(dir, -45), dir))
|
||||
var/turf/simulated/O = get_step(S,d)
|
||||
if(locate(/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel) in O)
|
||||
continue
|
||||
if(O.CanPass(null, S, 0, 0) && S.CanPass(null, O, 0, 0))
|
||||
new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O,amount*0.25,d)
|
||||
O.hotspot_expose((T20C*2) + 380,500) //Light flamethrower fuel on fire immediately.
|
||||
new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O,amount * 0.25,d)
|
||||
O.hotspot_expose((T20C*2) + 400, 500) //Light flamethrower fuel on fire immediately.
|
||||
|
||||
amount *= 0.25
|
||||
|
||||
@@ -153,4 +152,4 @@
|
||||
other_foam.Spread(exclude)
|
||||
else
|
||||
new/obj/effect/decal/cleanable/foam(target, amount*0.25,1)
|
||||
amount *= 0.75
|
||||
amount *= 0.75
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
perp.update_inv_shoes(1)
|
||||
amount--
|
||||
if(amount > 2 && prob(perp.slip_chance(perp.m_intent == "run" ? 20 : 5)))
|
||||
if(amount > 2 && prob(perp.slip_chance(perp.m_intent == M_RUN ? 20 : 5)))
|
||||
perp.slip(src, 4)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/proc/dry()
|
||||
|
||||
@@ -138,4 +138,18 @@
|
||||
anchored = TRUE
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "mfloor1"
|
||||
random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7")
|
||||
random_icon_states = list("mfloor1", "mfloor2", "mfloor3", "mfloor4", "mfloor5", "mfloor6", "mfloor7")
|
||||
|
||||
/obj/effect/decal/cleanable/confetti
|
||||
name = "confetti"
|
||||
desc = "Tiny bits of colored paper thrown about for the janitor to enjoy!"
|
||||
gender = PLURAL
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "confetti"
|
||||
|
||||
/obj/effect/decal/cleanable/confetti/attack_hand(mob/user)
|
||||
to_chat(user, SPAN_NOTICE("You start to meticulously pick up the confetti."))
|
||||
if(do_after(user, 60))
|
||||
qdel(src)
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
name = "egg cluster"
|
||||
desc = "They seem to pulse slightly with an inner life."
|
||||
icon_state = "eggs"
|
||||
health = 10
|
||||
var/amount_grown = 0
|
||||
var/last_itch = 0
|
||||
|
||||
@@ -119,6 +120,14 @@
|
||||
last_itch = world.time
|
||||
to_chat(O.owner, "<span class='notice'>Your [O.name] itches.</span>")
|
||||
|
||||
/obj/effect/spider/eggcluster/proc/take_damage(var/damage)
|
||||
health -= damage
|
||||
if(health <= 0)
|
||||
var/obj/item/organ/external/O = loc
|
||||
if(istype(O) && O.owner)
|
||||
to_chat(O.owner, SPAN_WARNING("You feel something dissolve in your [O.name]..."))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/spider/spiderling
|
||||
name = "spiderling"
|
||||
desc = "It never stays still for long."
|
||||
|
||||
@@ -444,7 +444,7 @@ var/list/global/slot_flags_enumeration = list(
|
||||
if(!istype(src, /obj/item/handcuffs))
|
||||
return 0
|
||||
if(slot_legcuffed)
|
||||
if(!istype(src, /obj/item/legcuffs))
|
||||
if(!istype(src, /obj/item/handcuffs))
|
||||
return 0
|
||||
if(slot_in_backpack) //used entirely for equipping spawned mobs or at round start
|
||||
var/allow = 0
|
||||
|
||||
@@ -178,7 +178,8 @@
|
||||
return
|
||||
|
||||
/obj/item/device/flash/emp_act(severity)
|
||||
if(broken) return
|
||||
if(broken)
|
||||
return
|
||||
flash_recharge()
|
||||
switch(times_used)
|
||||
if(0 to 5)
|
||||
@@ -187,13 +188,10 @@
|
||||
icon_state = "flashburnt"
|
||||
return
|
||||
times_used++
|
||||
if(istype(loc, /mob/living/carbon))
|
||||
if(iscarbon(loc))
|
||||
var/mob/living/carbon/M = loc
|
||||
var/safety = M.eyecheck(TRUE)
|
||||
if(safety < FLASH_PROTECTION_MODERATE)
|
||||
M.flash_eyes()
|
||||
for(var/mob/O in viewers(M, null))
|
||||
O.show_message("<span class='disarm'>[M] is blinded by the flash!</span>")
|
||||
M.flash_eyes()
|
||||
to_chat(M, SPAN_WARNING("Your [name] goes off!"))
|
||||
..()
|
||||
|
||||
/obj/item/device/flash/synthetic
|
||||
|
||||
@@ -55,4 +55,69 @@
|
||||
user.visible_message(SPAN_NOTICE("\The [user] activates the flare."), SPAN_NOTICE("You pull the cord on the flare, activating it!"))
|
||||
src.force = on_damage
|
||||
src.damtype = "fire"
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/item/device/flashlight/flare/torch
|
||||
name = "torch"
|
||||
desc = "A rustic source of light."
|
||||
w_class = ITEMSIZE_LARGE
|
||||
brightness_on = 2
|
||||
light_power = 3
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
icon_state = "torch"
|
||||
item_state = "torch"
|
||||
uv_intensity = 40
|
||||
produce_heat = 1000
|
||||
on_damage = 10
|
||||
|
||||
drop_sound = 'sound/items/drop/woodweapon.ogg'
|
||||
pickup_sound = 'sound/items/pickup/woodweapon.ogg'
|
||||
|
||||
/obj/item/device/flashlight/flare/torch/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/device/flashlight/flare/torch/update_icon()
|
||||
..()
|
||||
item_state = icon_state
|
||||
if(ismob(src.loc))
|
||||
var/mob/H = src.loc
|
||||
H.update_inv_l_hand()
|
||||
H.update_inv_r_hand()
|
||||
|
||||
|
||||
/obj/item/device/flashlight/flare/torch/proc/light(mob/user)
|
||||
user.visible_message(SPAN_NOTICE("\The [user] lights \the [src]."), SPAN_NOTICE("You light \the [src]."))
|
||||
force = on_damage
|
||||
damtype = "fire"
|
||||
on = TRUE
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/device/flashlight/flare/torch/attackby(var/obj/item/W, mob/user)
|
||||
if(W.isFlameSource() && !on && fuel)
|
||||
light(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/torch
|
||||
name = "torch handle"
|
||||
desc = "A torch handle without its head."
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
icon_state = "torch-empty"
|
||||
item_state = "torch-empty"
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
item_icons = list(
|
||||
slot_l_hand_str = 'icons/mob/items/lefthand_lighting.dmi',
|
||||
slot_r_hand_str = 'icons/mob/items/righthand_lighting.dmi',
|
||||
)
|
||||
|
||||
drop_sound = 'sound/items/drop/woodweapon.ogg'
|
||||
pickup_sound = 'sound/items/pickup/woodweapon.ogg'
|
||||
|
||||
/obj/item/torch/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/reagent_containers/glass/rag))
|
||||
to_chat(user, SPAN_NOTICE("You add \the [I] to \the [src]."))
|
||||
var/obj/item/device/flashlight/flare/torch/T = new()
|
||||
qdel(I)
|
||||
user.put_in_hands(T)
|
||||
qdel(src)
|
||||
|
||||
@@ -71,6 +71,18 @@
|
||||
return ..(freq, level)
|
||||
return -1
|
||||
|
||||
/obj/item/device/radio/headset/attack_hand(mob/user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.l_ear != src && H.r_ear != src)
|
||||
return ..()
|
||||
|
||||
if(slot_flags & SLOT_TWOEARS)
|
||||
var/obj/item/clothing/ears/OE = (H.l_ear == src ? H.r_ear : H.l_ear)
|
||||
qdel(OE)
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/device/radio/headset/attackby(obj/item/W, mob/user)
|
||||
if(W.isscrewdriver())
|
||||
if(keyslot1 || keyslot2)
|
||||
@@ -388,6 +400,16 @@
|
||||
translate_hivenet = 1
|
||||
ks2type = /obj/item/device/encryptionkey/hivenet
|
||||
|
||||
/obj/item/device/radio/headset/earmuff
|
||||
name = "earmuffs"
|
||||
desc = "Protects your hearing from loud noises, and quiet ones as well."
|
||||
desc_antag = "This set of earmuffs has a secret compartment housing radio gear, allowing it to function as a standard headset."
|
||||
icon = 'icons/obj/clothing/ears.dmi'
|
||||
icon_state = "earmuffs"
|
||||
item_state = "earmuffs"
|
||||
item_flags = SOUNDPROTECTION
|
||||
slot_flags = SLOT_EARS | SLOT_TWOEARS
|
||||
|
||||
/obj/item/device/radio/headset/syndicate
|
||||
name = "military headset"
|
||||
icon_state = "syn_headset"
|
||||
|
||||
@@ -206,6 +206,18 @@ BREATH ANALYZER
|
||||
limb_result = "[limb_result] \[<font color = '#ffa500'><b>[get_severity(org.burn_dam, TRUE)] burns</b></font>\]"
|
||||
if(org.status & ORGAN_BLEEDING)
|
||||
limb_result = "[limb_result] \[<span class='scan_danger'>bleeding</span>\]"
|
||||
var/is_bandaged = org.is_bandaged()
|
||||
var/is_salved = org.is_salved()
|
||||
if(is_bandaged && is_salved)
|
||||
var/icon/B = icon('icons/obj/stacks/medical.dmi', "bandaged")
|
||||
var/icon/S = icon('icons/obj/stacks/medical.dmi', "salved")
|
||||
limb_result = "[limb_result] \[[icon2html(B, user)] | [icon2html(S, user)]\]"
|
||||
else if(is_bandaged)
|
||||
var/icon/B = icon('icons/obj/stacks/medical.dmi', "bandaged")
|
||||
limb_result = "[limb_result] \[[icon2html(B, user)]\]"
|
||||
else if(is_salved)
|
||||
var/icon/S = icon('icons/obj/stacks/medical.dmi', "salved")
|
||||
limb_result = "[limb_result] \[[icon2html(S, user)]\]"
|
||||
dat += limb_result
|
||||
else
|
||||
dat += "No detectable limb injuries."
|
||||
|
||||
@@ -157,6 +157,7 @@ Contains:
|
||||
else
|
||||
to_chat(user, "<span class='warning'>\The [src] is used up, but there are more wounds to treat on \the [affecting.name].</span>")
|
||||
use(used)
|
||||
H.update_bandages(TRUE)
|
||||
else
|
||||
if (can_operate(H)) //Checks if mob is lying down on table for surgery
|
||||
if (do_surgery(H,user,src))
|
||||
@@ -282,6 +283,7 @@ Contains:
|
||||
else
|
||||
to_chat(user, "<span class='warning'>\The [src] is used up, but there are more wounds to treat on \the [affecting.name].</span>")
|
||||
use(used)
|
||||
H.update_bandages(TRUE)
|
||||
else
|
||||
if (can_operate(H)) //Checks if mob is lying down on table for surgery
|
||||
if (do_surgery(H,user,src))
|
||||
|
||||
@@ -504,7 +504,7 @@
|
||||
/obj/item/toy/snappop/Crossed(H as mob|obj)
|
||||
if((ishuman(H))) //i guess carp and shit shouldn't set them off
|
||||
var/mob/living/carbon/M = H
|
||||
if(M.m_intent == "run")
|
||||
if(M.m_intent == M_RUN)
|
||||
to_chat(M, SPAN_WARNING("You step on the snap pop!"))
|
||||
do_pop()
|
||||
|
||||
@@ -979,18 +979,6 @@
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "poked")
|
||||
contained_sprite = TRUE
|
||||
|
||||
/* NYET.
|
||||
/obj/item/toddler
|
||||
icon_state = "toddler"
|
||||
name = "toddler"
|
||||
desc = "This baby looks almost real. Wait, did it just burp?"
|
||||
force = 5
|
||||
w_class = ITEMSIZE_LARGE
|
||||
slot_flags = SLOT_BACK
|
||||
*/
|
||||
|
||||
//This should really be somewhere else but I don't know where. w/e
|
||||
|
||||
/obj/item/inflatable_duck
|
||||
name = "inflatable duck"
|
||||
desc = "No bother to sink or swim when you can just float!"
|
||||
@@ -1011,3 +999,24 @@
|
||||
throwforce = 1
|
||||
drop_sound = 'sound/items/drop/cardboardbox.ogg'
|
||||
pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
|
||||
|
||||
/obj/item/toy/partypopper
|
||||
name = "party popper"
|
||||
desc = "Instructions : Aim away from face. Wait for appropriate timing. Pull cord, enjoy confetti."
|
||||
icon_state = "partypopper"
|
||||
w_class = ITEMSIZE_TINY
|
||||
drop_sound = 'sound/items/drop/cardboardbox.ogg'
|
||||
pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
|
||||
|
||||
/obj/item/toy/partypopper/attack_self(mob/user)
|
||||
if(icon_state == "partypopper")
|
||||
spark(src, 1, user.dir)
|
||||
user.visible_message(SPAN_NOTICE("[user] pulls on the string, releasing a burst of confetti!"), SPAN_NOTICE("You pull on the string, releasing a burst of confetti!"))
|
||||
playsound(src, 'sound/effects/snap.ogg', 50, TRUE)
|
||||
icon_state = "partypopper_e"
|
||||
var/turf/T = get_step(src, user.dir)
|
||||
if(!turf_clear(T))
|
||||
T = get_turf(src)
|
||||
new /obj/effect/decal/cleanable/confetti(T)
|
||||
else
|
||||
to_chat(user, SPAN_NOTICE("The [src] is already spent!"))
|
||||
|
||||
@@ -441,13 +441,16 @@ RFD Mining-Class
|
||||
icon_state = "rfd-m"
|
||||
item_state = "rfd-m"
|
||||
|
||||
/obj/item/rfd/mining/afterattack(atom/A, mob/user, proximity)
|
||||
/obj/item/rfd/mining/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/rfd/mining/afterattack(atom/A, mob/user, proximity, click_parameters, var/report_duplicate = TRUE)
|
||||
if(!proximity)
|
||||
return
|
||||
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(R.stat || !R.cell || R.cell.charge <= 500)
|
||||
if(R.stat || !R.cell || R.cell.charge <= 200)
|
||||
if(last_fail <= world.time - 20) //Spam limiter.
|
||||
last_fail = world.time
|
||||
to_chat(user, SPAN_WARNING("You are unable to produce enough charge to use \the [src]!"))
|
||||
@@ -467,7 +470,8 @@ RFD Mining-Class
|
||||
return
|
||||
|
||||
if(locate(/obj/structure/track) in A)
|
||||
to_chat(user, SPAN_WARNING("There is already a track on \the [A]!"))
|
||||
if(report_duplicate)
|
||||
to_chat(user, SPAN_WARNING("There is already a track on \the [A]!"))
|
||||
return
|
||||
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
|
||||
@@ -480,7 +484,7 @@ RFD Mining-Class
|
||||
if(isrobot(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(R.cell)
|
||||
R.cell.use(500)
|
||||
R.cell.use(200)
|
||||
else
|
||||
stored_matter--
|
||||
to_chat(user, SPAN_NOTICE("The RFD now holds <b>[stored_matter]/30</b> fabrication-units."))
|
||||
|
||||
@@ -425,7 +425,7 @@ var/const/NO_EMAG_ACT = -50
|
||||
assignment = "Minedrone"
|
||||
|
||||
/obj/item/card/id/minedrone/New()
|
||||
access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station)
|
||||
access = list(access_maint_tunnels, access_mailsorting, access_cargo, access_cargo_bot, access_qm, access_mining, access_mining_station, access_external_airlocks)
|
||||
..()
|
||||
|
||||
/obj/item/card/id/centcom
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/obj/item/flamethrower
|
||||
name = "flamethrower"
|
||||
desc = "You are a firestarter!"
|
||||
desc = "A flamethrower created by modifying a welding tool to fit an external gas tank."
|
||||
icon = 'icons/obj/flamethrower.dmi'
|
||||
icon_state = "flamethrowerbase"
|
||||
item_state = "flamethrower_0"
|
||||
@@ -10,18 +10,29 @@
|
||||
throwforce = 10.0
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
w_class = ITEMSIZE_LARGE
|
||||
origin_tech = list(TECH_COMBAT = 1, TECH_PHORON = 1)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 500)
|
||||
var/status = 0
|
||||
var/secured = FALSE // Whether we have an igniter secured (screwdrivered) to us or not
|
||||
var/throw_amount = 100
|
||||
var/lit = 0 //on or off
|
||||
var/operating = 0//cooldown
|
||||
var/lit = FALSE //on or off
|
||||
var/operating = FALSE //cooldown
|
||||
var/turf/previousturf = null
|
||||
var/obj/item/weldingtool/weldtool = null
|
||||
var/obj/item/device/assembly/igniter/igniter = null
|
||||
var/obj/item/tank/phoron/ptank = null
|
||||
|
||||
/obj/item/flamethrower/examine(mob/user)
|
||||
..()
|
||||
if(Adjacent(user))
|
||||
if(ptank)
|
||||
to_chat(user, SPAN_NOTICE("Release pressure is set to [throw_amount] kPa. The tank has about [round(ptank.air_contents.return_pressure(), 10)] kPa left in it."))
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("It has no gas tank installed."))
|
||||
if(igniter)
|
||||
to_chat(user, SPAN_NOTICE("It has \an [igniter] installed."))
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("It has no igniter installed."))
|
||||
|
||||
/obj/item/flamethrower/Destroy()
|
||||
if(weldtool)
|
||||
@@ -45,13 +56,11 @@
|
||||
location = M.loc
|
||||
if(isturf(location)) //start a fire if possible
|
||||
location.hotspot_expose(700, 2)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/flamethrower/update_icon()
|
||||
cut_overlays()
|
||||
if(igniter)
|
||||
add_overlay("+igniter[status]")
|
||||
add_overlay("+igniter[secured]")
|
||||
if(ptank)
|
||||
add_overlay("+ptank")
|
||||
if(lit)
|
||||
@@ -59,10 +68,18 @@
|
||||
item_state = "flamethrower_1"
|
||||
else
|
||||
item_state = "flamethrower_0"
|
||||
return
|
||||
|
||||
/obj/item/flamethrower/isFlameSource()
|
||||
return lit
|
||||
|
||||
/obj/item/flamethrower/afterattack(atom/target, mob/user, proximity)
|
||||
if(!proximity) return
|
||||
if(proximity)
|
||||
return
|
||||
if(!ptank)
|
||||
return
|
||||
if(ptank.air_contents.get_by_flag(XGM_GAS_FUEL) < 1)
|
||||
to_chat(user, SPAN_WARNING("\The [src] doesn't have enough fuel left to throw!"))
|
||||
return
|
||||
// Make sure our user is still holding us
|
||||
if(user && user.get_active_hand() == src)
|
||||
var/turf/target_turf = get_turf(target)
|
||||
@@ -70,9 +87,11 @@
|
||||
var/turflist = getline(user, target_turf)
|
||||
flame_turf(turflist)
|
||||
|
||||
/obj/item/flamethrower/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(user.stat || user.restrained() || user.lying) return
|
||||
if(W.iswrench() && !status)//Taking this apart
|
||||
/obj/item/flamethrower/attackby(obj/item/W, mob/user)
|
||||
if(use_check_and_message(user))
|
||||
return
|
||||
|
||||
if(W.iswrench() && !secured)//Taking this apart
|
||||
var/turf/T = get_turf(src)
|
||||
if(weldtool)
|
||||
weldtool.forceMove(T)
|
||||
@@ -87,85 +106,117 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(W.isscrewdriver() && igniter && !lit)
|
||||
status = !status
|
||||
to_chat(user, "<span class='notice'>[igniter] is now [status ? "secured" : "unsecured"]!</span>")
|
||||
else if(W.isscrewdriver() && igniter && !lit)
|
||||
secured = !secured
|
||||
to_chat(user, SPAN_NOTICE("[igniter] is now [secured ? "secured" : "unsecured"]!"))
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(isigniter(W))
|
||||
else if(isigniter(W))
|
||||
var/obj/item/device/assembly/igniter/I = W
|
||||
if(I.secured) return
|
||||
if(igniter) return
|
||||
user.drop_from_inventory(I,src)
|
||||
if(I.secured)
|
||||
to_chat(user, SPAN_WARNING("\The [I] is not ready to attach yet! Use a screwdriver on it first."))
|
||||
return
|
||||
if(igniter)
|
||||
to_chat(user, SPAN_WARNING("\The [src] already has an igniter installed."))
|
||||
return
|
||||
user.drop_from_inventory(I, src)
|
||||
igniter = I
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(istype(W,/obj/item/tank/phoron))
|
||||
else if(istype(W, /obj/item/tank/phoron))
|
||||
if(ptank)
|
||||
to_chat(user, "<span class='notice'>There appears to already be a phoron tank loaded in [src]!</span>")
|
||||
to_chat(user, SPAN_WARNING("There appears to already be a tank loaded in \the [src]!"))
|
||||
return
|
||||
user.drop_from_inventory(W,src)
|
||||
user.drop_from_inventory(W, src)
|
||||
ptank = W
|
||||
update_icon()
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/device/analyzer))
|
||||
else if(istype(W, /obj/item/device/analyzer))
|
||||
var/obj/item/device/analyzer/A = W
|
||||
A.analyze_gases(src, user)
|
||||
return
|
||||
|
||||
else if(W.isFlameSource()) // you can light it with external input, even without an igniter
|
||||
attempt_lighting(user, TRUE)
|
||||
update_icon()
|
||||
return
|
||||
..()
|
||||
return
|
||||
|
||||
|
||||
/obj/item/flamethrower/attack_self(mob/user as mob)
|
||||
if(user.stat || user.restrained() || user.lying) return
|
||||
user.set_machine(src)
|
||||
/obj/item/flamethrower/attack_self(mob/user)
|
||||
if(use_check_and_message(user))
|
||||
return
|
||||
if(!ptank)
|
||||
to_chat(user, "<span class='notice'>Attach a phoron tank first!</span>")
|
||||
to_chat(user, SPAN_WARNING("Attach a phoron tank first!"))
|
||||
return
|
||||
var/dat = text("<TT><B>Flamethrower (<A HREF='?src=\ref[src];light=1'>[lit ? "<span class='warning'>Lit</span>" : "Unlit"]</a>)</B><BR>\n Tank Pressure: [ptank.air_contents.return_pressure()]<BR>\nAmount to throw: <A HREF='?src=\ref[src];amount=-100'>-</A> <A HREF='?src=\ref[src];amount=-10'>-</A> <A HREF='?src=\ref[src];amount=-1'>-</A> [throw_amount] <A HREF='?src=\ref[src];amount=1'>+</A> <A HREF='?src=\ref[src];amount=10'>+</A> <A HREF='?src=\ref[src];amount=100'>+</A><BR>\n<A HREF='?src=\ref[src];remove=1'>Remove phorontank</A> - <A HREF='?src=\ref[src];close=1'>Close</A></TT>")
|
||||
user << browse(dat, "window=flamethrower;size=600x300")
|
||||
onclose(user, "flamethrower")
|
||||
return
|
||||
|
||||
|
||||
/obj/item/flamethrower/Topic(href,href_list[])
|
||||
if(href_list["close"])
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=flamethrower")
|
||||
var/list/options = list(
|
||||
"Eject Tank" = image('icons/obj/tank.dmi', "phoron"),
|
||||
"Light" = image('icons/effects/effects.dmi', "exhaust"),
|
||||
"Lower Pressure" = image('icons/mob/screen/radial.dmi', "radial_sub"),
|
||||
"Raise Pressure" = image('icons/mob/screen/radial.dmi', "radial_add")
|
||||
)
|
||||
var/handle = show_radial_menu(user, user, options, radius = 42, tooltips=TRUE)
|
||||
if(!handle)
|
||||
return
|
||||
if(usr.stat || usr.restrained() || usr.lying) return
|
||||
usr.set_machine(src)
|
||||
if(href_list["light"])
|
||||
if(!ptank) return
|
||||
if(ptank.air_contents.gas[GAS_PHORON] < 1) return
|
||||
if(!status) return
|
||||
lit = !lit
|
||||
if(lit)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
if(href_list["amount"])
|
||||
throw_amount = throw_amount + text2num(href_list["amount"])
|
||||
throw_amount = max(50, min(5000, throw_amount))
|
||||
if(href_list["remove"])
|
||||
if(!ptank) return
|
||||
usr.put_in_hands(ptank)
|
||||
ptank = null
|
||||
lit = 0
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=flamethrower")
|
||||
for(var/mob/M in viewers(1, loc))
|
||||
if((M.client && M.machine == src))
|
||||
attack_self(M)
|
||||
switch(handle)
|
||||
if("Eject Tank")
|
||||
if(!ptank)
|
||||
return
|
||||
user.put_in_hands(ptank)
|
||||
ptank = null
|
||||
lit = FALSE
|
||||
if("Light")
|
||||
attempt_lighting(user)
|
||||
if("Lower Pressure")
|
||||
change_pressure(-50, user)
|
||||
if("Raise Pressure")
|
||||
change_pressure(50, user)
|
||||
else
|
||||
return
|
||||
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/flamethrower/proc/attempt_lighting(var/mob/user, var/external)
|
||||
if(!external) // if it's external input, we can't unlight it, but we don't need to check for an igniter either
|
||||
if(lit) // you can extinguish the flamethrower without an igniter
|
||||
lit = FALSE
|
||||
to_chat(user, SPAN_NOTICE("You extinguish \the [src]."))
|
||||
return
|
||||
if(!secured) // can't light via the flamethrower unless we have an igniter secured
|
||||
if(igniter)
|
||||
to_chat(user, SPAN_WARNING("\The [igniter] isn't secured, you need to use a screwdriver on it first."))
|
||||
else
|
||||
to_chat(user, SPAN_WARNING("\The [src] doesn't have a secured igniter installed."))
|
||||
return
|
||||
if(lit)
|
||||
to_chat(user, SPAN_WARNING("\The [src] is already lit."))
|
||||
return
|
||||
if(!ptank)
|
||||
to_chat(user, SPAN_WARNING("\The [src] doesn't have a tank installed."))
|
||||
return
|
||||
if(ptank.air_contents.get_by_flag(XGM_GAS_FUEL) < 1)
|
||||
to_chat(user, SPAN_WARNING("\The [src] doesn't have any flammable fuel to light!"))
|
||||
return
|
||||
lit = TRUE
|
||||
to_chat(user, SPAN_NOTICE("You light \the [src]."))
|
||||
if(lit)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/item/flamethrower/proc/change_pressure(var/pressure, var/mob/user)
|
||||
if(!pressure)
|
||||
return
|
||||
throw_amount += pressure
|
||||
throw_amount = Clamp(50, throw_amount, 5000)
|
||||
if(ismob(user))
|
||||
to_chat(user, SPAN_NOTICE("Pressure has been adjusted to [throw_amount] kPa."))
|
||||
|
||||
//Called from turf.dm turf/dblclick
|
||||
/obj/item/flamethrower/proc/flame_turf(turflist)
|
||||
if(!lit || operating) return
|
||||
operating = 1
|
||||
operating = TRUE
|
||||
playsound(src, fire_sound, 70, 1)
|
||||
for(var/turf/T in turflist)
|
||||
if(T.density || istype(T, /turf/space))
|
||||
@@ -178,32 +229,23 @@
|
||||
ignite_turf(T)
|
||||
sleep(1)
|
||||
previousturf = null
|
||||
operating = 0
|
||||
for(var/mob/M in viewers(1, loc))
|
||||
if((M.client && M.machine == src))
|
||||
attack_self(M)
|
||||
return
|
||||
operating = FALSE
|
||||
|
||||
|
||||
/obj/item/flamethrower/proc/ignite_turf(turf/target)
|
||||
//TODO: DEFERRED Consider checking to make sure tank pressure is high enough before doing this...
|
||||
//Transfer 5% of current tank air contents to turf
|
||||
var/datum/gas_mixture/air_transfer = ptank.air_contents.remove_ratio(0.02*(throw_amount/100))
|
||||
new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(target,air_transfer.gas[GAS_PHORON]*15,get_dir(loc,target))
|
||||
air_transfer.gas[GAS_PHORON] = 0
|
||||
var/datum/gas_mixture/air_transfer = ptank.air_contents.remove_ratio(0.02 * (throw_amount / 100))
|
||||
new /obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(target, air_transfer.get_by_flag(XGM_GAS_FUEL) * 15, get_dir(loc, target))
|
||||
for(var/g in air_transfer.gas)
|
||||
if(gas_data.flags[g] & XGM_GAS_FUEL)
|
||||
air_transfer.gas[g] = 0
|
||||
target.assume_air(air_transfer)
|
||||
//Burn it based on transfered gas
|
||||
//target.hotspot_expose(part4.air_contents.temperature*2,300)
|
||||
target.hotspot_expose((ptank.air_contents.temperature*2) + 380,500) // -- More of my "how do I shot fire?" dickery. -- TLE
|
||||
//location.hotspot_expose(1000,500,1)
|
||||
return
|
||||
target.hotspot_expose((ptank.air_contents.temperature*2) + 400, 500)
|
||||
|
||||
/obj/item/flamethrower/full/New(var/loc)
|
||||
..()
|
||||
/obj/item/flamethrower/full/Initialize()
|
||||
. = ..()
|
||||
weldtool = new /obj/item/weldingtool(src)
|
||||
weldtool.status = 0
|
||||
weldtool.status = FALSE
|
||||
igniter = new /obj/item/device/assembly/igniter(src)
|
||||
igniter.secured = 0
|
||||
status = 1
|
||||
update_icon()
|
||||
return
|
||||
igniter.secured = FALSE
|
||||
secured = TRUE
|
||||
update_icon()
|
||||
@@ -129,13 +129,14 @@
|
||||
desc = "PRESENTS!!!! eek!"
|
||||
icon = 'icons/obj/items.dmi'
|
||||
icon_state = "gift1"
|
||||
item_state = "gift1"
|
||||
item_state = "gift"
|
||||
w_class = ITEMSIZE_TINY
|
||||
randpixel = 12
|
||||
var/gift_type
|
||||
|
||||
/obj/item/xmasgift/Initialize()
|
||||
..()
|
||||
pixel_x = rand(-10,10)
|
||||
pixel_y = rand(-10,10)
|
||||
randpixel_xy()
|
||||
var/gift_benefactor = pick("the NanoTrasen Department of Christmas Affairs", "Miranda Trasen", "Joseph Dorne", "Isaac Asimov", "Baal D. Griffon", "the Sol Alliance (Sorry about the blockade!)",
|
||||
"Hephaestus Industries", "Idris Incorporated", "Glorsh Omega II", "the Jargon Federation", "the People's Republic of Adhomai", "the Adhomai Liberation Army", "the Izweski Hegemony",
|
||||
"the Zo'ra Hive","the Coalition of Colonies", "Digital Dingo", "Optimum Jeffrey", "Lemmy and the Clockworks", "President Hadii", "King Azunja","Supreme Commander Nated'Hakhan",
|
||||
@@ -148,14 +149,19 @@
|
||||
"respect","begrudging respect","love", "seasonal obligation")
|
||||
desc = "To: <i>The [station_name()]</i><BR>From: <i>[gift_benefactor], with [pick_emotion]</i>"
|
||||
|
||||
if(!gift_type)
|
||||
gift_type = get_gift_type()
|
||||
|
||||
if(ispath(gift_type, /mob/living/simple_animal))
|
||||
if(ispath(gift_type, /mob/living/simple_animal/schlorrgo))
|
||||
icon_state = "strangeschlorrgo"
|
||||
else
|
||||
icon_state = "strangepet"
|
||||
|
||||
return
|
||||
|
||||
/obj/item/xmasgift/ex_act(var/severity = 2.0)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/xmasgift/small/attack_self(mob/user)
|
||||
var/gift_type = pick(
|
||||
/obj/item/xmasgift/proc/get_gift_type()
|
||||
var/picked_gift_type = pick(
|
||||
/obj/random/action_figure,
|
||||
/obj/random/coin,
|
||||
/obj/random/spacecash,
|
||||
@@ -215,8 +221,16 @@
|
||||
/obj/item/ore/coal,
|
||||
/obj/item/stamp/clown,
|
||||
/obj/item/organ/internal/heart/skrell,
|
||||
/obj/item/toy/balloon/color)
|
||||
/obj/item/toy/balloon/color,
|
||||
/obj/item/storage/box/partypopper)
|
||||
|
||||
return picked_gift_type
|
||||
|
||||
/obj/item/xmasgift/ex_act(var/severity = 2.0)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/xmasgift/attack_self(mob/user)
|
||||
var/atom/movable/I = new gift_type(get_turf(user))
|
||||
user.remove_from_mob(src)
|
||||
user.put_in_hands(I)
|
||||
@@ -226,11 +240,10 @@
|
||||
|
||||
/obj/item/xmasgift/medium
|
||||
icon_state = "gift2"
|
||||
item_state = "gift2"
|
||||
w_class = ITEMSIZE_SMALL
|
||||
|
||||
/obj/item/xmasgift/medium/attack_self(mob/user)
|
||||
var/gift_type = pick(
|
||||
/obj/item/xmasgift/medium/get_gift_type()
|
||||
var/picked_gift_type = pick(
|
||||
/obj/item/sord,
|
||||
/obj/random/booze,
|
||||
/obj/random/random_flag,
|
||||
@@ -263,7 +276,7 @@
|
||||
/mob/living/simple_animal/rat/brown,
|
||||
/mob/living/simple_animal/rat/gray,
|
||||
/mob/living/simple_animal/rat/white,
|
||||
/obj/item/xmasgift/small,
|
||||
/obj/item/xmasgift,
|
||||
/obj/item/tank/jetpack/void,
|
||||
/obj/item/xmasgift/large,
|
||||
/obj/item/reagent_containers/food/snacks/pudding,
|
||||
@@ -286,21 +299,14 @@
|
||||
/obj/item/device/megaphone,
|
||||
/obj/item/device/violin)
|
||||
|
||||
var/atom/movable/I = new gift_type(get_turf(user))
|
||||
user.remove_from_mob(src)
|
||||
if (!user.put_in_hands(I))
|
||||
user.forceMove(get_turf(src))
|
||||
to_chat(user, SPAN_NOTICE("You open the gift, revealing your new [I.name]! Just what you always wanted!"))
|
||||
qdel(src)
|
||||
return
|
||||
return picked_gift_type
|
||||
|
||||
/obj/item/xmasgift/large
|
||||
icon_state = "gift3"
|
||||
item_state = "gift3"
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
|
||||
/obj/item/xmasgift/large/attack_self(mob/user)
|
||||
var/gift_type = pick(
|
||||
/obj/item/xmasgift/large/get_gift_type()
|
||||
var/picked_gift_type = pick(
|
||||
/obj/random/plushie,
|
||||
/obj/random/backpack,
|
||||
/obj/item/inflatable_duck,
|
||||
@@ -317,6 +323,7 @@
|
||||
/mob/living/simple_animal/mushroom,
|
||||
/mob/living/simple_animal/ice_tunneler,
|
||||
/mob/living/simple_animal/carp/baby,
|
||||
/mob/living/simple_animal/schlorrgo,
|
||||
/mob/living/carbon/human/monkey/nupnup,
|
||||
/obj/item/xmasgift/medium,
|
||||
/obj/item/tank/jetpack,
|
||||
@@ -329,11 +336,15 @@
|
||||
/mob/living/simple_animal/crab,
|
||||
/mob/living/simple_animal/parrot,
|
||||
/mob/living/simple_animal/hostile/commanded/dog/pug,
|
||||
/obj/item/target/alien)
|
||||
/obj/item/target/alien,
|
||||
/obj/item/storage/box/candy)
|
||||
|
||||
var/atom/movable/I = new gift_type(get_turf(user))
|
||||
user.remove_from_mob(src)
|
||||
user.put_in_hands(I)
|
||||
to_chat(user, SPAN_NOTICE("You open the gift, revealing your new [I.name]! Just what you always wanted!"))
|
||||
qdel(src)
|
||||
return
|
||||
return picked_gift_type
|
||||
|
||||
/obj/item/xmasgift/schlorrgo
|
||||
gift_type = /mob/living/simple_animal/schlorrgo
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
|
||||
/obj/item/xmasgift/viscerator
|
||||
gift_type = /mob/living/simple_animal/hostile/viscerator
|
||||
w_class = ITEMSIZE_NORMAL
|
||||
@@ -41,7 +41,7 @@
|
||||
eye_safety = M.eyecheck(TRUE)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs))
|
||||
if(H.protected_from_sound())
|
||||
ear_safety += 2
|
||||
if(HULK in H.mutations)
|
||||
ear_safety += 1
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
origin_tech = list(TECH_MATERIAL = 1)
|
||||
matter = list(DEFAULT_WALL_MATERIAL = 500)
|
||||
recyclable = TRUE
|
||||
var/elastic
|
||||
var/legcuff = FALSE
|
||||
var/elastic = FALSE
|
||||
var/dispenser = 0
|
||||
var/breakouttime = 1200 //Deciseconds = 120s = 2 minutes
|
||||
var/breakouttime = 2 MINUTES
|
||||
var/cuff_sound = 'sound/weapons/handcuffs.ogg'
|
||||
var/cuff_type = "handcuffs"
|
||||
drop_sound = 'sound/items/drop/accessory.ogg'
|
||||
pickup_sound = 'sound/items/pickup/accessory.ogg'
|
||||
|
||||
/obj/item/handcuffs/attack(var/mob/living/carbon/C, var/mob/living/user)
|
||||
|
||||
if(!user.IsAdvancedToolUser())
|
||||
return
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
place_handcuffs(user, user)
|
||||
return
|
||||
|
||||
if(!C.handcuffed)
|
||||
if((!legcuff && !C.handcuffed) || (legcuff && !C.legcuffed))
|
||||
if (C == user)
|
||||
place_handcuffs(user, user)
|
||||
return
|
||||
@@ -57,15 +57,20 @@
|
||||
if(!istype(H))
|
||||
return FALSE
|
||||
|
||||
if (!H.has_organ_for_slot(slot_handcuffed))
|
||||
if((!legcuff && !H.has_organ_for_slot(slot_handcuffed)) || (legcuff && !H.has_organ_for_slot(slot_legcuffed)))
|
||||
if(user)
|
||||
to_chat(user, SPAN_DANGER("\The [H] needs at least two wrists before you can cuff them together!"))
|
||||
to_chat(user, SPAN_DANGER("\The [H] needs at least two [legcuff ? "ankles" : "wrists"] before you can cuff them together!"))
|
||||
return FALSE
|
||||
|
||||
if(istype(H.gloves,/obj/item/clothing/gloves/rig) && !elastic) // Can't cuff someone who's in a deployed hardsuit.
|
||||
if(user)
|
||||
to_chat(user, SPAN_DANGER("\The [src] won't fit around \the [H.gloves]!"))
|
||||
return FALSE
|
||||
if(!elastic) // Can't cuff someone who's in a deployed hardsuit.
|
||||
if(!legcuff && istype(H.gloves, /obj/item/clothing/gloves/rig))
|
||||
if(user)
|
||||
to_chat(user, SPAN_DANGER("\The [src] won't fit around \the [H.gloves]!"))
|
||||
return FALSE
|
||||
if(legcuff && istype(H.shoes, /obj/item/clothing/shoes/magboots/rig))
|
||||
if(user)
|
||||
to_chat(user, SPAN_DANGER("\The [src] won't fit around \the [H.shoes]!"))
|
||||
return FALSE
|
||||
|
||||
if(user)
|
||||
user.visible_message(SPAN_DANGER("\The [user] is attempting to put [cuff_type] on \the [H]!"))
|
||||
@@ -85,8 +90,9 @@
|
||||
user.do_attack_animation(H)
|
||||
user.visible_message(SPAN_DANGER("\The [user] has put [cuff_type] on \the [H]!"))
|
||||
|
||||
target.drop_r_hand()
|
||||
target.drop_l_hand()
|
||||
if(!legcuff)
|
||||
target.drop_r_hand()
|
||||
target.drop_l_hand()
|
||||
|
||||
// Apply cuffs.
|
||||
var/obj/item/handcuffs/cuffs = src
|
||||
@@ -96,8 +102,13 @@
|
||||
user.drop_from_inventory(cuffs,target)
|
||||
else
|
||||
cuffs.forceMove(target)
|
||||
target.handcuffed = cuffs
|
||||
target.update_inv_handcuffed()
|
||||
|
||||
if(!legcuff)
|
||||
target.handcuffed = cuffs
|
||||
target.update_inv_handcuffed()
|
||||
else
|
||||
target.legcuffed = cuffs
|
||||
target.update_inv_legcuffed()
|
||||
return TRUE
|
||||
|
||||
/mob/living/carbon/human/RestrainedClickOn(var/atom/A)
|
||||
@@ -137,9 +148,9 @@
|
||||
slot_l_hand_str = 'icons/mob/items/stacks/lefthand_materials.dmi',
|
||||
slot_r_hand_str = 'icons/mob/items/stacks/righthand_materials.dmi',
|
||||
)
|
||||
breakouttime = 300 //Deciseconds = 30s
|
||||
breakouttime = 30 SECONDS
|
||||
cuff_sound = 'sound/weapons/cablecuff.ogg'
|
||||
cuff_type = "cable restraints"
|
||||
cuff_type = "cable restraint handcuffs"
|
||||
var/can_be_cut = TRUE
|
||||
elastic = TRUE
|
||||
build_from_parts = TRUE
|
||||
@@ -155,6 +166,13 @@
|
||||
color = pick(COLOR_RED, COLOR_BLUE, COLOR_LIME, COLOR_ORANGE, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN)
|
||||
add_overlay(overlay_image(icon, "[initial(icon_state)]_end", flags=RESET_COLOR))
|
||||
|
||||
/obj/item/handcuffs/cable/attack_self(mob/user)
|
||||
legcuff = !legcuff
|
||||
cuff_type = "cable restraint [legcuff ? "leg" : "hand"]cuffs"
|
||||
to_chat(user, SPAN_NOTICE("You twist the cable into [cuff_type]."))
|
||||
icon_state = "cable[legcuff ? "leg" : ""]cuff"
|
||||
breakouttime = legcuff ? 10 SECONDS : 30 SECONDS
|
||||
|
||||
/obj/item/handcuffs/cable/yellow
|
||||
color = COLOR_YELLOW
|
||||
|
||||
@@ -169,6 +187,9 @@
|
||||
desc = "A set of handcuffs made out of vines. How devilish!"
|
||||
can_be_cut = FALSE
|
||||
|
||||
/obj/item/handcuffs/cable/green/vines/attack_self(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/handcuffs/cable/pink
|
||||
color = COLOR_PINK
|
||||
|
||||
@@ -211,14 +232,22 @@
|
||||
icon_state = "tape_cross"
|
||||
item_state = null
|
||||
icon = 'icons/obj/bureaucracy.dmi'
|
||||
breakouttime = 200
|
||||
breakouttime = 20 SECONDS
|
||||
cuff_type = "duct tape"
|
||||
|
||||
/obj/item/handcuffs/ziptie
|
||||
name = "ziptie"
|
||||
desc = " A sturdy and reliable plastic ziptie for binding the wrists."
|
||||
icon_state = "ziptie"
|
||||
breakouttime = 600
|
||||
breakouttime = 1 MINUTE
|
||||
cuff_sound = 'sound/weapons/cablecuff.ogg'
|
||||
cuff_type = "zipties"
|
||||
elastic = TRUE
|
||||
|
||||
/obj/item/handcuffs/legcuffs
|
||||
name = "legcuffs"
|
||||
desc = "Use this to keep prisoners in line."
|
||||
icon_state = "legcuff"
|
||||
legcuff = TRUE
|
||||
breakouttime = 30 SECONDS
|
||||
cuff_type = "legcuffs"
|
||||
@@ -17,6 +17,24 @@
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/material/ashtray/shatter()
|
||||
if(emptyout(get_turf(src)))
|
||||
visible_message(SPAN_DANGER("The contents of [src] spill everywhere!"))
|
||||
|
||||
/obj/item/material/ashtray/proc/emptyout(atom/dest)
|
||||
var/count = 0
|
||||
for (var/obj/item/clothing/mask/smokable/cigarette/O in contents)
|
||||
count++
|
||||
O.forceMove(dest)
|
||||
return count > 0
|
||||
|
||||
/obj/item/material/ashtray/attack_self(mob/user)
|
||||
var/turf/dest = get_turf(src)
|
||||
if(emptyout(dest))
|
||||
user.visible_message("<b>[user]</b> pours [src] out onto [dest].", SPAN_NOTICE("You pour [src] out onto [dest]."))
|
||||
return
|
||||
to_chat(user, SPAN_WARNING("[src] is empty, there's nothing to pour out!"))
|
||||
|
||||
/obj/item/material/ashtray/update_icon()
|
||||
color = null
|
||||
cut_overlays()
|
||||
@@ -50,7 +68,7 @@
|
||||
if (istype(W,/obj/item/clothing/mask/smokable/cigarette))
|
||||
var/obj/item/clothing/mask/smokable/cigarette/cig = W
|
||||
if (cig.lit == TRUE)
|
||||
src.visible_message("[user] crushes [cig] in \the [src], putting it out.")
|
||||
user.visible_message("<b>[user]</b> crushes [cig] in \the [src], putting it out.", SPAN_NOTICE(""))
|
||||
playsound(src.loc, 'sound/items/cigs_lighters/cig_snuff.ogg', 50, 1)
|
||||
STOP_PROCESSING(SSprocessing, cig)
|
||||
var/obj/item/butt = new cig.type_butt(src)
|
||||
@@ -60,7 +78,10 @@
|
||||
//spawn(1)
|
||||
// TemperatureAct(150)
|
||||
else if (cig.lit == FALSE)
|
||||
to_chat(user, "You place [cig] in [src] without even smoking it. Why would you do that?")
|
||||
user.visible_message(
|
||||
"<b>[user]</b> places [cig] in [src] without even smoking it.",
|
||||
SPAN_NOTICE("You place [cig] in [src] without even smoking it. Why would you do that?")
|
||||
)
|
||||
|
||||
src.visible_message("[user] places [W] in [src].")
|
||||
user.update_inv_l_hand()
|
||||
@@ -69,7 +90,8 @@
|
||||
update_icon()
|
||||
else
|
||||
health = max(0,health - W.force)
|
||||
to_chat(user, "You hit [src] with [W].")
|
||||
user.visible_message(user, SPAN_DANGER("[user] hits [src] with [W]!"), SPAN_DANGER("You hit [src] with [W]."))
|
||||
playsound(get_turf(src), material.hitsound, 25)
|
||||
if (health < 1)
|
||||
shatter()
|
||||
return
|
||||
@@ -77,10 +99,8 @@
|
||||
/obj/item/material/ashtray/throw_impact(atom/hit_atom)
|
||||
if (health > 0)
|
||||
health = max(0,health - 3)
|
||||
if (contents.len)
|
||||
src.visible_message("<span class='danger'>\The [src] slams into [hit_atom], spilling its contents!</span>")
|
||||
for (var/obj/item/clothing/mask/smokable/cigarette/O in contents)
|
||||
O.forceMove(src.loc)
|
||||
if(emptyout(get_turf(src)))
|
||||
visible_message(SPAN_DANGER("[src] slams into [hit_atom], spilling its contents everywhere!"))
|
||||
if (health < 1)
|
||||
shatter()
|
||||
return
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
if(H.shoes || H.wear_suit?.body_parts_covered & FEET)
|
||||
damage_coef -= 0.1
|
||||
|
||||
if (H.m_intent == "run")
|
||||
if (H.m_intent == M_RUN)
|
||||
damage_coef += 0.4
|
||||
|
||||
|
||||
|
||||
@@ -17,9 +17,15 @@ var/list/tape_roll_applications = list()
|
||||
icon = 'icons/policetape.dmi'
|
||||
anchored = 1
|
||||
var/lifted = 0
|
||||
var/list/crumplers
|
||||
var/crumpled = 0
|
||||
var/icon_base
|
||||
|
||||
/obj/item/tape/examine(mob/user, distance)
|
||||
. = ..()
|
||||
if(LAZYLEN(crumplers) && Adjacent(user))
|
||||
to_chat(user, SPAN_WARNING("\The [initial(name)] has been crumpled by [english_list(crumplers)]."))
|
||||
|
||||
/obj/item/tape/New()
|
||||
..()
|
||||
if(!hazard_overlays)
|
||||
@@ -42,6 +48,19 @@ var/list/tape_roll_applications = list()
|
||||
req_access = list(access_security)
|
||||
icon_base = "police"
|
||||
|
||||
/obj/item/taperoll/medical
|
||||
name = "medical tape"
|
||||
desc = "A roll of medical tape used to prevent overcrowding of hallways during emergencies."
|
||||
icon_state = "medical_start"
|
||||
tape_type = /obj/item/tape/medical
|
||||
icon_base = "medical"
|
||||
|
||||
/obj/item/tape/medical
|
||||
name = "medical tape"
|
||||
desc = "A length of medical tape. Better not cross it."
|
||||
req_one_access = list(access_medical_equip)
|
||||
icon_base = "medical"
|
||||
|
||||
/obj/item/taperoll/engineering
|
||||
name = "engineering tape"
|
||||
desc = "A roll of engineering tape used to block off working areas from the public."
|
||||
@@ -137,41 +156,50 @@ var/list/tape_roll_applications = list()
|
||||
tape_roll_applications[F] |= direction
|
||||
return
|
||||
|
||||
/obj/item/tape/proc/crumple()
|
||||
/obj/item/tape/proc/crumple(var/mob/user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/card/id/ID = H.GetIdCard(TRUE)
|
||||
if(ID && ID.registered_name)
|
||||
LAZYDISTINCTADD(crumplers, ID.registered_name)
|
||||
if(!crumpled)
|
||||
crumpled = 1
|
||||
crumpled = TRUE
|
||||
icon_state = "[icon_state]_c"
|
||||
name = "crumpled [name]"
|
||||
|
||||
/obj/item/tape/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(!lifted && ismob(mover))
|
||||
var/mob/M = mover
|
||||
add_fingerprint(M)
|
||||
if (!allowed(M)) //only select few learn art of not crumpling the tape
|
||||
to_chat(M, "<span class='warning'>You are not supposed to go past [src]...</span>")
|
||||
crumple()
|
||||
return ..(mover)
|
||||
if(!allowed(M)) //only select few learn art of not crumpling the tape
|
||||
if(M.a_intent != I_HURT && M.m_intent != M_RUN)
|
||||
return FALSE
|
||||
to_chat(M, SPAN_WARNING("You aren't supposed to go past the [initial(name)]..."))
|
||||
crumple(mover)
|
||||
return ..()
|
||||
|
||||
/obj/item/tape/attackby(obj/item/W as obj, mob/user as mob)
|
||||
/obj/item/tape/attackby(obj/item/W, mob/user)
|
||||
breaktape(W, user)
|
||||
|
||||
/obj/item/tape/attack_hand(mob/user as mob)
|
||||
if (user.a_intent == I_HELP && src.allowed(user))
|
||||
user.show_viewers(SPAN_NOTICE("[user] lifts [src], allowing passage."))
|
||||
crumple()
|
||||
lifted = 1
|
||||
spawn(200)
|
||||
lifted = 0
|
||||
/obj/item/tape/attack_hand(mob/user)
|
||||
if(user.a_intent == I_HELP)
|
||||
lifted = !lifted
|
||||
user.visible_message("<b>[user]</b> [lifted ? "lifts" : "drops"] the [initial(name)], [lifted ? "allowing" : "blocking"] passage.", SPAN_NOTICE("You [lifted ? "lift" : "drop"] the [initial(name)], [lifted ? "allowing" : "blocking"] passage."))
|
||||
var/shake_time = animate_shake()
|
||||
sleep(shake_time)
|
||||
if(!allowed(user))
|
||||
crumple(user)
|
||||
if(lifted)
|
||||
animate(src, 1 SECOND, alpha = 150)
|
||||
else
|
||||
animate(src, 1 SECOND, alpha = initial(alpha))
|
||||
else
|
||||
breaktape(null, user)
|
||||
|
||||
|
||||
|
||||
/obj/item/tape/proc/breaktape(obj/item/W as obj, mob/user as mob)
|
||||
if(user.a_intent == I_HELP && ((!can_puncture(W) && src.allowed(user))))
|
||||
to_chat(user, "You can't break the [src] with that!")
|
||||
to_chat(user, SPAN_NOTICE("You can't break \the [src] with that!"))
|
||||
return
|
||||
user.show_viewers(SPAN_NOTICE("[user] breaks the [src]!"))
|
||||
user.visible_message(SPAN_NOTICE("[user] breaks \the [src]!"))
|
||||
|
||||
var/dir[2]
|
||||
var/icon_dir = src.icon_state
|
||||
@@ -193,5 +221,4 @@ var/list/tape_roll_applications = list()
|
||||
qdel(P)
|
||||
cur = get_step(cur,dir[i])
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
qdel(src)
|
||||
@@ -512,6 +512,11 @@
|
||||
desc_antag = "These snap pops have an extra compound added that will deploy a tiny smokescreen when snapped."
|
||||
starts_with = list(/obj/item/toy/snappop/syndi = 8)
|
||||
|
||||
/obj/item/storage/box/partypopper
|
||||
name = "party popper box"
|
||||
desc = "Six cones of confetti conflagarating fun!"
|
||||
starts_with = list(/obj/item/toy/partypopper = 6)
|
||||
|
||||
/obj/item/storage/box/autoinjectors
|
||||
name = "box of empty injectors"
|
||||
desc = "Contains empty autoinjectors."
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user