diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt
index c2625e2663..7063273378 100644
--- a/SQL/database_changelog.txt
+++ b/SQL/database_changelog.txt
@@ -1,13 +1,52 @@
Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255.
-The latest database version is 3.1; The query to update the schema revision table is:
+The latest database version is 3.4; The query to update the schema revision table is:
-INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 1);
+INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 4);
or
-INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 1);
+INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 4);
+
+In any query remember to add a prefix to the table names if you use one.
----------------------------------------------------
+28 August 2017, by MrStonedOne
+Modified table 'messages', adding a deleted column and editing all indexes to include it
+
+ALTER TABLE `messages`
+ADD COLUMN `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' AFTER `edits`,
+DROP INDEX `idx_msg_ckey_time`,
+DROP INDEX `idx_msg_type_ckeys_time`,
+DROP INDEX `idx_msg_type_ckey_time_odr`,
+ADD INDEX `idx_msg_ckey_time` (`targetckey`,`timestamp`, `deleted`),
+ADD INDEX `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`, `deleted`),
+ADD INDEX `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`, `deleted`);
+
+----------------------------------------------------
+
+25 August 2017, by Jordie0608
+
+Modified tables 'connection_log', 'legacy_population', 'library', 'messages' and 'player' to add additional 'round_id' tracking in various forms and 'server_ip' and 'server_port' to the table 'messages'.
+
+ALTER TABLE `connection_log` ADD COLUMN `round_id` INT(11) UNSIGNED NOT NULL AFTER `server_port`;
+ALTER TABLE `legacy_population` ADD COLUMN `round_id` INT(11) UNSIGNED NOT NULL AFTER `server_port`;
+ALTER TABLE `library` ADD COLUMN `round_id_created` INT(11) UNSIGNED NOT NULL AFTER `deleted`;
+ALTER TABLE `messages` ADD COLUMN `server_ip` INT(10) UNSIGNED NOT NULL AFTER `server`, ADD COLUMN `server_port` SMALLINT(5) UNSIGNED NOT NULL AFTER `server_ip`, ADD COLUMN `round_id` INT(11) UNSIGNED NOT NULL AFTER `server_port`;
+ALTER TABLE `player` ADD COLUMN `firstseen_round_id` INT(11) UNSIGNED NOT NULL AFTER `firstseen`, ADD COLUMN `lastseen_round_id` INT(11) UNSIGNED NOT NULL AFTER `lastseen`;
+
+----------------------------------------------------
+
+18 August 2017, by Cyberboss and nfreader
+
+Modified table 'death', adding the columns `last_words` and 'suicide'.
+
+ALTER TABLE `death`
+ADD COLUMN `last_words` varchar(255) DEFAULT NULL AFTER `staminaloss`,
+ADD COLUMN `suicide` tinyint(0) NOT NULL DEFAULT '0' AFTER `last_words`;
+
+Remember to add a prefix to the table name if you use them.
+
+----------------------------------------------------
20th July 2017, by Shadowlight213
Added role_time table to track time spent playing departments.
@@ -17,21 +56,10 @@ CREATE TABLE `role_time` ( `ckey` VARCHAR(32) NOT NULL , `job` VARCHAR(128) NOT
ALTER TABLE `player` ADD `flags` INT NOT NULL default '0' AFTER `accountjoindate`;
-
-UPDATE `schema_revision` SET minor = 1;
Remember to add a prefix to the table name if you use them.
----------------------------------------------------
-Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255.
-
-The latest database version is 3.0; The query to update the schema revision table is:
-
-INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 0);
-or
-INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 0);
-
-----------------------------------------------------
28 June 2017, by oranges
Added schema_revision to store the current db revision, why start at 3.0?
@@ -336,4 +364,4 @@ UPDATE erro_library SET deleted = 1 WHERE id = someid
(Replace someid with the id of the book you want to soft delete.)
-----------------------------------------------------
+----------------------------------------------------
\ No newline at end of file
diff --git a/SQL/errofreedatabase.sql b/SQL/errofreedatabase.sql
index 7f23fcc861..7d6ea4561c 100644
--- a/SQL/errofreedatabase.sql
+++ b/SQL/errofreedatabase.sql
@@ -12,4 +12,4 @@ ALTER TABLE erro_poll_option RENAME TO SS13_poll_option;
ALTER TABLE erro_poll_question RENAME TO SS13_poll_question;
ALTER TABLE erro_poll_textreply RENAME TO SS13_poll_textreply;
ALTER TABLE erro_poll_vote RENAME TO SS13_poll_vote;
-ALTER TABLE erro_watch RENAME TO SS13_watch;
+ALTER TABLE erro_watch RENAME TO SS13_watch;
\ No newline at end of file
diff --git a/SQL/optimisations_2017-02-19.sql b/SQL/optimisations_2017-02-19.sql
index 674cbcf9c6..b9017497ed 100644
--- a/SQL/optimisations_2017-02-19.sql
+++ b/SQL/optimisations_2017-02-19.sql
@@ -38,7 +38,7 @@ Take note some columns have been renamed, removed or changed type. Any services
----------------------------------------------------*/
START TRANSACTION;
-ALTER TABLE `feedback`.`ban`
+ALTER TABLE `ban`
DROP COLUMN `rounds`
, CHANGE COLUMN `bantype` `bantype` ENUM('PERMABAN', 'TEMPBAN', 'JOB_PERMABAN', 'JOB_TEMPBAN', 'ADMIN_PERMABAN', 'ADMIN_TEMPBAN') NOT NULL
, CHANGE COLUMN `reason` `reason` VARCHAR(2048) NOT NULL
@@ -51,14 +51,14 @@ ALTER TABLE `feedback`.`ban`
, ADD COLUMN `a_ipTEMP` INT UNSIGNED NOT NULL AFTER `a_ip`
, ADD COLUMN `unbanned_ipTEMP` INT UNSIGNED NULL DEFAULT NULL AFTER `unbanned_ip`;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`ban`
+UPDATE `ban`
SET `server_ip` = INET_ATON(SUBSTRING_INDEX(IF(`serverip` = '', '0', IF(SUBSTRING_INDEX(`serverip`, ':', 1) LIKE '%_._%', `serverip`, '0')), ':', 1))
, `server_port` = IF(`serverip` LIKE '%:_%', CAST(SUBSTRING_INDEX(`serverip`, ':', -1) AS UNSIGNED), '0')
, `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0'))
, `a_ipTEMP` = INET_ATON(IF(`a_ip` LIKE '%_._%', `a_ip`, '0'))
, `unbanned_ipTEMP` = INET_ATON(IF(`unbanned_ip` LIKE '%_._%', `unbanned_ip`, '0'));
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`ban`
+ALTER TABLE `ban`
DROP COLUMN `unbanned_ip`
, DROP COLUMN `a_ip`
, DROP COLUMN `ip`
@@ -69,17 +69,17 @@ ALTER TABLE `feedback`.`ban`
COMMIT;
START TRANSACTION;
-ALTER TABLE `feedback`.`connection_log`
+ALTER TABLE `connection_log`
ADD COLUMN `server_ip` INT UNSIGNED NOT NULL AFTER `serverip`
, ADD COLUMN `server_port` SMALLINT UNSIGNED NOT NULL AFTER `server_ip`
, ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`connection_log`
+UPDATE `connection_log`
SET `server_ip` = INET_ATON(SUBSTRING_INDEX(IF(`serverip` = '', '0', IF(SUBSTRING_INDEX(`serverip`, ':', 1) LIKE '%_._%', `serverip`, '0')), ':', 1))
, `server_port` = IF(`serverip` LIKE '%:_%', CAST(SUBSTRING_INDEX(`serverip`, ':', -1) AS UNSIGNED), '0')
, `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0'));
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`connection_log`
+ALTER TABLE `connection_log`
DROP COLUMN `ip`
, DROP COLUMN `serverip`
, CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL;
@@ -87,12 +87,12 @@ COMMIT;
START TRANSACTION;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`death`
+UPDATE `death`
SET `bruteloss` = LEAST(`bruteloss`, 65535)
, `brainloss` = LEAST(`brainloss`, 65535)
, `fireloss` = LEAST(`fireloss`, 65535)
, `oxyloss` = LEAST(`oxyloss`, 65535);
-ALTER TABLE `feedback`.`death`
+ALTER TABLE `death`
CHANGE COLUMN `pod` `pod` VARCHAR(50) NOT NULL
, CHANGE COLUMN `coord` `coord` VARCHAR(32) NOT NULL
, CHANGE COLUMN `mapname` `mapname` VARCHAR(32) NOT NULL
@@ -109,39 +109,39 @@ ALTER TABLE `feedback`.`death`
, CHANGE COLUMN `oxyloss` `oxyloss` SMALLINT UNSIGNED NOT NULL
, ADD COLUMN `server_ip` INT UNSIGNED NOT NULL AFTER `server`
, ADD COLUMN `server_port` SMALLINT UNSIGNED NOT NULL AFTER `server_ip`;
-UPDATE `feedback`.`death`
+UPDATE `death`
SET `server_ip` = INET_ATON(SUBSTRING_INDEX(IF(`server` = '', '0', IF(SUBSTRING_INDEX(`server`, ':', 1) LIKE '%_._%', `server`, '0')), ':', 1))
, `server_port` = IF(`server` LIKE '%:_%', CAST(SUBSTRING_INDEX(`server`, ':', -1) AS UNSIGNED), '0');
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`death`
+ALTER TABLE `death`
DROP COLUMN `server`;
COMMIT;
-ALTER TABLE `feedback`.`library`
+ALTER TABLE `library`
CHANGE COLUMN `category` `category` ENUM('Any', 'Fiction', 'Non-Fiction', 'Adult', 'Reference', 'Religion') NOT NULL
, CHANGE COLUMN `ckey` `ckey` VARCHAR(32) NOT NULL DEFAULT 'LEGACY'
, CHANGE COLUMN `datetime` `datetime` DATETIME NOT NULL
, CHANGE COLUMN `deleted` `deleted` TINYINT(1) UNSIGNED NULL DEFAULT NULL;
-ALTER TABLE `feedback`.`messages`
+ALTER TABLE `messages`
CHANGE COLUMN `type` `type` ENUM('memo', 'message', 'message sent', 'note', 'watchlist entry') NOT NULL
, CHANGE COLUMN `text` `text` VARCHAR(2048) NOT NULL
, CHANGE COLUMN `secret` `secret` TINYINT(1) UNSIGNED NOT NULL;
START TRANSACTION;
-ALTER TABLE `feedback`.`player`
+ALTER TABLE `player`
ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`player`
+UPDATE `player`
SET `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0'));
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`player`
+ALTER TABLE `player`
DROP COLUMN `ip`
, CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL;
COMMIT;
START TRANSACTION;
-ALTER TABLE `feedback`.`poll_question`
+ALTER TABLE `poll_question`
CHANGE COLUMN `polltype` `polltype` ENUM('OPTION', 'TEXT', 'NUMVAL', 'MULTICHOICE', 'IRV') NOT NULL
, CHANGE COLUMN `adminonly` `adminonly` TINYINT(1) UNSIGNED NOT NULL
, CHANGE COLUMN `createdby_ckey` `createdby_ckey` VARCHAR(32) NULL DEFAULT NULL
@@ -149,36 +149,36 @@ ALTER TABLE `feedback`.`poll_question`
, ADD COLUMN `createdby_ipTEMP` INT UNSIGNED NOT NULL AFTER `createdby_ip`
, DROP COLUMN `for_trialmin`;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`poll_question`
+UPDATE `poll_question`
SET `createdby_ipTEMP` = INET_ATON(IF(`createdby_ip` LIKE '%_._%', `createdby_ip`, '0'));
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`poll_question`
+ALTER TABLE `poll_question`
DROP COLUMN `createdby_ip`
, CHANGE COLUMN `createdby_ipTEMP` `createdby_ip` INT(10) UNSIGNED NOT NULL;
COMMIT;
START TRANSACTION;
-ALTER TABLE `feedback`.`poll_textreply`
+ALTER TABLE `poll_textreply`
CHANGE COLUMN `replytext` `replytext` VARCHAR(2048) NOT NULL
, ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`poll_textreply`
+UPDATE `poll_textreply`
SET `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0'));
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`poll_textreply`
+ALTER TABLE `poll_textreply`
DROP COLUMN `ip`
, CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL;
COMMIT;
START TRANSACTION;
-ALTER TABLE `feedback`.`poll_vote`
+ALTER TABLE `poll_vote`
CHANGE COLUMN `ckey` `ckey` VARCHAR(32) NOT NULL
, ADD COLUMN `ipTEMP` INT UNSIGNED NOT NULL AFTER `ip`;
SET SQL_SAFE_UPDATES = 0;
-UPDATE `feedback`.`poll_vote`
+UPDATE `poll_vote`
SET `ipTEMP` = INET_ATON(IF(`ip` LIKE '%_._%', `ip`, '0'));
SET SQL_SAFE_UPDATES = 1;
-ALTER TABLE `feedback`.`poll_vote`
+ALTER TABLE `poll_vote`
DROP COLUMN `ip`
, CHANGE COLUMN `ipTEMP` `ip` INT(10) UNSIGNED NOT NULL;
COMMIT;
@@ -191,39 +191,39 @@ You may find it helpful to modify or create your own indexes if you utilise addi
----------------------------------------------------*/
-ALTER TABLE `feedback`.`ban`
+ALTER TABLE `ban`
ADD INDEX `idx_ban_checkban` (`ckey` ASC, `bantype` ASC, `expiration_time` ASC, `unbanned` ASC, `job` ASC)
, ADD INDEX `idx_ban_isbanned` (`ckey` ASC, `ip` ASC, `computerid` ASC, `bantype` ASC, `expiration_time` ASC, `unbanned` ASC)
, ADD INDEX `idx_ban_count` (`id` ASC, `a_ckey` ASC, `bantype` ASC, `expiration_time` ASC, `unbanned` ASC);
-ALTER TABLE `feedback`.`ipintel`
+ALTER TABLE `ipintel`
ADD INDEX `idx_ipintel` (`ip` ASC, `intel` ASC, `date` ASC);
-ALTER TABLE `feedback`.`library`
+ALTER TABLE `library`
ADD INDEX `idx_lib_id_del` (`id` ASC, `deleted` ASC)
, ADD INDEX `idx_lib_del_title` (`deleted` ASC, `title` ASC)
, ADD INDEX `idx_lib_search` (`deleted` ASC, `author` ASC, `title` ASC, `category` ASC);
-ALTER TABLE `feedback`.`messages`
+ALTER TABLE `messages`
ADD INDEX `idx_msg_ckey_time` (`targetckey` ASC, `timestamp` ASC)
, ADD INDEX `idx_msg_type_ckeys_time` (`type` ASC, `targetckey` ASC, `adminckey` ASC, `timestamp` ASC)
, ADD INDEX `idx_msg_type_ckey_time_odr` (`type` ASC, `targetckey` ASC, `timestamp` ASC);
-ALTER TABLE `feedback`.`player`
+ALTER TABLE `player`
ADD INDEX `idx_player_cid_ckey` (`computerid` ASC, `ckey` ASC)
, ADD INDEX `idx_player_ip_ckey` (`ip` ASC, `ckey` ASC);
-ALTER TABLE `feedback`.`poll_option`
+ALTER TABLE `poll_option`
ADD INDEX `idx_pop_pollid` (`pollid` ASC);
-ALTER TABLE `feedback`.`poll_question`
+ALTER TABLE `poll_question`
ADD INDEX `idx_pquest_question_time_ckey` (`question` ASC, `starttime` ASC, `endtime` ASC, `createdby_ckey` ASC, `createdby_ip` ASC)
, ADD INDEX `idx_pquest_time_admin` (`starttime` ASC, `endtime` ASC, `adminonly` ASC)
, ADD INDEX `idx_pquest_id_time_type_admin` (`id` ASC, `starttime` ASC, `endtime` ASC, `polltype` ASC, `adminonly` ASC);
-ALTER TABLE `feedback`.`poll_vote`
+ALTER TABLE `poll_vote`
ADD INDEX `idx_pvote_pollid_ckey` (`pollid` ASC, `ckey` ASC)
, ADD INDEX `idx_pvote_optionid_ckey` (`optionid` ASC, `ckey` ASC);
-ALTER TABLE `feedback`.`poll_textreply`
- ADD INDEX `idx_ptext_pollid_ckey` (`pollid` ASC, `ckey` ASC);
+ALTER TABLE `poll_textreply`
+ ADD INDEX `idx_ptext_pollid_ckey` (`pollid` ASC, `ckey` ASC);
\ No newline at end of file
diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql
index 12b0b93c6a..1edd5ad12b 100644
--- a/SQL/tgstation_schema.sql
+++ b/SQL/tgstation_schema.sql
@@ -254,10 +254,11 @@ CREATE TABLE `messages` (
`secret` tinyint(1) unsigned NOT NULL,
`lasteditor` varchar(32) DEFAULT NULL,
`edits` text,
+ `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
- KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`),
- KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`),
- KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`)
+ KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`, `deleted`),
+ KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`, `deleted`),
+ KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`, `deleted`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -430,4 +431,4 @@ CREATE TABLE `schema_revision` (
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
\ No newline at end of file
diff --git a/SQL/tgstation_schema.sql.rej b/SQL/tgstation_schema.sql.rej
deleted file mode 100644
index 51068bed4e..0000000000
--- a/SQL/tgstation_schema.sql.rej
+++ /dev/null
@@ -1,9 +0,0 @@
-diff a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql (rejected hunks)
-@@ -268,7 +283,6 @@ CREATE TABLE `player` (
- `ip` int(10) unsigned NOT NULL,
- `computerid` varchar(32) NOT NULL,
- `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
-- `exp` mediumtext,
- PRIMARY KEY (`id`),
- UNIQUE KEY `ckey` (`ckey`),
- KEY `idx_player_cid_ckey` (`computerid`,`ckey`),
diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql
index 6c8ea19b0f..72045e50fb 100644
--- a/SQL/tgstation_schema_prefixed.sql
+++ b/SQL/tgstation_schema_prefixed.sql
@@ -31,7 +31,7 @@ CREATE TABLE `SS13_admin` (
-- Table structure for table `SS13_admin_log`
--
-DROP TABLE IF EXISTS `SS13_dmin_log`;
+DROP TABLE IF EXISTS `SS13_admin_log`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `SS13_admin_log` (
@@ -254,10 +254,11 @@ CREATE TABLE `SS13_messages` (
`secret` tinyint(1) unsigned NOT NULL,
`lasteditor` varchar(32) DEFAULT NULL,
`edits` text,
+ `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
- KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`),
- KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`),
- KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`)
+ KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`, `deleted`),
+ KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`, `deleted`),
+ KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`, `deleted`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -430,4 +431,4 @@ CREATE TABLE `SS13_schema_revision` (
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
\ No newline at end of file
diff --git a/SQL/tgstation_schema_prefixed.sql.rej b/SQL/tgstation_schema_prefixed.sql.rej
deleted file mode 100644
index dd4bc6a7f5..0000000000
--- a/SQL/tgstation_schema_prefixed.sql.rej
+++ /dev/null
@@ -1,9 +0,0 @@
-diff a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql (rejected hunks)
-@@ -268,7 +297,6 @@ CREATE TABLE `SS13_player` (
- `ip` int(10) unsigned NOT NULL,
- `computerid` varchar(32) NOT NULL,
- `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
-- `exp` mediumtext,
- PRIMARY KEY (`id`),
- UNIQUE KEY `ckey` (`ckey`),
- KEY `idx_player_cid_ckey` (`computerid`,`ckey`),
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 95f1cb283c..27f366f7f8 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -24458,7 +24458,7 @@
/area/crew_quarters/heads/captain)
"bfE" = (
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/item/storage/secure/safe{
pixel_x = 35;
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 5e0ded4416..0484d95b79 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -53210,7 +53210,7 @@
/area/tcommsat/server)
"bYo" = (
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/item/device/radio/intercom{
name = "Station Intercom";
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index ec76a564d5..a60e43dd83 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -29108,7 +29108,7 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/turf/open/floor/carpet,
/area/crew_quarters/heads/captain/private)
diff --git a/_maps/map_files/OmegaStation/OmegaStation.dmm b/_maps/map_files/OmegaStation/OmegaStation.dmm
index 207a64fe5d..419737682f 100644
--- a/_maps/map_files/OmegaStation/OmegaStation.dmm
+++ b/_maps/map_files/OmegaStation/OmegaStation.dmm
@@ -1187,7 +1187,7 @@
pixel_x = 32;
pixel_y = 24
},
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 10
diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm
index 502f7ba293..66a9216882 100644
--- a/_maps/map_files/PubbyStation/PubbyStation.dmm
+++ b/_maps/map_files/PubbyStation/PubbyStation.dmm
@@ -13917,7 +13917,7 @@
/area/storage/primary)
"aEx" = (
/obj/structure/table/wood,
-/obj/item/pinpointer,
+/obj/item/pinpointer/nuke,
/obj/item/disk/nuclear,
/obj/machinery/light{
dir = 8
diff --git a/code/__DEFINES/pinpointers.dm b/code/__DEFINES/pinpointers.dm
index 80403e54de..75f0452ea9 100644
--- a/code/__DEFINES/pinpointers.dm
+++ b/code/__DEFINES/pinpointers.dm
@@ -2,6 +2,3 @@
#define TRACK_NUKE_DISK 1 //We track the nuclear authentication disk, either to protect it or steal it
#define TRACK_MALF_AI 2 //We track the malfunctioning AI, so we can prevent it from blowing us all up
#define TRACK_INFILTRATOR 3 //We track the Syndicate infiltrator, so we can get back to ship when the nuke's armed
-#define TRACK_OPERATIVES 4 //We track the closest operative, so we can regroup when we need to
-#define TRACK_ATOM 5 //We track a specified atom, so admins can make us function for events
-#define TRACK_COORDINATES 6 //We point towards the specified coordinates on our z-level, so we can navigate
diff --git a/code/citadel/custom_loadout/custom_items.dm b/code/citadel/custom_loadout/custom_items.dm
index 6495d38a0f..da81dfb37c 100644
--- a/code/citadel/custom_loadout/custom_items.dm
+++ b/code/citadel/custom_loadout/custom_items.dm
@@ -10,6 +10,9 @@
w_class = WEIGHT_CLASS_TINY
flags_1 = NOBLUDGEON_1
+
+/*Inferno707*/
+
/obj/item/clothing/neck/cloak/inferno
name = "Kiara's Cloak"
desc = "The design on this seems a little too familiar."
@@ -19,6 +22,16 @@
w_class = WEIGHT_CLASS_SMALL
body_parts_covered = CHEST|GROIN|LEGS|ARMS
+/obj/item/clothing/neck/petcollar/inferno
+ name = "Kiara's Collar"
+ desc = "A soft black collar that seems to stretch to fit whoever wears it."
+ icon_state = "infcollar"
+ item_state = "infcollar"
+ item_color = null
+ tagname = null
+
+/*DirtyOldHarry*/
+
/obj/item/lighter/gold
name = "\improper Engraved Zippo"
desc = "A shiny and relatively expensive zippo lighter. There's a small etched in verse on the bottom that reads, 'No Gods, No Masters, Only Man.'"
@@ -30,4 +43,14 @@
slot_flags = SLOT_BELT
heat = 1500
resistance_flags = FIRE_PROOF
- light_color = LIGHT_COLOR_FIRE
\ No newline at end of file
+ light_color = LIGHT_COLOR_FIRE
+
+
+/*Zombierobin*/
+
+/obj/item/clothing/neck/scarf/zomb //Default white color, same functionality as beanies.
+ name = "A special scarf"
+ icon_state = "zombscarf"
+ desc = "A fashionable collar"
+ item_color = "zombscarf"
+ dog_fashion = /datum/dog_fashion/head
\ No newline at end of file
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 311b96808d..180d14853e 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -108,6 +108,8 @@ GLOBAL_PROTECT(config_dir)
var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database
var/use_account_age_for_jobs = 0 //Uses the time they made the account for the job restriction stuff. New player joining alerts should be unaffected.
var/see_own_notes = 0 //Can players see their own admin notes (read-only)? Config option in config.txt
+ var/note_fresh_days
+ var/note_stale_days
var/use_exp_tracking = FALSE
var/use_exp_restrictions_heads = FALSE
@@ -486,6 +488,10 @@ GLOBAL_PROTECT(config_dir)
showircname = 1
if("see_own_notes")
see_own_notes = 1
+ if("note_fresh_days")
+ note_fresh_days = text2num(value)
+ if("note_stale_days")
+ note_stale_days = text2num(value)
if("soft_popcap")
soft_popcap = text2num(value)
if("hard_popcap")
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 78a402a2dc..7df65438f2 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -311,7 +311,7 @@
traitor_mob.mind.store_memory("Radio Frequency: [format_frequency(R.traitor_frequency)] ([R.name]).")
else if(uplink_loc == PDA)
- PDA.lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]"
+ PDA.lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
if(!silent) to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
traitor_mob.mind.store_memory("Uplink Passcode: [PDA.lock_code] ([PDA.name]).")
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index 24d5311af3..8b16b2b0d5 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -309,8 +309,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
owner_AI.nuking = TRUE
owner_AI.doomsday_device = DOOM
owner_AI.doomsday_device.start()
- for(var/pinpointer in GLOB.pinpointer_list)
- var/obj/item/pinpointer/P = pinpointer
+ for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_MALF_AI) //Pinpointers start tracking the AI wherever it goes
qdel(src)
diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm.rej b/code/game/gamemodes/malfunction/Malf_Modules.dm.rej
new file mode 100644
index 0000000000..97dbe2bbdb
--- /dev/null
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm.rej
@@ -0,0 +1,11 @@
+diff a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm (rejected hunks)
+@@ -309,8 +309,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
+ owner_AI.nuking = TRUE
+ owner_AI.doomsday_device = DOOM
+ owner_AI.doomsday_device.start()
+- for(var/pinpointer in GLOB.pinpointer_list)
+- var/obj/item/weapon/pinpointer/P = pinpointer
++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
+ P.switch_mode_to(TRACK_MALF_AI) //Pinpointers start tracking the AI wherever it goes
+ qdel(src)
+
diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
index 58ca8bbea9..182b7e2756 100644
--- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
+++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm
@@ -12,6 +12,8 @@
var/list/abductee_minds
var/flash = " - || - "
var/obj/machinery/abductor/console/console
+ var/message_cooldown = 0
+ var/breakout_time = 0.75
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
@@ -40,25 +42,23 @@
/obj/machinery/abductor/experiment/relaymove(mob/user)
if(user.stat != CONSCIOUS)
return
- container_resist(user)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
/obj/machinery/abductor/experiment/container_resist(mob/living/user)
- var/breakout_time = 600
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
- to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about a minute.)")
- user.visible_message("You hear a metallic creaking from [src]!")
-
- if(do_after(user,(breakout_time), target = src))
+ user.visible_message("You see [user] kicking against the door of [src]!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a metallic creaking from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
return
-
- visible_message("[user] successfully broke out of [src]!")
- to_chat(user, "You successfully break out of [src]!")
-
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
open_machine()
-
/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
var/icon/photo = null
var/g = (H.gender == FEMALE) ? "f" : "m"
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 59650561a6..1b1bec68c1 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -325,7 +325,7 @@
gloves = /obj/item/clothing/gloves/combat
back = /obj/item/storage/backpack
ears = /obj/item/device/radio/headset/syndicate/alt
- l_pocket = /obj/item/pinpointer/syndicate
+ l_pocket = /obj/item/pinpointer/nuke/syndicate
id = /obj/item/card/id/syndicate
belt = /obj/item/gun/ballistic/automatic/pistol
backpack_contents = list(/obj/item/storage/box/syndie=1)
diff --git a/code/game/gamemodes/nuclear/nuclear.dm.rej b/code/game/gamemodes/nuclear/nuclear.dm.rej
new file mode 100644
index 0000000000..19648547c7
--- /dev/null
+++ b/code/game/gamemodes/nuclear/nuclear.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm (rejected hunks)
+@@ -325,7 +325,7 @@
+ gloves = /obj/item/clothing/gloves/combat
+ back = /obj/item/weapon/storage/backpack
+ ears = /obj/item/device/radio/headset/syndicate/alt
+- l_pocket = /obj/item/weapon/pinpointer/syndicate
++ l_pocket = /obj/item/weapon/pinpointer/nuke/syndicate
+ id = /obj/item/weapon/card/id/syndicate
+ belt = /obj/item/weapon/gun/ballistic/automatic/pistol
+ backpack_contents = list(/obj/item/weapon/storage/box/syndie=1)
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm
index ee611349f8..95fc735ec6 100644
--- a/code/game/gamemodes/nuclear/nuclearbomb.dm
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm
@@ -362,9 +362,9 @@
if(safety)
if(timing)
set_security_level(previous_level)
- for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(initial(S.mode))
- S.nuke_warning = FALSE
+ S.alert = FALSE
timing = FALSE
bomb_set = TRUE
detonation_timer = null
@@ -381,16 +381,16 @@
bomb_set = TRUE
set_security_level("delta")
detonation_timer = world.time + (timer_set * 10)
- for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(TRACK_INFILTRATOR)
countdown.start()
else
bomb_set = FALSE
detonation_timer = null
set_security_level(previous_level)
- for(var/obj/item/pinpointer/syndicate/S in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
S.switch_mode_to(initial(S.mode))
- S.nuke_warning = FALSE
+ S.alert = FALSE
countdown.stop()
update_icon()
diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm.rej b/code/game/gamemodes/nuclear/nuclearbomb.dm.rej
new file mode 100644
index 0000000000..6a35e91cde
--- /dev/null
+++ b/code/game/gamemodes/nuclear/nuclearbomb.dm.rej
@@ -0,0 +1,33 @@
+diff a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm (rejected hunks)
+@@ -362,9 +362,9 @@
+ if(safety)
+ if(timing)
+ set_security_level(previous_level)
+- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
+ S.switch_mode_to(initial(S.mode))
+- S.nuke_warning = FALSE
++ S.alert = FALSE
+ timing = FALSE
+ bomb_set = TRUE
+ detonation_timer = null
+@@ -381,16 +381,16 @@
+ bomb_set = TRUE
+ set_security_level("delta")
+ detonation_timer = world.time + (timer_set * 10)
+- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
+ S.switch_mode_to(TRACK_INFILTRATOR)
+ countdown.start()
+ else
+ bomb_set = FALSE
+ detonation_timer = null
+ set_security_level(previous_level)
+- for(var/obj/item/weapon/pinpointer/syndicate/S in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/syndicate/S in GLOB.pinpointer_list)
+ S.switch_mode_to(initial(S.mode))
+- S.nuke_warning = FALSE
++ S.alert = FALSE
+ countdown.stop()
+ update_icon()
+
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm
index 9f63309643..461ef78ef3 100644
--- a/code/game/gamemodes/nuclear/pinpointer.dm
+++ b/code/game/gamemodes/nuclear/pinpointer.dm
@@ -1,56 +1,7 @@
-//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
-/obj/item/pinpointer
- name = "pinpointer"
- desc = "A handheld tracking device that locks onto certain signals."
- icon = 'icons/obj/device.dmi'
- icon_state = "pinoff"
- flags_1 = CONDUCT_1
- slot_flags = SLOT_BELT
- w_class = WEIGHT_CLASS_SMALL
- item_state = "electronic"
- lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL = 500, MAT_GLASS = 250)
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
- var/active = FALSE
- var/atom/movable/target = null //The thing we're searching for
- var/atom/movable/constant_target = null //The thing we're always focused on, if we're in the right mode
- var/target_x = 0 //The target coordinates if we're tracking those
- var/target_y = 0
- var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
- var/nuke_warning = FALSE // If we've set off a miniature alarm about an armed nuke
- var/mode = TRACK_NUKE_DISK //What are we looking for?
+/obj/item/pinpointer/nuke
+ var/mode = TRACK_NUKE_DISK
-/obj/item/pinpointer/New()
- ..()
- GLOB.pinpointer_list += src
-
-/obj/item/pinpointer/Destroy()
- STOP_PROCESSING(SSfastprocess, src)
- GLOB.pinpointer_list -= src
- return ..()
-
-/obj/item/pinpointer/attack_self(mob/living/user)
- active = !active
- user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
- playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
- icon_state = "pin[active ? "onnull" : "off"]"
- if(active)
- START_PROCESSING(SSfastprocess, src)
- else
- target = null //Restarting the pinpointer forces a target reset
- STOP_PROCESSING(SSfastprocess, src)
-
-/obj/item/pinpointer/attackby(obj/item/I, mob/living/user, params)
- if(mode != TRACK_ATOM)
- return ..()
- user.visible_message("[user] tunes [src] to [I].", "You fine-tune [src]'s tracking to track [I].")
- playsound(src, 'sound/machines/click.ogg', 50, 1)
- constant_target = I
-
-/obj/item/pinpointer/examine(mob/user)
+/obj/item/pinpointer/nuke/examine(mob/user)
..()
var/msg = "Its tracking indicator reads "
switch(mode)
@@ -60,12 +11,6 @@
msg += "\"01000001 01001001\"."
if(TRACK_INFILTRATOR)
msg += "\"vasvygengbefuvc\"."
- if(TRACK_OPERATIVES)
- msg += "\"[target ? "Operative [target]" : "friends"]\"."
- if(TRACK_ATOM)
- msg += "\"[initial(constant_target.name)]\"."
- if(TRACK_COORDINATES)
- msg += "\"([target_x], [target_y])\"."
else
msg = "Its tracking indicator is blank."
to_chat(user, msg)
@@ -73,22 +18,20 @@
if(bomb.timing)
to_chat(user, "Extreme danger. Arming signal detected. Time remaining: [bomb.get_time_left()]")
-/obj/item/pinpointer/process()
- if(!active)
- STOP_PROCESSING(SSfastprocess, src)
- return
- scan_for_target()
- point_to_target()
- my_god_jc_a_bomb()
- addtimer(CALLBACK(src, .proc/refresh_target), 50, TIMER_UNIQUE)
+/obj/item/pinpointer/nuke/process()
+ ..()
+ if(active) // If shit's going down
+ for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list)
+ if(bomb.timing)
+ if(!alert)
+ alert = TRUE
+ playsound(src, 'sound/items/nuke_toy_lowpower.ogg', 50, 0)
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
-/obj/item/pinpointer/proc/scan_for_target() //Looks for whatever it's tracking
- if(target)
- if(isliving(target))
- var/mob/living/L = target
- if(L.stat == DEAD)
- target = null
- return
+/obj/item/pinpointer/nuke/scan_for_target()
+ target = null
switch(mode)
if(TRACK_NUKE_DISK)
var/obj/item/disk/nuclear/N = locate() in GLOB.poi_list
@@ -104,76 +47,36 @@
target = A
if(TRACK_INFILTRATOR)
target = SSshuttle.getShuttle("syndicate")
- if(TRACK_OPERATIVES)
- var/list/possible_targets = list()
- var/turf/here = get_turf(src)
- for(var/V in SSticker.mode.syndicates)
- var/datum/mind/M = V
- if(M.current && M.current.stat != DEAD)
- possible_targets |= M.current
- var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
- if(closest_operative)
- target = closest_operative
- if(TRACK_ATOM)
- if(constant_target)
- target = constant_target
- if(TRACK_COORDINATES)
- var/turf/T = get_turf(src)
- target = locate(target_x, target_y, T.z)
+ ..()
-/obj/item/pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
- if(!active)
- return
- if(!target || (mode == TRACK_ATOM && !constant_target))
- icon_state = "pinon[nuke_warning ? "alert" : ""]null"
- return
- var/turf/here = get_turf(src)
- var/turf/there = get_turf(target)
- if(here.z != there.z)
- icon_state = "pinon[nuke_warning ? "alert" : ""]null"
- return
- if(get_dist_euclidian(here,there)<=minimum_range)
- icon_state = "pinon[nuke_warning ? "alert" : ""]direct"
- else
- setDir(get_dir(here, there))
- switch(get_dist(here, there))
- if(1 to 8)
- icon_state = "pinon[nuke_warning ? "alert" : "close"]"
- if(9 to 16)
- icon_state = "pinon[nuke_warning ? "alert" : "medium"]"
- if(16 to INFINITY)
- icon_state = "pinon[nuke_warning ? "alert" : "far"]"
-
-/obj/item/pinpointer/proc/my_god_jc_a_bomb() //If we should get the hell back to the ship
- for(var/obj/machinery/nuclearbomb/bomb in GLOB.nuke_list)
- if(bomb.timing)
- if(!nuke_warning)
- nuke_warning = TRUE
- playsound(src, 'sound/items/nuke_toy_lowpower.ogg', 50, 0)
- if(isliving(loc))
- var/mob/living/L = loc
- to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
-
-/obj/item/pinpointer/proc/switch_mode_to(new_mode) //If we shouldn't be tracking what we are
+/obj/item/pinpointer/nuke/proc/switch_mode_to(new_mode)
if(isliving(loc))
var/mob/living/L = loc
to_chat(L, "Your [name] beeps as it reconfigures its tracking algorithms.")
playsound(L, 'sound/machines/triple_beep.ogg', 50, 1)
mode = new_mode
- target = null //Switch modes so we can find the new target
+ scan_for_target()
-/obj/item/pinpointer/proc/refresh_target() //Periodically removes the target to allow the pinpointer to update (i.e. malf AI shunts, an operative dies)
- target = null
-
-/obj/item/pinpointer/syndicate //Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
+/obj/item/pinpointer/nuke/syndicate // Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
name = "syndicate pinpointer"
desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
+ icon_state = "pinpointer_syndicate"
-/obj/item/pinpointer/syndicate/cyborg //Cyborg pinpointers just look for a random operative.
+/obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative.
name = "cyborg syndicate pinpointer"
desc = "An integrated tracking device, jury-rigged to search for living Syndicate operatives."
- mode = TRACK_OPERATIVES
flags_1 = NODROP_1
-
+/obj/item/pinpointer/syndicate_cyborg/scan_for_target()
+ target = null
+ var/list/possible_targets = list()
+ var/turf/here = get_turf(src)
+ for(var/V in SSticker.mode.syndicates)
+ var/datum/mind/M = V
+ if(M.current && M.current.stat != DEAD)
+ possible_targets |= M.current
+ var/mob/living/closest_operative = get_closest_atom(/mob/living/carbon/human, possible_targets, here)
+ if(closest_operative)
+ target = closest_operative
+ ..()
diff --git a/code/game/gamemodes/nuclear/pinpointer.dm.rej b/code/game/gamemodes/nuclear/pinpointer.dm.rej
new file mode 100644
index 0000000000..79d652af9b
--- /dev/null
+++ b/code/game/gamemodes/nuclear/pinpointer.dm.rej
@@ -0,0 +1,21 @@
+diff a/code/game/gamemodes/nuclear/pinpointer.dm b/code/game/gamemodes/nuclear/pinpointer.dm (rejected hunks)
+@@ -30,7 +30,6 @@
+ var/mob/living/L = loc
+ to_chat(L, "Your [name] vibrates and lets out a tinny alarm. Uh oh.")
+
+-
+ /obj/item/pinpointer/nuke/scan_for_target()
+ target = null
+ switch(mode)
+@@ -58,10 +57,10 @@
+ mode = new_mode
+ scan_for_target()
+
+-
+ /obj/item/pinpointer/nuke/syndicate // Syndicate pinpointers automatically point towards the infiltrator once the nuke is active.
+ name = "syndicate pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals. It's configured to switch tracking modes once it detects the activation signal of a nuclear device."
++ icon_state = "pinpointer_syndicate"
+
+ /obj/item/pinpointer/syndicate_cyborg // Cyborg pinpointers just look for a random operative.
+ name = "cyborg syndicate pinpointer"
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index ba0f727203..c0aee8bb76 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -186,7 +186,7 @@
return ..()
//Old ninja objectives.
-/datum/objective_item/special/pinpointer
+/datum/objective_item/special/pinpointer/nuke
name = "the captain's pinpointer."
targetitem = /obj/item/pinpointer
difficulty = 10
diff --git a/code/game/gamemodes/objective_items.dm.rej b/code/game/gamemodes/objective_items.dm.rej
new file mode 100644
index 0000000000..3770d7eea9
--- /dev/null
+++ b/code/game/gamemodes/objective_items.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm (rejected hunks)
+@@ -158,7 +158,7 @@
+ difficulty = 10
+
+ //Old ninja objectives.
+-/datum/objective_item/special/pinpointer
++/datum/objective_item/special/pinpointer/nuke
+ name = "the captain's pinpointer."
+ targetitem = /obj/item/pinpointer
+ difficulty = 10
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 7ea954a671..2276b5154b 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -392,6 +392,9 @@
QDEL_IN(mob_occupant, 40)
/obj/machinery/clonepod/relaymove(mob/user)
+ container_resist()
+
+/obj/machinery/clonepod/container_resist(mob/living/user)
if(user.stat == CONSCIOUS)
go_out()
diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index 65a6088721..4085b4edb4 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -14,6 +14,8 @@
var/damage_coeff
var/scan_level
var/precision_coeff
+ var/message_cooldown
+ var/breakout_time = 2
/obj/machinery/dna_scannernew/RefreshParts()
scan_level = 0
@@ -65,23 +67,20 @@
open_machine()
/obj/machinery/dna_scannernew/container_resist(mob/living/user)
- var/breakout_time = 2
- if(state_open || !locked) //Open and unlocked, no need to escape
- state_open = TRUE
+ if(!locked)
+ open_machine()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
- to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about [breakout_time] minutes.)")
- user.visible_message("You hear a metallic creaking from [src]!")
-
+ user.visible_message("You see [user] kicking against the door of [src]!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a metallic creaking from [src].")
if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
return
-
locked = FALSE
- visible_message("[user] successfully broke out of [src]!")
- to_chat(user, "You successfully break out of [src]!")
-
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
open_machine()
/obj/machinery/dna_scannernew/proc/locate_computer(type_)
@@ -122,10 +121,11 @@
/obj/machinery/dna_scannernew/relaymove(mob/user as mob)
if(user.stat || locked)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
return
-
open_machine()
- return
/obj/machinery/dna_scannernew/attackby(obj/item/I, mob/user, params)
diff --git a/code/game/machinery/gulag_teleporter.dm b/code/game/machinery/gulag_teleporter.dm
index b37c5a10a7..d77e91af90 100644
--- a/code/game/machinery/gulag_teleporter.dm
+++ b/code/game/machinery/gulag_teleporter.dm
@@ -19,6 +19,8 @@ The console is located at computer/gulag_teleporter.dm
active_power_usage = 5000
circuit = /obj/item/circuitboard/machine/gulag_teleporter
var/locked = FALSE
+ var/message_cooldown
+ var/breakout_time = 1
var/jumpsuit_type = /obj/item/clothing/under/rank/prisoner
var/shoes_type = /obj/item/clothing/shoes/sneakers/orange
var/obj/machinery/gulag_item_reclaimer/linked_reclaimer
@@ -46,7 +48,7 @@ The console is located at computer/gulag_teleporter.dm
/obj/machinery/gulag_teleporter/interact(mob/user)
if(locked)
- to_chat(user, "[src] is locked.")
+ to_chat(user, "[src] is locked!")
return
toggle_open()
@@ -89,28 +91,27 @@ The console is located at computer/gulag_teleporter.dm
if(user.stat != CONSCIOUS)
return
if(locked)
- to_chat(user, "[src] is locked!")
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
return
open_machine()
/obj/machinery/gulag_teleporter/container_resist(mob/living/user)
- var/breakout_time = 600
if(!locked)
open_machine()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
- to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about a minute.)")
- user.visible_message("You hear a metallic creaking from [src]!")
-
- if(do_after(user,(breakout_time), target = src))
+ user.visible_message("You see [user] kicking against the door of [src]!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a metallic creaking from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open || !locked)
return
-
locked = FALSE
- visible_message("[user] successfully broke out of [src]!")
- to_chat(user, "You successfully break out of [src]!")
-
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
open_machine()
/obj/machinery/gulag_teleporter/proc/locate_reclaimer()
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index cd2a5bd3b5..a78fa50a6a 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -1,379 +1,406 @@
-// SUIT STORAGE UNIT /////////////////
-/obj/machinery/suit_storage_unit
- name = "suit storage unit"
- desc = "An industrial unit made to hold space suits. It comes with a built-in UV cauterization mechanism. A small warning label advises that organic matter should not be placed into the unit."
- icon = 'icons/obj/suitstorage.dmi'
- icon_state = "close"
+// SUIT STORAGE UNIT /////////////////
+/obj/machinery/suit_storage_unit
+ name = "suit storage unit"
+ desc = "An industrial unit made to hold space suits. It comes with a built-in UV cauterization mechanism. A small warning label advises that organic matter should not be placed into the unit."
+ icon = 'icons/obj/suitstorage.dmi'
+ icon_state = "close"
anchored = TRUE
density = TRUE
- max_integrity = 250
-
- var/obj/item/clothing/suit/space/suit = null
- var/obj/item/clothing/head/helmet/space/helmet = null
- var/obj/item/clothing/mask/mask = null
- var/obj/item/storage = null
-
- var/suit_type = null
- var/helmet_type = null
- var/mask_type = null
- var/storage_type = null
-
- state_open = FALSE
- var/locked = FALSE
- panel_open = FALSE
- var/safeties = TRUE
-
- var/uv = FALSE
- var/uv_super = FALSE
- var/uv_cycles = 6
-
-/obj/machinery/suit_storage_unit/standard_unit
- suit_type = /obj/item/clothing/suit/space/eva
- helmet_type = /obj/item/clothing/head/helmet/space/eva
- mask_type = /obj/item/clothing/mask/breath
-
-/obj/machinery/suit_storage_unit/captain
- suit_type = /obj/item/clothing/suit/space/hardsuit/captain
- mask_type = /obj/item/clothing/mask/gas/sechailer
- storage_type = /obj/item/tank/jetpack/oxygen/captain
-
-/obj/machinery/suit_storage_unit/engine
- suit_type = /obj/item/clothing/suit/space/hardsuit/engine
- mask_type = /obj/item/clothing/mask/breath
-
-/obj/machinery/suit_storage_unit/ce
- suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite
- mask_type = /obj/item/clothing/mask/breath
- storage_type= /obj/item/clothing/shoes/magboots/advance
-
-/obj/machinery/suit_storage_unit/security
- suit_type = /obj/item/clothing/suit/space/hardsuit/security
- mask_type = /obj/item/clothing/mask/gas/sechailer
-
-/obj/machinery/suit_storage_unit/hos
- suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos
- mask_type = /obj/item/clothing/mask/gas/sechailer
- storage_type = /obj/item/tank/internals/oxygen
-
-/obj/machinery/suit_storage_unit/atmos
- suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos
- mask_type = /obj/item/clothing/mask/gas
- storage_type = /obj/item/watertank/atmos
-
-/obj/machinery/suit_storage_unit/mining
- suit_type = /obj/item/clothing/suit/hooded/explorer
- mask_type = /obj/item/clothing/mask/gas/explorer
-
-/obj/machinery/suit_storage_unit/mining/eva
- suit_type = /obj/item/clothing/suit/space/hardsuit/mining
- mask_type = /obj/item/clothing/mask/breath
-
-/obj/machinery/suit_storage_unit/cmo
- suit_type = /obj/item/clothing/suit/space/hardsuit/medical
- mask_type = /obj/item/clothing/mask/breath
-
-/obj/machinery/suit_storage_unit/rd
- suit_type = /obj/item/clothing/suit/space/hardsuit/rd
- mask_type = /obj/item/clothing/mask/breath
-
-/obj/machinery/suit_storage_unit/syndicate
- suit_type = /obj/item/clothing/suit/space/hardsuit/syndi
- mask_type = /obj/item/clothing/mask/gas/syndicate
- storage_type = /obj/item/tank/jetpack/oxygen/harness
-
-/obj/machinery/suit_storage_unit/ert/command
- suit_type = /obj/item/clothing/suit/space/hardsuit/ert
- mask_type = /obj/item/clothing/mask/breath
- storage_type = /obj/item/tank/internals/emergency_oxygen/double
-
-/obj/machinery/suit_storage_unit/ert/security
- suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec
- mask_type = /obj/item/clothing/mask/breath
- storage_type = /obj/item/tank/internals/emergency_oxygen/double
-
-/obj/machinery/suit_storage_unit/ert/engineer
- suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi
- mask_type = /obj/item/clothing/mask/breath
- storage_type = /obj/item/tank/internals/emergency_oxygen/double
-
-/obj/machinery/suit_storage_unit/ert/medical
- suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med
- mask_type = /obj/item/clothing/mask/breath
- storage_type = /obj/item/tank/internals/emergency_oxygen/double
-
+ max_integrity = 250
+
+ var/obj/item/clothing/suit/space/suit = null
+ var/obj/item/clothing/head/helmet/space/helmet = null
+ var/obj/item/clothing/mask/mask = null
+ var/obj/item/storage = null
+
+ var/suit_type = null
+ var/helmet_type = null
+ var/mask_type = null
+ var/storage_type = null
+
+ state_open = FALSE
+ var/locked = FALSE
+ panel_open = FALSE
+ var/safeties = TRUE
+
+ var/uv = FALSE
+ var/uv_super = FALSE
+ var/uv_cycles = 6
+ var/message_cooldown
+ var/breakout_time = 0.5
+
+/obj/machinery/suit_storage_unit/standard_unit
+ suit_type = /obj/item/clothing/suit/space/eva
+ helmet_type = /obj/item/clothing/head/helmet/space/eva
+ mask_type = /obj/item/clothing/mask/breath
+
+/obj/machinery/suit_storage_unit/captain
+ suit_type = /obj/item/clothing/suit/space/hardsuit/captain
+ mask_type = /obj/item/clothing/mask/gas/sechailer
+ storage_type = /obj/item/tank/jetpack/oxygen/captain
+
+/obj/machinery/suit_storage_unit/engine
+ suit_type = /obj/item/clothing/suit/space/hardsuit/engine
+ mask_type = /obj/item/clothing/mask/breath
+
+/obj/machinery/suit_storage_unit/ce
+ suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite
+ mask_type = /obj/item/clothing/mask/breath
+ storage_type= /obj/item/clothing/shoes/magboots/advance
+
+/obj/machinery/suit_storage_unit/security
+ suit_type = /obj/item/clothing/suit/space/hardsuit/security
+ mask_type = /obj/item/clothing/mask/gas/sechailer
+
+/obj/machinery/suit_storage_unit/hos
+ suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos
+ mask_type = /obj/item/clothing/mask/gas/sechailer
+ storage_type = /obj/item/tank/internals/oxygen
+
+/obj/machinery/suit_storage_unit/atmos
+ suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos
+ mask_type = /obj/item/clothing/mask/gas
+ storage_type = /obj/item/watertank/atmos
+
+/obj/machinery/suit_storage_unit/mining
+ suit_type = /obj/item/clothing/suit/hooded/explorer
+ mask_type = /obj/item/clothing/mask/gas/explorer
+
+/obj/machinery/suit_storage_unit/mining/eva
+ suit_type = /obj/item/clothing/suit/space/hardsuit/mining
+ mask_type = /obj/item/clothing/mask/breath
+
+/obj/machinery/suit_storage_unit/cmo
+ suit_type = /obj/item/clothing/suit/space/hardsuit/medical
+ mask_type = /obj/item/clothing/mask/breath
+
+/obj/machinery/suit_storage_unit/rd
+ suit_type = /obj/item/clothing/suit/space/hardsuit/rd
+ mask_type = /obj/item/clothing/mask/breath
+
+/obj/machinery/suit_storage_unit/syndicate
+ suit_type = /obj/item/clothing/suit/space/hardsuit/syndi
+ mask_type = /obj/item/clothing/mask/gas/syndicate
+ storage_type = /obj/item/tank/jetpack/oxygen/harness
+
+/obj/machinery/suit_storage_unit/ert/command
+ suit_type = /obj/item/clothing/suit/space/hardsuit/ert
+ mask_type = /obj/item/clothing/mask/breath
+ storage_type = /obj/item/tank/internals/emergency_oxygen/double
+
+/obj/machinery/suit_storage_unit/ert/security
+ suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec
+ mask_type = /obj/item/clothing/mask/breath
+ storage_type = /obj/item/tank/internals/emergency_oxygen/double
+
+/obj/machinery/suit_storage_unit/ert/engineer
+ suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi
+ mask_type = /obj/item/clothing/mask/breath
+ storage_type = /obj/item/tank/internals/emergency_oxygen/double
+
+/obj/machinery/suit_storage_unit/ert/medical
+ suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med
+ mask_type = /obj/item/clothing/mask/breath
+ storage_type = /obj/item/tank/internals/emergency_oxygen/double
+
/obj/machinery/suit_storage_unit/Initialize()
. = ..()
- wires = new /datum/wires/suit_storage_unit(src)
- if(suit_type)
- suit = new suit_type(src)
- if(helmet_type)
- helmet = new helmet_type(src)
- if(mask_type)
- mask = new mask_type(src)
- if(storage_type)
- storage = new storage_type(src)
- update_icon()
-
-/obj/machinery/suit_storage_unit/Destroy()
+ wires = new /datum/wires/suit_storage_unit(src)
+ if(suit_type)
+ suit = new suit_type(src)
+ if(helmet_type)
+ helmet = new helmet_type(src)
+ if(mask_type)
+ mask = new mask_type(src)
+ if(storage_type)
+ storage = new storage_type(src)
+ update_icon()
+
+/obj/machinery/suit_storage_unit/Destroy()
QDEL_NULL(suit)
QDEL_NULL(helmet)
QDEL_NULL(mask)
QDEL_NULL(storage)
- return ..()
-
-/obj/machinery/suit_storage_unit/update_icon()
- cut_overlays()
-
- if(uv)
- if(uv_super)
- add_overlay("super")
- else if(occupant)
- add_overlay("uvhuman")
- else
- add_overlay("uv")
- else if(state_open)
- if(stat & BROKEN)
- add_overlay("broken")
- else
- add_overlay("open")
- if(suit)
- add_overlay("suit")
- if(helmet)
- add_overlay("helm")
- if(storage)
- add_overlay("storage")
- else if(occupant)
- add_overlay("human")
-
-/obj/machinery/suit_storage_unit/power_change()
- ..()
- if(!is_operational() && state_open)
- open_machine()
- dump_contents()
- update_icon()
-
-/obj/machinery/suit_storage_unit/proc/dump_contents()
- dropContents()
- helmet = null
- suit = null
- mask = null
- storage = null
- occupant = null
-
-/obj/machinery/suit_storage_unit/deconstruct(disassembled = TRUE)
+ return ..()
+
+/obj/machinery/suit_storage_unit/update_icon()
+ cut_overlays()
+
+ if(uv)
+ if(uv_super)
+ add_overlay("super")
+ else if(occupant)
+ add_overlay("uvhuman")
+ else
+ add_overlay("uv")
+ else if(state_open)
+ if(stat & BROKEN)
+ add_overlay("broken")
+ else
+ add_overlay("open")
+ if(suit)
+ add_overlay("suit")
+ if(helmet)
+ add_overlay("helm")
+ if(storage)
+ add_overlay("storage")
+ else if(occupant)
+ add_overlay("human")
+
+/obj/machinery/suit_storage_unit/power_change()
+ ..()
+ if(!is_operational() && state_open)
+ open_machine()
+ dump_contents()
+ update_icon()
+
+/obj/machinery/suit_storage_unit/proc/dump_contents()
+ dropContents()
+ helmet = null
+ suit = null
+ mask = null
+ storage = null
+ occupant = null
+
+/obj/machinery/suit_storage_unit/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
- open_machine()
- dump_contents()
- new /obj/item/stack/sheet/metal (loc, 2)
- qdel(src)
-
-/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user)
- if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A))
- return
- var/mob/living/target = A
- if(!state_open)
- to_chat(user, "The unit's doors are shut!")
- return
- if(!is_operational())
- to_chat(user, "The unit is not operational!")
- return
- if(occupant || helmet || suit || storage)
- to_chat(user, "It's too cluttered inside to fit in!")
- return
-
- if(target == user)
- user.visible_message("[user] starts squeezing into [src]!", "You start working your way into [src]...")
- else
- target.visible_message("[user] starts shoving [target] into [src]!", "[user] starts shoving you into [src]!")
-
- if(do_mob(user, target, 30))
- if(occupant || helmet || suit || storage)
- return
- if(target == user)
- user.visible_message("[user] slips into [src] and closes the door behind them!", "You slip into [src]'s cramped space and shut its door.")
- else
- target.visible_message("[user] pushes [target] into [src] and shuts its door!", "[user] shoves you into [src] and shuts the door!")
- close_machine(target)
- add_fingerprint(user)
-
-/obj/machinery/suit_storage_unit/proc/cook()
- if(uv_cycles)
- uv_cycles--
- uv = TRUE
- locked = TRUE
- update_icon()
- if(occupant)
- var/mob/living/mob_occupant = occupant
- if(uv_super)
- mob_occupant.adjustFireLoss(rand(20, 36))
- else
- mob_occupant.adjustFireLoss(rand(10, 16))
- mob_occupant.emote("scream")
- addtimer(CALLBACK(src, .proc/cook), 50)
- else
- uv_cycles = initial(uv_cycles)
- uv = FALSE
- locked = FALSE
- if(uv_super)
- visible_message("[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.")
- playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, 1)
- helmet = null
- qdel(helmet)
- suit = null
- qdel(suit) // Delete everything but the occupant.
- mask = null
- qdel(mask)
- storage = null
- qdel(storage)
- // The wires get damaged too.
- wires.cut_all()
- else
- if(!occupant)
- visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.")
- else
- visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.")
- playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
- for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
- I.clean_blood()
- I.fingerprints = list()
- open_machine(FALSE)
- if(occupant)
- dump_contents()
-
-/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
- if(!prob(prb))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(5, 1, src)
- s.start()
- if(electrocute_mob(user, src, src, 1, TRUE))
- return 1
-
-/obj/machinery/suit_storage_unit/relaymove(mob/user)
- container_resist(user)
-
-/obj/machinery/suit_storage_unit/container_resist(mob/living/user)
- add_fingerprint(user)
- if(locked)
- visible_message("You see [user] kicking against the doors of [src]!", "You start kicking against the doors...")
- addtimer(CALLBACK(src, .proc/resist_open, user), 300)
- else
- open_machine()
- dump_contents()
-
-/obj/machinery/suit_storage_unit/proc/resist_open(mob/user)
- if(!state_open && occupant && (user in src) && user.stat == 0) // Check they're still here.
- visible_message("You see [user] bursts out of [src]!", "You escape the cramped confines of [src]!")
- open_machine()
-
-/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params)
- if(state_open && is_operational())
- if(istype(I, /obj/item/clothing/suit/space))
- if(suit)
- to_chat(user, "The unit already contains a suit!.")
- return
- if(!user.drop_item())
- return
- suit = I
- else if(istype(I, /obj/item/clothing/head/helmet))
- if(helmet)
- to_chat(user, "The unit already contains a helmet!")
- return
- if(!user.drop_item())
- return
- helmet = I
- else if(istype(I, /obj/item/clothing/mask))
- if(mask)
- to_chat(user, "The unit already contains a mask!")
- return
- if(!user.drop_item())
- return
- mask = I
- else
- if(storage)
- to_chat(user, "The auxiliary storage compartment is full!")
- return
- if(!user.drop_item())
- return
- storage = I
-
- I.loc = src
- visible_message("[user] inserts [I] into [src]", "You load [I] into [src].")
- update_icon()
- return
-
- if(panel_open && is_wire_tool(I))
- wires.interact(user)
- if(!state_open)
- if(default_deconstruction_screwdriver(user, "panel", "close", I))
- return
- if(default_pry_open(I))
- dump_contents()
- return
-
- return ..()
-
+ open_machine()
+ dump_contents()
+ new /obj/item/stack/sheet/metal (loc, 2)
+ qdel(src)
+
+/obj/machinery/suit_storage_unit/MouseDrop_T(atom/A, mob/user)
+ if(user.stat || user.lying || !Adjacent(user) || !Adjacent(A) || !isliving(A))
+ return
+ var/mob/living/target = A
+ if(!state_open)
+ to_chat(user, "The unit's doors are shut!")
+ return
+ if(!is_operational())
+ to_chat(user, "The unit is not operational!")
+ return
+ if(occupant || helmet || suit || storage)
+ to_chat(user, "It's too cluttered inside to fit in!")
+ return
+
+ if(target == user)
+ user.visible_message("[user] starts squeezing into [src]!", "You start working your way into [src]...")
+ else
+ target.visible_message("[user] starts shoving [target] into [src]!", "[user] starts shoving you into [src]!")
+
+ if(do_mob(user, target, 30))
+ if(occupant || helmet || suit || storage)
+ return
+ if(target == user)
+ user.visible_message("[user] slips into [src] and closes the door behind them!", "You slip into [src]'s cramped space and shut its door.")
+ else
+ target.visible_message("[user] pushes [target] into [src] and shuts its door!", "[user] shoves you into [src] and shuts the door!")
+ close_machine(target)
+ add_fingerprint(user)
+
+/obj/machinery/suit_storage_unit/proc/cook()
+ if(uv_cycles)
+ uv_cycles--
+ uv = TRUE
+ locked = TRUE
+ update_icon()
+ if(occupant)
+ var/mob/living/mob_occupant = occupant
+ if(uv_super)
+ mob_occupant.adjustFireLoss(rand(20, 36))
+ else
+ mob_occupant.adjustFireLoss(rand(10, 16))
+ mob_occupant.emote("scream")
+ addtimer(CALLBACK(src, .proc/cook), 50)
+ else
+ uv_cycles = initial(uv_cycles)
+ uv = FALSE
+ locked = FALSE
+ if(uv_super)
+ visible_message("[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.")
+ playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, 1)
+ helmet = null
+ qdel(helmet)
+ suit = null
+ qdel(suit) // Delete everything but the occupant.
+ mask = null
+ qdel(mask)
+ storage = null
+ qdel(storage)
+ // The wires get damaged too.
+ wires.cut_all()
+ else
+ if(!occupant)
+ visible_message("[src]'s door slides open. The glowing yellow lights dim to a gentle green.")
+ else
+ visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.")
+ playsound(src, 'sound/machines/airlockclose.ogg', 25, 1)
+ for(var/obj/item/I in src) //Scorches away blood and forensic evidence, although the SSU itself is unaffected
+ I.clean_blood()
+ I.fingerprints = list()
+ open_machine(FALSE)
+ if(occupant)
+ dump_contents()
+
+/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
+ if(!prob(prb))
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(5, 1, src)
+ s.start()
+ if(electrocute_mob(user, src, src, 1, TRUE))
+ return 1
+
+/obj/machinery/suit_storage_unit/relaymove(mob/user)
+ if(locked)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
+ return
+ open_machine()
+ dump_contents()
+
+/obj/machinery/suit_storage_unit/container_resist(mob/living/user)
+ if(!locked)
+ open_machine()
+ dump_contents()
+ return
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ user.visible_message("You see [user] kicking against the doors of [src]!", \
+ "You start kicking against the doors... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a thump from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(!user || user.stat != CONSCIOUS || user.loc != src )
+ return
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
+ open_machine()
+ dump_contents()
+
+ add_fingerprint(user)
+ if(locked)
+ visible_message("You see [user] kicking against the doors of [src]!", \
+ "You start kicking against the doors...")
+ addtimer(CALLBACK(src, .proc/resist_open, user), 300)
+ else
+ open_machine()
+ dump_contents()
+
+/obj/machinery/suit_storage_unit/proc/resist_open(mob/user)
+ if(!state_open && occupant && (user in src) && user.stat == 0) // Check they're still here.
+ visible_message("You see [user] bursts out of [src]!", \
+ "You escape the cramped confines of [src]!")
+ open_machine()
+
+/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params)
+ if(state_open && is_operational())
+ if(istype(I, /obj/item/clothing/suit/space))
+ if(suit)
+ to_chat(user, "The unit already contains a suit!.")
+ return
+ if(!user.drop_item())
+ return
+ suit = I
+ else if(istype(I, /obj/item/clothing/head/helmet))
+ if(helmet)
+ to_chat(user, "The unit already contains a helmet!")
+ return
+ if(!user.drop_item())
+ return
+ helmet = I
+ else if(istype(I, /obj/item/clothing/mask))
+ if(mask)
+ to_chat(user, "The unit already contains a mask!")
+ return
+ if(!user.drop_item())
+ return
+ mask = I
+ else
+ if(storage)
+ to_chat(user, "The auxiliary storage compartment is full!")
+ return
+ if(!user.drop_item())
+ return
+ storage = I
+
+ I.loc = src
+ visible_message("[user] inserts [I] into [src]", "You load [I] into [src].")
+ update_icon()
+ return
+
+ if(panel_open && is_wire_tool(I))
+ wires.interact(user)
+ if(!state_open)
+ if(default_deconstruction_screwdriver(user, "panel", "close", I))
+ return
+ if(default_pry_open(I))
+ dump_contents()
+ return
+
+ return ..()
+
/obj/machinery/suit_storage_unit/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
- datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "suit_storage_unit", name, 400, 305, master_ui, state)
- ui.open()
-
-/obj/machinery/suit_storage_unit/ui_data()
- var/list/data = list()
- data["locked"] = locked
- data["open"] = state_open
- data["safeties"] = safeties
- data["uv_active"] = uv
- data["uv_super"] = uv_super
- if(helmet)
- data["helmet"] = helmet.name
- if(suit)
- data["suit"] = suit.name
- if(mask)
- data["mask"] = mask.name
- if(storage)
- data["storage"] = storage.name
- if(occupant)
- data["occupied"] = 1
- return data
-
-/obj/machinery/suit_storage_unit/ui_act(action, params)
- if(..() || uv)
- return
- switch(action)
- if("door")
- if(state_open)
- close_machine()
- else
- open_machine(0)
- if(occupant)
- dump_contents() // Dump out contents if someone is in there.
- . = TRUE
- if("lock")
- locked = !locked
- . = TRUE
- if("uv")
- if(occupant && safeties)
- return
- else if(!helmet && !mask && !suit && !storage && !occupant)
- return
- else
- if(occupant)
- var/mob/living/mob_occupant = occupant
- to_chat(mob_occupant, "[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!")
- cook()
- . = TRUE
- if("dispense")
- if(!state_open)
- return
-
- var/static/list/valid_items = list("helmet", "suit", "mask", "storage")
- var/item_name = params["item"]
- if(item_name in valid_items)
- var/obj/item/I = vars[item_name]
- vars[item_name] = null
- if(I)
- I.forceMove(loc)
- . = TRUE
- update_icon()
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "suit_storage_unit", name, 400, 305, master_ui, state)
+ ui.open()
+
+/obj/machinery/suit_storage_unit/ui_data()
+ var/list/data = list()
+ data["locked"] = locked
+ data["open"] = state_open
+ data["safeties"] = safeties
+ data["uv_active"] = uv
+ data["uv_super"] = uv_super
+ if(helmet)
+ data["helmet"] = helmet.name
+ if(suit)
+ data["suit"] = suit.name
+ if(mask)
+ data["mask"] = mask.name
+ if(storage)
+ data["storage"] = storage.name
+ if(occupant)
+ data["occupied"] = 1
+ return data
+
+/obj/machinery/suit_storage_unit/ui_act(action, params)
+ if(..() || uv)
+ return
+ switch(action)
+ if("door")
+ if(state_open)
+ close_machine()
+ else
+ open_machine(0)
+ if(occupant)
+ dump_contents() // Dump out contents if someone is in there.
+ . = TRUE
+ if("lock")
+ locked = !locked
+ . = TRUE
+ if("uv")
+ if(occupant && safeties)
+ return
+ else if(!helmet && !mask && !suit && !storage && !occupant)
+ return
+ else
+ if(occupant)
+ var/mob/living/mob_occupant = occupant
+ to_chat(mob_occupant, "[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!")
+ cook()
+ . = TRUE
+ if("dispense")
+ if(!state_open)
+ return
+
+ var/static/list/valid_items = list("helmet", "suit", "mask", "storage")
+ var/item_name = params["item"]
+ if(item_name in valid_items)
+ var/obj/item/I = vars[item_name]
+ vars[item_name] = null
+ if(I)
+ I.forceMove(loc)
+ . = TRUE
+ update_icon()
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 427bc95253..bf879f84da 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -869,7 +869,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
products = list(/obj/item/reagent_containers/syringe = 12, /obj/item/reagent_containers/dropper = 3, /obj/item/stack/medical/gauze = 8, /obj/item/reagent_containers/pill/patch/styptic = 5, /obj/item/reagent_containers/pill/insulin = 10,
/obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/glass/bottle/charcoal = 4, /obj/item/reagent_containers/spray/medical/sterilizer = 1,
/obj/item/reagent_containers/glass/bottle/epinephrine = 4, /obj/item/reagent_containers/glass/bottle/morphine = 4, /obj/item/reagent_containers/glass/bottle/salglu_solution = 3,
- /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2)
+ /obj/item/reagent_containers/glass/bottle/toxin = 3, /obj/item/reagent_containers/syringe/antiviral = 6, /obj/item/reagent_containers/pill/salbutamol = 2, /obj/item/device/healthanalyzer = 4, /obj/item/device/sensor_device = 2, /obj/item/pinpointer/crew = 2)
contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6)
premium = list(/obj/item/storage/box/hug/medical = 1, /obj/item/reagent_containers/hypospray/medipen = 3, /obj/item/storage/belt/medical = 3, /obj/item/wrench/medical = 1)
armor = list(melee = 100, bullet = 100, laser = 100, energy = 100, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 50)
diff --git a/code/game/objects/items/devices/PDA/virus_cart.dm b/code/game/objects/items/devices/PDA/virus_cart.dm
index 2b0a9d3b3c..8c4a42a5aa 100644
--- a/code/game/objects/items/devices/PDA/virus_cart.dm
+++ b/code/game/objects/items/devices/PDA/virus_cart.dm
@@ -90,7 +90,7 @@
return
if(!isnull(target) && !target.toff)
charges--
- var/lock_code = "[rand(100,999)] [pick("Alpha","Bravo","Charlie","Delta","Echo","Foxtrot","Golf","Hotel","India","Juliet","Kilo","Lima","Mike","November","Oscar","Papa","Quebec","Romeo","Sierra","Tango","Uniform","Victor","Whiskey","X-ray","Yankee","Zulu")]"
+ var/lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
to_chat(U, "Virus Sent! The unlock code to the target is: [lock_code]")
if(!target.hidden_uplink)
var/obj/item/device/uplink/uplink = new(target)
diff --git a/code/game/objects/items/devices/pinpointer.dm b/code/game/objects/items/devices/pinpointer.dm
new file mode 100644
index 0000000000..1d11f312a4
--- /dev/null
+++ b/code/game/objects/items/devices/pinpointer.dm
@@ -0,0 +1,152 @@
+//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
+/obj/item/weapon/pinpointer
+ name = "pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pinpointer"
+ flags = CONDUCT
+ slot_flags = SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL = 500, MAT_GLASS = 250)
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ var/active = FALSE
+ var/atom/movable/target = null //The thing we're searching for
+ var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
+ var/alert = FALSE // TRUE to display things more seriously
+
+/obj/item/weapon/pinpointer/New()
+ ..()
+ GLOB.pinpointer_list += src
+
+/obj/item/weapon/pinpointer/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ GLOB.pinpointer_list -= src
+ return ..()
+
+/obj/item/weapon/pinpointer/attack_self(mob/living/user)
+ active = !active
+ user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
+ playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
+ if(active)
+ START_PROCESSING(SSfastprocess, src)
+ else
+ target = null
+ STOP_PROCESSING(SSfastprocess, src)
+ update_pointer_overlay()
+
+/obj/item/weapon/pinpointer/process()
+ if(!active)
+ STOP_PROCESSING(SSfastprocess, src)
+ return
+ scan_for_target()
+ update_pointer_overlay()
+
+/obj/item/weapon/pinpointer/proc/scan_for_target()
+ return
+
+/obj/item/weapon/pinpointer/proc/update_pointer_overlay()
+ cut_overlays()
+ if(!active)
+ return
+ if(!target)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ var/turf/here = get_turf(src)
+ var/turf/there = get_turf(target)
+ if(here.z != there.z)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ return
+ if(get_dist_euclidian(here,there) <= minimum_range)
+ add_overlay("pinon[alert ? "alert" : ""]direct")
+ else
+ setDir(get_dir(here, there))
+ switch(get_dist(here, there))
+ if(1 to 8)
+ add_overlay("pinon[alert ? "alert" : "close"]")
+ if(9 to 16)
+ add_overlay("pinon[alert ? "alert" : "medium"]")
+ if(16 to INFINITY)
+ add_overlay("pinon[alert ? "alert" : "far"]")
+
+/obj/item/weapon/pinpointer/crew // A replacement for the old crew monitoring consoles
+ name = "crew pinpointer"
+ desc = "A handheld tracking device that points to crew suit sensors."
+ icon_state = "pinpointer_crew"
+
+/obj/item/weapon/pinpointer/crew/proc/trackable(mob/living/carbon/human/H)
+ var/turf/here = get_turf(src)
+ if((H.z == 0 || H.z == here.z) && istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = H.w_uniform
+
+ // Suit sensors must be on maximum.
+ if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS)
+ return FALSE
+
+ var/turf/there = get_turf(H)
+ return (H.z != 0 || (there && there.z == H.z))
+
+ return FALSE
+
+/obj/item/weapon/pinpointer/crew/attack_self(mob/living/user)
+ if(active)
+ active = FALSE
+ user.visible_message("[user] deactivates their pinpointer.", "You deactivate your pinpointer.")
+ playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
+ target = null //Restarting the pinpointer forces a target reset
+ STOP_PROCESSING(SSfastprocess, src)
+ update_pointer_overlay()
+ return
+
+ var/list/name_counts = list()
+ var/list/names = list()
+
+ for(var/mob/living/carbon/human/H in GLOB.mob_list)
+ if(!trackable(H))
+ continue
+
+ var/name = "Unknown"
+ if(H.wear_id)
+ var/obj/item/weapon/card/id/I = H.wear_id.GetID()
+ name = I.registered_name
+
+ while(name in name_counts)
+ name_counts[name]++
+ name = text("[] ([])", name, name_counts[name])
+ names[name] = H
+ name_counts[name] = 1
+
+ if(!names.len)
+ user.visible_message("[user]'s pinpointer fails to detect a signal.", "Your pinpointer fails to detect a signal.")
+ return
+
+ var/A = input(user, "Person to track", "Pinpoint") in names
+ if(!src || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !A)
+ return
+
+ target = names[A]
+ active = TRUE
+ user.visible_message("[user] activates their pinpointer.", "You activate your pinpointer.")
+ playsound(user, 'sound/items/screwdriver2.ogg', 50, 1)
+ START_PROCESSING(SSfastprocess, src)
+ update_pointer_overlay()
+
+/obj/item/weapon/pinpointer/crew/scan_for_target()
+ if(target)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(!trackable(H))
+ target = null
+ if(!target)
+ active = FALSE
+
+/obj/item/weapon/pinpointer/process()
+ if(!active)
+ STOP_PROCESSING(SSfastprocess, src)
+ return
+ scan_for_target()
+ update_pointer_overlay()
+
diff --git a/code/game/objects/items/implants/implantchair.dm b/code/game/objects/items/implants/implantchair.dm
index 55a35960cf..2f59020cbe 100644
--- a/code/game/objects/items/implants/implantchair.dm
+++ b/code/game/objects/items/implants/implantchair.dm
@@ -1,187 +1,188 @@
-/obj/machinery/implantchair
- name = "mindshield implanter"
- desc = "Used to implant occupants with mindshield implants."
- icon = 'icons/obj/machines/implantchair.dmi'
- icon_state = "implantchair"
- density = TRUE
- opacity = 0
- anchored = TRUE
-
- var/ready = TRUE
- var/replenishing = FALSE
-
- var/ready_implants = 5
- var/max_implants = 5
- var/injection_cooldown = 600
- var/replenish_cooldown = 6000
- var/implant_type = /obj/item/implant/mindshield
- var/auto_inject = FALSE
- var/auto_replenish = TRUE
- var/special = FALSE
- var/special_name = "special function"
-
-/obj/machinery/implantchair/Initialize()
- . = ..()
- open_machine()
- update_icon()
-
-
-/obj/machinery/implantchair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "implantchair", name, 375, 280, master_ui, state)
- ui.open()
-
-
-/obj/machinery/implantchair/ui_data()
- var/list/data = list()
- data["occupied"] = occupant ? 1 : 0
- data["open"] = state_open
-
- data["occupant"] = list()
- if(occupant)
- var/mob/living/mob_occupant = occupant
- data["occupant"]["name"] = mob_occupant.name
- data["occupant"]["stat"] = mob_occupant.stat
-
- data["special_name"] = special ? special_name : null
- data["ready_implants"] = ready_implants
- data["ready"] = ready
- data["replenishing"] = replenishing
-
- return data
-
-/obj/machinery/implantchair/ui_act(action, params)
- if(..())
- return
- switch(action)
- if("door")
- if(state_open)
- close_machine()
- else
- open_machine()
- . = TRUE
- if("implant")
- implant(occupant,usr)
- . = TRUE
-
-/obj/machinery/implantchair/proc/implant(mob/living/M,mob/user)
- if (!istype(M))
- return
- if(!ready_implants || !ready)
- return
- if(implant_action(M,user))
- ready_implants--
- if(!replenishing && auto_replenish)
- replenishing = TRUE
- addtimer(CALLBACK(src,"replenish"),replenish_cooldown)
- if(injection_cooldown > 0)
- ready = FALSE
- addtimer(CALLBACK(src,"set_ready"),injection_cooldown)
- else
- playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, 1)
- update_icon()
-
-/obj/machinery/implantchair/proc/implant_action(mob/living/M)
- var/obj/item/implant/I = new implant_type
- if(I.implant(M))
- visible_message("[M] has been implanted by the [name].")
- return 1
-
-/obj/machinery/implantchair/update_icon()
- icon_state = initial(icon_state)
- if(state_open)
- icon_state += "_open"
- if(occupant)
- icon_state += "_occupied"
- if(ready)
- add_overlay("ready")
- else
- cut_overlays()
-
-/obj/machinery/implantchair/proc/replenish()
- if(ready_implants < max_implants)
- ready_implants++
- if(ready_implants < max_implants)
- addtimer(CALLBACK(src,"replenish"),replenish_cooldown)
- else
- replenishing = FALSE
-
-/obj/machinery/implantchair/proc/set_ready()
- ready = TRUE
- update_icon()
-
-/obj/machinery/implantchair/container_resist(mob/living/user)
- if(state_open)
- return
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
- to_chat(user, "You lean on the back of [src] and start pushing the door open... (this will take about about a minute.)")
- audible_message("You hear a metallic creaking from [src]!",hearing_distance = 2)
-
- if(do_after(user, 600, target = src))
- if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
- return
- visible_message("[user] successfully broke out of [src]!")
- to_chat(user, "You successfully break out of [src]!")
- open_machine()
-
-/obj/machinery/implantchair/relaymove(mob/user)
- container_resist(user)
-
-/obj/machinery/implantchair/MouseDrop_T(mob/target, mob/user)
- if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !isliving(target) || !user.IsAdvancedToolUser())
- return
- close_machine(target)
-
-/obj/machinery/implantchair/close_machine(mob/living/user)
- if((isnull(user) || istype(user)) && state_open)
- ..(user)
- if(auto_inject && ready && ready_implants > 0)
- implant(user,null)
-
-/obj/machinery/implantchair/genepurge
- name = "Genetic purifier"
- desc = "Used to purge human genome of foreign influences"
- special = TRUE
- special_name = "Purge genome"
- injection_cooldown = 0
- replenish_cooldown = 300
-
-/obj/machinery/implantchair/genepurge/implant_action(mob/living/carbon/human/H,mob/user)
- if(!istype(H))
- return 0
- H.set_species(/datum/species/human, 1)//lizards go home
- purrbation_remove(H)//remove cats
- H.dna.remove_all_mutations()//hulks out
- return 1
-
-
-/obj/machinery/implantchair/brainwash
- name = "Neural Imprinter"
- desc = "Used to indoctrinate rehabilitate hardened recidivists."
- special_name = "Imprint"
- injection_cooldown = 3000
- auto_inject = FALSE
- auto_replenish = FALSE
- special = TRUE
- var/objective = "Obey the law. Praise Nanotrasen."
- var/custom = FALSE
-
-/obj/machinery/implantchair/brainwash/implant_action(mob/living/C,mob/user)
- if(!istype(C) || !C.mind) // I don't know how this makes any sense for silicons but laws trump objectives anyway.
- return 0
- if(custom)
- if(!user || !user.Adjacent(src))
- return 0
- objective = stripped_input(usr,"What order do you want to imprint on [C]?","Enter the order","",120)
- message_admins("[key_name_admin(user)] set brainwash machine objective to '[objective]'.")
- log_game("[key_name_admin(user)] set brainwash machine objective to '[objective]'.")
- var/datum/objective/custom_objective = new/datum/objective(objective)
- custom_objective.owner = C.mind
- C.mind.objectives += custom_objective
- C.mind.announce_objectives()
- message_admins("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
- log_game("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
- return 1
-
+/obj/machinery/implantchair
+ name = "mindshield implanter"
+ desc = "Used to implant occupants with mindshield implants."
+ icon = 'icons/obj/machines/implantchair.dmi'
+ icon_state = "implantchair"
+ density = TRUE
+ opacity = 0
+ anchored = TRUE
+
+ var/ready = TRUE
+ var/replenishing = FALSE
+
+ var/ready_implants = 5
+ var/max_implants = 5
+ var/injection_cooldown = 600
+ var/replenish_cooldown = 6000
+ var/implant_type = /obj/item/implant/mindshield
+ var/auto_inject = FALSE
+ var/auto_replenish = TRUE
+ var/special = FALSE
+ var/special_name = "special function"
+ var/message_cooldown
+ var/breakout_time = 1
+
+/obj/machinery/implantchair/Initialize()
+ . = ..()
+ open_machine()
+ update_icon()
+
+
+/obj/machinery/implantchair/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "implantchair", name, 375, 280, master_ui, state)
+ ui.open()
+
+
+/obj/machinery/implantchair/ui_data()
+ var/list/data = list()
+ data["occupied"] = occupant ? 1 : 0
+ data["open"] = state_open
+
+ data["occupant"] = list()
+ if(occupant)
+ var/mob/living/mob_occupant = occupant
+ data["occupant"]["name"] = mob_occupant.name
+ data["occupant"]["stat"] = mob_occupant.stat
+
+ data["special_name"] = special ? special_name : null
+ data["ready_implants"] = ready_implants
+ data["ready"] = ready
+ data["replenishing"] = replenishing
+
+ return data
+
+/obj/machinery/implantchair/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("door")
+ if(state_open)
+ close_machine()
+ else
+ open_machine()
+ . = TRUE
+ if("implant")
+ implant(occupant,usr)
+ . = TRUE
+
+/obj/machinery/implantchair/proc/implant(mob/living/M,mob/user)
+ if (!istype(M))
+ return
+ if(!ready_implants || !ready)
+ return
+ if(implant_action(M,user))
+ ready_implants--
+ if(!replenishing && auto_replenish)
+ replenishing = TRUE
+ addtimer(CALLBACK(src,"replenish"),replenish_cooldown)
+ if(injection_cooldown > 0)
+ ready = FALSE
+ addtimer(CALLBACK(src,"set_ready"),injection_cooldown)
+ else
+ playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 25, 1)
+ update_icon()
+
+/obj/machinery/implantchair/proc/implant_action(mob/living/M)
+ var/obj/item/implant/I = new implant_type
+ if(I.implant(M))
+ visible_message("[M] has been implanted by the [name].")
+ return 1
+
+/obj/machinery/implantchair/update_icon()
+ icon_state = initial(icon_state)
+ if(state_open)
+ icon_state += "_open"
+ if(occupant)
+ icon_state += "_occupied"
+ if(ready)
+ add_overlay("ready")
+ else
+ cut_overlays()
+
+/obj/machinery/implantchair/proc/replenish()
+ if(ready_implants < max_implants)
+ ready_implants++
+ if(ready_implants < max_implants)
+ addtimer(CALLBACK(src,"replenish"),replenish_cooldown)
+ else
+ replenishing = FALSE
+
+/obj/machinery/implantchair/proc/set_ready()
+ ready = TRUE
+ update_icon()
+
+/obj/machinery/implantchair/container_resist(mob/living/user)
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ user.visible_message("You see [user] kicking against the door of [src]!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a metallic creaking from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
+ return
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
+ open_machine()
+
+/obj/machinery/implantchair/relaymove(mob/user)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
+
+/obj/machinery/implantchair/MouseDrop_T(mob/target, mob/user)
+ if(user.stat || user.lying || !Adjacent(user) || !user.Adjacent(target) || !isliving(target) || !user.IsAdvancedToolUser())
+ return
+ close_machine(target)
+
+/obj/machinery/implantchair/close_machine(mob/living/user)
+ if((isnull(user) || istype(user)) && state_open)
+ ..(user)
+ if(auto_inject && ready && ready_implants > 0)
+ implant(user,null)
+
+/obj/machinery/implantchair/genepurge
+ name = "Genetic purifier"
+ desc = "Used to purge human genome of foreign influences"
+ special = TRUE
+ special_name = "Purge genome"
+ injection_cooldown = 0
+ replenish_cooldown = 300
+
+/obj/machinery/implantchair/genepurge/implant_action(mob/living/carbon/human/H,mob/user)
+ if(!istype(H))
+ return 0
+ H.set_species(/datum/species/human, 1)//lizards go home
+ purrbation_remove(H)//remove cats
+ H.dna.remove_all_mutations()//hulks out
+ return 1
+
+
+/obj/machinery/implantchair/brainwash
+ name = "Neural Imprinter"
+ desc = "Used to indoctrinate rehabilitate hardened recidivists."
+ special_name = "Imprint"
+ injection_cooldown = 3000
+ auto_inject = FALSE
+ auto_replenish = FALSE
+ special = TRUE
+ var/objective = "Obey the law. Praise Nanotrasen."
+ var/custom = FALSE
+
+/obj/machinery/implantchair/brainwash/implant_action(mob/living/C,mob/user)
+ if(!istype(C) || !C.mind) // I don't know how this makes any sense for silicons but laws trump objectives anyway.
+ return 0
+ if(custom)
+ if(!user || !user.Adjacent(src))
+ return 0
+ objective = stripped_input(usr,"What order do you want to imprint on [C]?","Enter the order","",120)
+ message_admins("[key_name_admin(user)] set brainwash machine objective to '[objective]'.")
+ log_game("[key_name_admin(user)] set brainwash machine objective to '[objective]'.")
+ var/datum/objective/custom_objective = new/datum/objective(objective)
+ custom_objective.owner = C.mind
+ C.mind.objectives += custom_objective
+ C.mind.announce_objectives()
+ message_admins("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
+ log_game("[key_name_admin(user)] brainwashed [key_name_admin(C)] with objective '[objective]'.")
+ return 1
diff --git a/code/game/objects/items/pinpointer.dm b/code/game/objects/items/pinpointer.dm
new file mode 100644
index 0000000000..28488a231f
--- /dev/null
+++ b/code/game/objects/items/pinpointer.dm
@@ -0,0 +1,150 @@
+//Pinpointers are used to track atoms from a distance as long as they're on the same z-level. The captain and nuke ops have ones that track the nuclear authentication disk.
+/obj/item/pinpointer
+ name = "pinpointer"
+ desc = "A handheld tracking device that locks onto certain signals."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pinpointer"
+ flags_1 = CONDUCT_1
+ slot_flags = SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL = 500, MAT_GLASS = 250)
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
+ var/active = FALSE
+ var/atom/movable/target //The thing we're searching for
+ var/minimum_range = 0 //at what range the pinpointer declares you to be at your destination
+ var/alert = FALSE // TRUE to display things more seriously
+
+/obj/item/pinpointer/Initialize()
+ . = ..()
+ GLOB.pinpointer_list += src
+
+/obj/item/pinpointer/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ GLOB.pinpointer_list -= src
+ return ..()
+
+/obj/item/pinpointer/attack_self(mob/living/user)
+ active = !active
+ user.visible_message("[user] [active ? "" : "de"]activates their pinpointer.", "You [active ? "" : "de"]activate your pinpointer.")
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ if(active)
+ START_PROCESSING(SSfastprocess, src)
+ else
+ target = null
+ STOP_PROCESSING(SSfastprocess, src)
+ update_icon()
+
+/obj/item/pinpointer/process()
+ if(!active)
+ return PROCESS_KILL
+ scan_for_target()
+ update_icon()
+
+/obj/item/pinpointer/proc/scan_for_target()
+ return
+
+/obj/item/pinpointer/update_icon()
+ cut_overlays()
+ if(!active)
+ return
+ if(!target)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ var/turf/here = get_turf(src)
+ var/turf/there = get_turf(target)
+ if(here.z != there.z)
+ add_overlay("pinon[alert ? "alert" : ""]null")
+ return
+ if(get_dist_euclidian(here,there) <= minimum_range)
+ add_overlay("pinon[alert ? "alert" : ""]direct")
+ else
+ setDir(get_dir(here, there))
+ switch(get_dist(here, there))
+ if(1 to 8)
+ add_overlay("pinon[alert ? "alert" : "close"]")
+ if(9 to 16)
+ add_overlay("pinon[alert ? "alert" : "medium"]")
+ if(16 to INFINITY)
+ add_overlay("pinon[alert ? "alert" : "far"]")
+
+/obj/item/pinpointer/crew // A replacement for the old crew monitoring consoles
+ name = "crew pinpointer"
+ desc = "A handheld tracking device that points to crew suit sensors."
+ icon_state = "pinpointer_crew"
+
+/obj/item/pinpointer/crew/proc/trackable(mob/living/carbon/human/H)
+ var/turf/here = get_turf(src)
+ if((H.z == 0 || H.z == here.z) && istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = H.w_uniform
+
+ // Suit sensors must be on maximum.
+ if(!U.has_sensor || U.sensor_mode < SENSOR_COORDS)
+ return FALSE
+
+ var/turf/there = get_turf(H)
+ return (H.z != 0 || (there && there.z == H.z))
+
+ return FALSE
+
+/obj/item/pinpointer/crew/attack_self(mob/living/user)
+ if(active)
+ active = FALSE
+ user.visible_message("[user] deactivates their pinpointer.", "You deactivate your pinpointer.")
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ target = null //Restarting the pinpointer forces a target reset
+ STOP_PROCESSING(SSfastprocess, src)
+ update_icon()
+ return
+
+ var/list/name_counts = list()
+ var/list/names = list()
+
+ for(var/mob/living/carbon/human/H in GLOB.mob_list)
+ if(!trackable(H))
+ continue
+
+ var/crewmember_name = "Unknown"
+ if(H.wear_id)
+ var/obj/item/card/id/I = H.wear_id.GetID()
+ crewmember_name = I.registered_name
+
+ while(crewmember_name in name_counts)
+ name_counts[crewmember_name]++
+ crewmember_name = text("[] ([])", crewmember_name, name_counts[crewmember_name])
+ names[crewmember_name] = H
+ name_counts[crewmember_name] = 1
+
+ if(!names.len)
+ user.visible_message("[user]'s pinpointer fails to detect a signal.", "Your pinpointer fails to detect a signal.")
+ return
+
+ var/A = input(user, "Person to track", "Pinpoint") in names
+ if(!A || QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated())
+ return
+
+ target = names[A]
+ active = TRUE
+ user.visible_message("[user] activates their pinpointer.", "You activate your pinpointer.")
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ START_PROCESSING(SSfastprocess, src)
+ update_icon()
+
+/obj/item/pinpointer/crew/scan_for_target()
+ if(target)
+ if(ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(!trackable(H))
+ target = null
+ if(!target) //target can be set to null from above code, or elsewhere
+ active = FALSE
+
+/obj/item/pinpointer/process()
+ if(!active)
+ return PROCESS_KILL
+ scan_for_target()
+ update_icon()
+
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 323527fc88..6c19b49073 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -487,7 +487,7 @@
righthand_file = 'icons/mob/inhands/weapons/chainsaw_righthand.dmi'
flags_1 = CONDUCT_1
force = 13
- var/force_on = 21
+ var/force_on = 24
w_class = WEIGHT_CLASS_HUGE
throwforce = 13
throw_speed = 2
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 78e672e49d..4f8705aa71 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -16,7 +16,7 @@
integrity_failure = 50
armor = list(melee = 20, bullet = 10, laser = 10, energy = 0, bomb = 10, bio = 0, rad = 0, fire = 70, acid = 60)
var/breakout_time = 2
- var/lastbang
+ var/message_cooldown
var/can_weld_shut = TRUE
var/horizontal = FALSE
var/allow_objects = FALSE
@@ -300,14 +300,12 @@
/obj/structure/closet/relaymove(mob/user)
if(user.stat || !isturf(loc) || !isliving(user))
return
- var/mob/living/L = user
- if(!open())
- if(L.last_special <= world.time)
- container_resist(L)
- if(world.time > lastbang+5)
- lastbang = world.time
- for(var/mob/M in get_hearers_in_view(src, null))
- M.show_message("BANG, bang!", 2)
+ if(locked)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
+ return
+ container_resist()
/obj/structure/closet/attack_hand(mob/user)
..()
@@ -367,9 +365,10 @@
//okay, so the closet is either welded or locked... resist!!!
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
- to_chat(user, "You lean on the back of [src] and start pushing the door open.")
- visible_message("[src] begins to shake violently!")
- if(do_after(user,(breakout_time * 60 * 10), target = src)) //minutes * 60seconds * 10deciseconds
+ user.visible_message("[src] begins to shake violently!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear banging from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
return
//we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
@@ -388,7 +387,7 @@
/obj/structure/closet/AltClick(mob/user)
..()
- if(!user.canUseTopic(src, be_close=TRUE))
+ if(!user.canUseTopic(src, be_close=TRUE) || isturf(loc))
to_chat(user, "You can't do that right now!")
return
if(opened || !secure)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index cefd972aaf..aeacf17598 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -83,7 +83,7 @@
new /obj/item/storage/belt/security/full(src)
new /obj/item/gun/energy/e_gun/hos(src)
new /obj/item/device/flashlight/seclite(src)
- new /obj/item/pinpointer(src)
+ new /obj/item/pinpointer/nuke(src)
/obj/structure/closet/secure_closet/warden
name = "\proper warden's locker"
@@ -108,6 +108,7 @@
new /obj/item/clothing/gloves/krav_maga/sec(src)
new /obj/item/door_remote/head_of_security(src)
new /obj/item/gun/ballistic/shotgun/automatic/combat/compact(src)
+ new /obj/item/pinpointer/crew(src)
/obj/structure/closet/secure_closet/security
name = "security officer's locker"
@@ -183,6 +184,7 @@
new /obj/item/reagent_containers/spray/pepper(src)
new /obj/item/clothing/suit/armor/vest/det_suit(src)
new /obj/item/storage/belt/holster/full(src)
+ new /obj/item/pinpointer/crew(src)
new /obj/item/device/mass_spectrometer(src)
/obj/structure/closet/secure_closet/injection
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index 600e15201d..f4a98811c0 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -23,6 +23,8 @@
var/obj/structure/tray/connected = null
var/locked = FALSE
var/opendir = SOUTH
+ var/message_cooldown
+ var/breakout_time = 1
/obj/structure/bodycontainer/Destroy()
open()
@@ -41,6 +43,11 @@
/obj/structure/bodycontainer/relaymove(mob/user)
if(user.stat || !isturf(loc))
return
+ if(locked)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
+ return
open()
/obj/structure/bodycontainer/attack_paw(mob/user)
@@ -84,11 +91,20 @@
qdel(src)
/obj/structure/bodycontainer/container_resist(mob/living/user)
- open()
-
-/obj/structure/bodycontainer/relay_container_resist(mob/living/user, obj/O)
- to_chat(user, "You slam yourself into the side of [O].")
- container_resist(user)
+ if(!locked)
+ open()
+ return
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ user.visible_message(null, \
+ "You lean on the back of [src] and start pushing the tray open... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a metallic creaking from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(!user || user.stat != CONSCIOUS || user.loc != src )
+ return
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
+ open()
/obj/structure/bodycontainer/proc/open()
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
index b885f980a2..43394f01c9 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
@@ -67,6 +67,9 @@
deconstruct(FALSE)
/obj/structure/transit_tube_pod/container_resist(mob/living/user)
+ if(!user.incapacitated())
+ empty_pod()
+ return
if(!moving)
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm
index a83ced850e..f447b2f3e9 100644
--- a/code/modules/VR/vr_sleeper.dm
+++ b/code/modules/VR/vr_sleeper.dm
@@ -49,6 +49,10 @@
open_machine()
+/obj/machinery/vr_sleeper/container_resist(mob/living/user)
+ open_machine()
+
+
/obj/machinery/vr_sleeper/Destroy()
open_machine()
cleanup_vr_human()
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index f5f3326001..8890b9a6ae 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1124,7 +1124,10 @@
else if(href_list["showmessageckey"])
var/target = href_list["showmessageckey"]
- browse_messages(target_ckey = target)
+ var/agegate = TRUE
+ if (href_list["showall"])
+ agegate = FALSE
+ browse_messages(target_ckey = target, agegate = agegate)
else if(href_list["showmessageckeylinkless"])
var/target = href_list["showmessageckeylinkless"]
diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm
index 7301724eb6..abb87a4235 100644
--- a/code/modules/admin/verbs/onlyone.dm
+++ b/code/modules/admin/verbs/onlyone.dm
@@ -50,8 +50,8 @@ GLOBAL_VAR_INIT(highlander, FALSE)
equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(src), slot_ears)
equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(src), slot_head)
equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(src), slot_shoes)
- equip_to_slot_or_del(new /obj/item/pinpointer(src), slot_l_store)
- for(var/obj/item/pinpointer/P in src)
+ equip_to_slot_or_del(new /obj/item/pinpointer/nuke(src), slot_l_store)
+ for(var/obj/item/pinpointer/nuke/P in src)
P.attack_self(src)
var/obj/item/card/id/W = new(src)
W.icon_state = "centcom"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index f0f41e375a..89e6538b07 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -32,6 +32,8 @@
var/running_bob_anim = FALSE
var/escape_in_progress = FALSE
+ var/message_cooldown
+ var/breakout_time = 0.5
/obj/machinery/atmospherics/components/unary/cryo_cell/Initialize()
. = ..()
@@ -219,7 +221,9 @@
update_icon()
/obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/user)
- container_resist(user)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
/obj/machinery/atmospherics/components/unary/cryo_cell/open_machine(drop = 0)
if(!state_open && !panel_open)
@@ -239,16 +243,17 @@
return occupant
/obj/machinery/atmospherics/components/unary/cryo_cell/container_resist(mob/living/user)
- if(escape_in_progress)
- to_chat(user, "You are already trying to exit (This will take around 30 seconds)")
- return
- escape_in_progress = TRUE
- to_chat(user, "You struggle inside the cryotube, kicking the release with your foot... (This will take around 30 seconds.)")
- audible_message("You hear a thump from [src].")
- if(do_after(user, 300))
- if(occupant == user) // Check they're still here.
- open_machine()
- escape_in_progress = FALSE
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ user.visible_message("You see [user] kicking against the glass of [src]!", \
+ "You struggle inside [src], kicking the release with your foot... (this will take about [(breakout_time<1) ? "[breakout_time*60] seconds" : "[breakout_time] minute\s"].)", \
+ "You hear a thump from [src].")
+ if(do_after(user,(breakout_time*60*10), target = src)) //minutes * 60seconds * 10deciseconds
+ if(!user || user.stat != CONSCIOUS || user.loc != src )
+ return
+ user.visible_message("[user] successfully broke out of [src]!", \
+ "You successfully break out of [src]!")
+ open_machine()
/obj/machinery/atmospherics/components/unary/cryo_cell/examine(mob/user)
..()
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 6135e6ac9d..6fbc7d552f 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -577,13 +577,13 @@ GLOBAL_LIST(external_rsc_urls)
var/const/adminckey = "CID-Error"
var/sql_ckey = sanitizeSQL(ckey)
//check to see if we noted them in the last day.
- var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW()")
+ var/datum/DBQuery/query_get_notes = SSdbcore.NewQuery("SELECT id FROM [format_table_name("messages")] WHERE type = 'note' AND targetckey = '[sql_ckey]' AND adminckey = '[adminckey]' AND timestamp + INTERVAL 1 DAY < NOW() AND deleted = 0")
if(!query_get_notes.Execute())
return
if(query_get_notes.NextRow())
return
//regardless of above, make sure their last note is not from us, as no point in repeating the same note over and over.
- query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' ORDER BY timestamp DESC LIMIT 1")
+ query_get_notes = SSdbcore.NewQuery("SELECT adminckey FROM [format_table_name("messages")] WHERE targetckey = '[sql_ckey]' AND deleted = 0 ORDER BY timestamp DESC LIMIT 1")
if(!query_get_notes.Execute())
return
if(query_get_notes.NextRow())
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index cd0f893fa6..a86b30e605 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -234,7 +234,7 @@ GLOBAL_VAR_INIT(normal_ooc_colour, OOC_COLOR)
to_chat(usr, "Sorry, that function is not enabled on this server.")
return
- browse_messages(null, usr.ckey, null, 1)
+ browse_messages(null, usr.ckey, null, TRUE)
/client/proc/ignore_key(client)
var/client/C = client
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 1f12e671ec..d3b53d3a41 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -308,8 +308,8 @@
name = "Chainsaw"
result = /obj/item/twohanded/required/chainsaw
reqs = list(/obj/item/circular_saw = 1,
- /obj/item/stack/cable_coil = 1,
- /obj/item/stack/sheet/plasteel = 1)
+ /obj/item/stack/cable_coil = 3,
+ /obj/item/stack/sheet/plasteel = 5)
tools = list(/obj/item/weldingtool)
time = 50
category = CAT_WEAPONRY
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index d9f70160a4..978e8af62d 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -51,6 +51,9 @@
/obj/machinery/gibber/container_resist(mob/living/user)
go_out()
+/obj/machinery/gibber/relaymove(mob/living/user)
+ go_out()
+
/obj/machinery/gibber/attack_hand(mob/user)
if(stat & (NOPOWER|BROKEN))
return
@@ -225,4 +228,4 @@
if(M.loc == input_plate)
M.forceMove(src)
- M.gib()
\ No newline at end of file
+ M.gib()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index 53b899f696..806fbc1f90 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -148,6 +148,7 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "smartvend", name, 440, 550, master_ui, state)
+ ui.set_autoupdate(FALSE)
ui.open()
/obj/machinery/smartfridge/ui_data(mob/user)
@@ -156,10 +157,11 @@
var/listofitems = list()
for (var/I in src)
var/atom/movable/O = I
- if (listofitems[O.name])
- listofitems[O.name]["amount"]++
- else
- listofitems[O.name] = list("name" = O.name, "type" = O.type, "amount" = 1)
+ if (!QDELETED(O))
+ if (listofitems[O.name])
+ listofitems[O.name]["amount"]++
+ else
+ listofitems[O.name] = list("name" = O.name, "type" = O.type, "amount" = 1)
sortList(listofitems)
.["contents"] = listofitems
@@ -167,6 +169,9 @@
.["isdryer"] = FALSE
+/obj/machinery/smartfridge/handle_atom_del(atom/A) // Update the UIs in case something inside gets deleted
+ SStgui.update_uis(src)
+
/obj/machinery/smartfridge/ui_act(action, params)
. = ..()
if(.)
@@ -227,20 +232,7 @@
..()
/obj/machinery/smartfridge/drying_rack/ui_data(mob/user)
- . = list()
-
- var/listofitems = list()
- for (var/I in src)
- var/atom/movable/O = I
-
- if (listofitems[O.name])
- listofitems[O.name]["amount"]++
- else
- listofitems[O.name] = list("name" = O.name, "type" = O.type, "amount" = 1)
- sortList(listofitems)
-
- .["contents"] = listofitems
- .["name"] = name
+ . = ..()
.["isdryer"] = TRUE
.["verb"] = "Take"
.["drying"] = drying
@@ -249,6 +241,7 @@
/obj/machinery/smartfridge/drying_rack/ui_act(action, params)
. = ..()
if(.)
+ update_icon() // This is to handle a case where the last item is taken out manually instead of through drying pop-out
return
switch(action)
if("Dry")
@@ -280,6 +273,7 @@
..()
if(drying)
if(rack_dry())//no need to update unless something got dried
+ SStgui.update_uis(src)
update_icon()
/obj/machinery/smartfridge/drying_rack/accept_check(obj/item/O)
diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm
index 94d2753fc5..9a33e1e759 100644
--- a/code/modules/jobs/job_types/medical.dm
+++ b/code/modules/jobs/job_types/medical.dm
@@ -33,6 +33,7 @@ Chief Medical Officer
id = /obj/item/card/id/silver
belt = /obj/item/device/pda/heads/cmo
+ l_pocket = /obj/item/pinpointer/crew
ears = /obj/item/device/radio/headset/heads/cmo
uniform = /obj/item/clothing/under/rank/chief_medical_officer
shoes = /obj/item/clothing/shoes/sneakers/brown
diff --git a/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm b/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm
index 648e6170fa..228c9fe6e7 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories_Citadel.dm
@@ -1,8 +1,8 @@
/datum/sprite_accessory
- var/extra = 0
+ var/extra = FALSE
var/extra_icon = 'icons/mob/mam_bodyparts.dmi'
var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay.
- var/extra2 = 0
+ var/extra2 = FALSE
var/extra2_icon = 'icons/mob/mam_bodyparts.dmi'
var/extra2_color_src = MUTCOLORS3
// var/list/ckeys_allowed = null
@@ -13,6 +13,10 @@
icon = 'icons/mob/mam_bodyparts.dmi'
*/
+/***************** Alphabetical Order please ***************
+************* Keep it to Ears, Tails, Tails Animated *********/
+
+
/datum/sprite_accessory/tails/lizard/none
name = "None"
icon_state = "None"
@@ -31,12 +35,17 @@
color_src = 0
icon = 'icons/mob/mam_bodyparts.dmi'
+/datum/sprite_accessory/ears/human/bear
+ name = "Bear"
+ icon_state = "bear"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+
/datum/sprite_accessory/tails/human/bear
name = "Bear"
icon_state = "bear"
icon = 'icons/mob/mam_bodyparts.dmi'
-/datum/sprite_accessory/ears/human/bear
+/datum/sprite_accessory/tails_animated/human/bear
name = "Bear"
icon_state = "bear"
icon = 'icons/mob/mam_bodyparts.dmi'
@@ -51,10 +60,27 @@
icon_state = "catbig"
icon = 'icons/mob/mam_bodyparts.dmi'
+/datum/sprite_accessory/ears/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+ gender_specific = 1
+
+/datum/sprite_accessory/tails/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+
+/datum/sprite_accessory/tails_animated/human/cow
+ name = "Cow"
+ icon_state = "cow"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+
/datum/sprite_accessory/ears/fennec
name = "Fennec"
icon_state = "fennec"
icon = 'icons/mob/mam_bodyparts.dmi'
+ hasinner = 1
/datum/sprite_accessory/tails/human/fennec
name = "Fennec"
@@ -76,37 +102,49 @@
name = "Fox"
icon_state = "fox"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/tails_animated/human/fox
name = "Fox"
icon_state = "fox"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
+
+/datum/sprite_accessory/tails/human/horse
+ name = "Horse"
+ icon_state = "horse"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+ color_src = HAIR
+
+/datum/sprite_accessory/tails_animated/human/horse
+ name = "Horse"
+ icon_state = "horse"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+ color_src = HAIR
/datum/sprite_accessory/tails/human/husky
name = "Husky"
icon_state = "husky"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/tails_animated/human/husky
name = "Husky"
icon_state = "husky"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/tails/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = 1
+ extra = TRUE
extra_color_src = MUTCOLORS2
icon = 'icons/mob/mam_bodyparts.dmi'
/datum/sprite_accessory/tails_animated/human/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = 1
+ extra = TRUE
extra_color_src = MUTCOLORS2
icon = 'icons/mob/mam_bodyparts.dmi'
@@ -146,6 +184,24 @@
name = "Otusian"
icon_state = "otie"
+/datum/sprite_accessory/ears/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ hasinner= 1
+ icon = 'icons/mob/mam_bodyparts.dmi'
+
+/datum/sprite_accessory/tails/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = 0
+ icon = 'icons/mob/mam_bodyparts.dmi'
+
+/datum/sprite_accessory/tails_animated/human/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ color_src = 0
+ icon = 'icons/mob/mam_bodyparts.dmi'
+
/datum/sprite_accessory/ears/human/skunk
name = "skunk"
icon_state = "skunk"
@@ -191,7 +247,7 @@
/datum/sprite_accessory/ears/wolf
name = "Wolf"
icon_state = "wolf"
- extra = 1
+ hasinner = 1
/datum/sprite_accessory/tails/human/wolf
name = "Wolf"
@@ -203,18 +259,6 @@
icon_state = "wolf"
icon = 'icons/mob/mam_bodyparts.dmi'
-/datum/sprite_accessory/tails/human/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
- color_src = 0
- icon = 'icons/mob/mam_bodyparts.dmi'
-
-/datum/sprite_accessory/ears/human/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
- hasinner= 1
- icon = 'icons/mob/mam_bodyparts.dmi'
-
/******************************************
*************** Body Parts ****************
*******************************************/
@@ -248,36 +292,37 @@
name = "Beak"
icon_state = "bird"
icon = 'icons/mob/mam_bodyparts.dmi'
+ color_src = MUTCOLORS3
/datum/sprite_accessory/snouts/lcanid
name = "Fox, Long"
icon_state = "lcanid"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/snouts/scanid
name = "Fox, Short"
icon_state = "scanid"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/snouts/wolf
name = "Wolf"
icon_state = "wolf"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/snouts/husky
name = "Husky"
icon_state = "husky"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/snouts/otie
name = "Otie"
icon_state = "otie"
icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/******************************************
************ Actual Species ***************
@@ -286,31 +331,30 @@
/datum/sprite_accessory/mam_tails/ailurus
name = "Ailurus"
icon_state = "ailurus"
- extra = 1
- extra_color_src = MUTCOLORS2
+ extra = TRUE
/datum/sprite_accessory/mam_tails_animated/ailurus
name = "Ailurus"
icon_state = "ailurus"
- extra = 1
- extra_color_src = MUTCOLORS2
-
-/datum/sprite_accessory/mam_tails/bear
- name = "Bear"
- icon_state = "bear"
- icon = 'icons/mob/mam_bodyparts.dmi'
+ extra = TRUE
/datum/sprite_accessory/mam_ears/bear
name = "Bear"
icon_state = "bear"
- icon = 'icons/mob/mam_bodyparts.dmi'
+
+/datum/sprite_accessory/mam_tails/bear
+ name = "Bear"
+ icon_state = "bear"
+
+/datum/sprite_accessory/mam_tails_animated/bear
+ name = "Bear"
+ icon_state = "bear"
/datum/sprite_accessory/mam_ears/catbig
name = "Cat, Big"
icon_state = "cat"
hasinner = 1
- icon = 'icons/mob/mutant_bodyparts.dmi'
-
+
/datum/sprite_accessory/mam_tails/catbig
name = "Cat, Big"
icon_state = "catbig"
@@ -323,6 +367,14 @@
name = "Cow"
icon_state = "cow"
gender_specific = 1
+
+/datum/sprite_accessory/mam_tail/cow
+ name = "Cow"
+ icon_state = "cow"
+
+/datum/sprite_accessory/mam_tails_animated/cow
+ name = "Cow"
+ icon_state = "cow"
/datum/sprite_accessory/mam_ears/deer
name = "Deer"
@@ -331,8 +383,7 @@
/datum/sprite_accessory/mam_tails/eevee
name = "Eevee"
icon_state = "eevee"
- extra = 1
- extra_color_src = MUTCOLORS2
+ extra = TRUE
/datum/sprite_accessory/mam_ears/eevee
name = "Eevee"
@@ -341,8 +392,7 @@
/datum/sprite_accessory/mam_tails_animated/eevee
name = "Eevee"
icon_state = "eevee"
- extra = 1
- extra_color_src = MUTCOLORS2
+ extra = TRUE
/datum/sprite_accessory/mam_ears/fennec
name = "Fennec"
@@ -360,25 +410,17 @@
/datum/sprite_accessory/mam_ears/fox
name = "Fox"
icon_state = "fox"
- hasinner = 0
+ hasinner = 1
/datum/sprite_accessory/mam_tails/fox
name = "Fox"
icon_state = "fox"
- extra = 1
- extra_color_src = MUTCOLORS2
+ extra = TRUE
/datum/sprite_accessory/mam_tails_animated/fox
name = "Fox"
icon_state = "fox"
- extra = 1
- extra_color_src = MUTCOLORS2
-
-/datum/sprite_accessory/mam_ears/husky
- name = "Husky"
- icon_state = "wolf"
- icon = 'icons/mob/mam_bodyparts.dmi'
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_tails/hawk
name = "Hawk"
@@ -388,20 +430,36 @@
name = "Hawk"
icon_state = "hawk"
+/datum/sprite_accessory/mam_tails/horse
+ name = "Horse"
+ icon_state = "horse"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_tails_animated/horse
+ name = "Horse"
+ icon_state = "Horse"
+ color_src = HAIR
+
+/datum/sprite_accessory/mam_ears/husky
+ name = "Husky"
+ icon_state = "wolf"
+ icon = 'icons/mob/mam_bodyparts.dmi'
+ extra = TRUE
+
/datum/sprite_accessory/mam_tails/husky
name = "Husky"
icon_state = "husky"
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_tails_animated/husky
name = "Husky"
icon_state = "husky"
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_ears/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_tails/kangaroo
name = "kangaroo"
@@ -414,14 +472,12 @@
/datum/sprite_accessory/mam_tails/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = 1
- extra_color_src = MUTCOLORS2
+ extra = TRUE
/datum/sprite_accessory/mam_tails_animated/kitsune
name = "Kitsune"
icon_state = "kitsune"
- extra = 1
- extra_color_src = MUTCOLORS2
+ extra = TRUE
/datum/sprite_accessory/mam_ears/lab
name = "Dog, Long"
@@ -462,6 +518,32 @@
name = "Otusian"
icon_state = "otie"
+/datum/sprite_accessory/mam_ears/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+ hasinner= 1
+
+/datum/sprite_accessory/mam_tails/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_tails_animated/rabbit
+ name = "Rabbit"
+ icon_state = "rabbit"
+
+/datum/sprite_accessory/mam_ears/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+ hasinner= 1
+
+/datum/sprite_accessory/mam_tails/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
+/datum/sprite_accessory/mam_tails_animated/sergal
+ name = "Sergal"
+ icon_state = "sergal"
+
/datum/sprite_accessory/mam_ears/skunk
name = "skunk"
icon_state = "skunk"
@@ -470,13 +552,13 @@
name = "skunk"
icon_state = "skunk"
color_src = 0
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_tails_animated/skunk
name = "skunk"
icon_state = "skunk"
color_src = 0
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_tails/shark
name = "Shark"
@@ -486,19 +568,19 @@
/datum/sprite_accessory/mam_tails_animated/shark
name = "Shark"
icon_state = "shark"
- color_src = 0
+ color_src = MUTCOLORS
/datum/sprite_accessory/mam_tails/shepherd
name = "Shepherd"
icon_state = "shepherd"
- extra = 1
- extra2 = 1
+ extra = TRUE
+ extra2 = TRUE
/datum/sprite_accessory/mam_tails_animated/shepherd
name = "Shepherd"
icon_state = "shepherd"
- extra = 1
- extra2 = 1
+ extra = TRUE
+ extra2 = TRUE
/datum/sprite_accessory/mam_ears/squirrel
name = "Squirrel"
@@ -516,7 +598,7 @@
/datum/sprite_accessory/mam_ears/wolf
name = "Wolf"
icon_state = "wolf"
- extra = 1
+ hasinner = 1
/datum/sprite_accessory/mam_tails/wolf
name = "Wolf"
@@ -526,26 +608,13 @@
name = "Wolf"
icon_state = "wolf"
-/datum/sprite_accessory/mam_tails/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
-
-/datum/sprite_accessory/mam_tails_animated/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
-
-/datum/sprite_accessory/mam_ears/rabbit
- name = "Rabbit"
- icon_state = "rabbit"
- hasinner= 1
-
/******************************************
************ Body Markings ****************
*******************************************/
/datum/sprite_accessory/mam_body_markings
- extra = 1
- extra2 = 1
+ extra = TRUE
+ extra2 = TRUE
icon = 'icons/mob/mam_body_markings.dmi'
/datum/sprite_accessory/mam_body_markings/none
@@ -555,8 +624,6 @@
/datum/sprite_accessory/mam_body_markings/ailurus
name = "Red Panda"
icon_state = "ailurus"
- extra_color_src = MUTCOLORS2
- extra2_color_src = MUTCOLORS3
gender_specific = 1
/datum/sprite_accessory/mam_body_markings/belly
@@ -598,13 +665,11 @@
/datum/sprite_accessory/mam_body_markings/fennec
name = "Fennec"
icon_state = "Fennec"
- extra_color_src = MUTCOLORS3
gender_specific = 1
/datum/sprite_accessory/mam_body_markings/fox
name = "Fox"
icon_state = "fox"
- extra_color_src = MUTCOLORS3
gender_specific = 1
/datum/sprite_accessory/mam_body_markings/hawk
@@ -668,9 +733,9 @@
/datum/sprite_accessory/taur
icon = 'icons/mob/mam_taur.dmi'
extra_icon = 'icons/mob/mam_taur.dmi'
- extra = 1
+ extra = TRUE
extra2_icon = 'icons/mob/mam_taur.dmi'
- extra2 = 1
+ extra2 = TRUE
center = TRUE
dimension_x = 64
@@ -805,19 +870,17 @@
/datum/sprite_accessory/mam_body_markings/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra_color_src = MUTCOLORS2
- extra2_color_src = MUTCOLORS3
gender_specific = 1
/datum/sprite_accessory/mam_tails/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_tails_animated/guilmon
name = "Guilmon"
icon_state = "guilmon"
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_ears/guilmon
name = "Guilmon"
@@ -834,33 +897,33 @@
name = "DataShark"
icon_state = "datashark"
color_src = 0
-
+
/*
//Till I get my snowflake only ckey lock, these are locked-locked :D
/datum/sprite_accessory/mam_ears/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = 1
+ extra = TRUE
extra_color_src = MUTCOLORS3
locked = TRUE
/datum/sprite_accessory/mam_tails/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = 1
+ extra = TRUE
locked = TRUE
/datum/sprite_accessory/mam_tails_animated/sabresune
name = "sabresune"
icon_state = "sabresune"
- extra = 1
+ extra = TRUE
/datum/sprite_accessory/mam_body_markings/sabresune
name = "Sabresune"
icon_state = "sabresune"
color_src = MUTCOLORS2
- extra = 0
- extra2 = 0
+ extra = FALSE
+ extra2 = FALSE
locked = TRUE
*/
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 52650ec273..06f3007e6b 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -1,67 +1,67 @@
-/mob/living/carbon/human/movement_delay()
- . = 0
- . += ..()
- . += config.human_delay
- . += dna.species.movement_delay(src)
-
-/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube)
+/mob/living/carbon/human/movement_delay()
+ . = 0
+ . += ..()
+ . += config.human_delay
+ . += dna.species.movement_delay(src)
+
+/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube)
if(isobj(shoes) && (shoes.flags_1&NOSLIP_1) && !(lube&GALOSHES_DONT_HELP))
- return 0
- return ..()
-
-/mob/living/carbon/human/experience_pressure_difference()
- playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
+ return 0
+ return ..()
+
+/mob/living/carbon/human/experience_pressure_difference()
+ playsound(src, 'sound/effects/space_wind.ogg', 50, 1)
if(shoes && shoes.flags_1&NOSLIP_1)
- return 0
- return ..()
-
-/mob/living/carbon/human/mob_has_gravity()
- . = ..()
- if(!.)
- if(mob_negates_gravity())
- . = 1
-
-/mob/living/carbon/human/mob_negates_gravity()
- return ((shoes && shoes.negates_gravity()) || dna.species.negates_gravity(src))
-
-/mob/living/carbon/human/Move(NewLoc, direct)
- . = ..()
- for(var/datum/mutation/human/HM in dna.mutations)
- HM.on_move(src, NewLoc)
- if(shoes)
- if(!lying && !buckled)
- if(loc == NewLoc)
- if(!has_gravity(loc))
- return
- var/obj/item/clothing/shoes/S = shoes
-
- //Bloody footprints
- var/turf/T = get_turf(src)
- if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
- var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
- if(oldFP && oldFP.blood_state == S.blood_state)
- return
- else
- //No oldFP or it's a different kind of blood
- S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state]-BLOOD_LOSS_PER_STEP)
- var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
- FP.blood_state = S.blood_state
- FP.entered_dirs |= dir
- FP.bloodiness = S.bloody_shoes[S.blood_state]
- if(S.blood_DNA && S.blood_DNA.len)
- FP.transfer_blood_dna(S.blood_DNA)
- FP.update_icon()
- update_inv_shoes()
- //End bloody footprints
-
- S.step_action()
-
-/mob/living/carbon/human/Moved()
- . = ..()
- if(buckled_mobs && buckled_mobs.len && riding_datum)
- riding_datum.on_vehicle_move()
-
-/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
- if(..())
- return 1
- return dna.species.space_move(src)
+ return 0
+ return ..()
+
+/mob/living/carbon/human/mob_has_gravity()
+ . = ..()
+ if(!.)
+ if(mob_negates_gravity())
+ . = 1
+
+/mob/living/carbon/human/mob_negates_gravity()
+ return ((shoes && shoes.negates_gravity()) || dna.species.negates_gravity(src))
+
+/mob/living/carbon/human/Move(NewLoc, direct)
+ . = ..()
+ for(var/datum/mutation/human/HM in dna.mutations)
+ HM.on_move(src, NewLoc)
+
+ if(shoes)
+ if(!lying && !buckled)
+ if(loc == NewLoc)
+ if(!has_gravity(loc))
+ return
+ var/obj/item/clothing/shoes/S = shoes
+
+ //Bloody footprints
+ var/turf/T = get_turf(src)
+ if(S.bloody_shoes && S.bloody_shoes[S.blood_state])
+ var/obj/effect/decal/cleanable/blood/footprints/oldFP = locate(/obj/effect/decal/cleanable/blood/footprints) in T
+ if(oldFP && oldFP.blood_state == S.blood_state)
+ return
+ else
+ //No oldFP or it's a different kind of blood
+ S.bloody_shoes[S.blood_state] = max(0, S.bloody_shoes[S.blood_state]-BLOOD_LOSS_PER_STEP)
+ var/obj/effect/decal/cleanable/blood/footprints/FP = new /obj/effect/decal/cleanable/blood/footprints(T)
+ FP.blood_state = S.blood_state
+ FP.entered_dirs |= dir
+ FP.bloodiness = S.bloody_shoes[S.blood_state]
+ if(S.blood_DNA && S.blood_DNA.len)
+ FP.transfer_blood_dna(S.blood_DNA)
+ FP.update_icon()
+ update_inv_shoes()
+ //End bloody footprints
+
+ S.step_action()
+/mob/living/carbon/human/Moved()
+ . = ..()
+ if(buckled_mobs && buckled_mobs.len && riding_datum)
+ riding_datum.on_vehicle_move()
+
+/mob/living/carbon/human/Process_Spacemove(movement_dir = 0) //Temporary laziness thing. Will change to handles by species reee.
+ if(..())
+ return 1
+ return dna.species.space_move(src)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index d6d6084380..38e13f41d0 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -58,12 +58,14 @@
var/datum/gas_mixture/breath
- if(health <= HEALTH_THRESHOLD_CRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube")))
+ if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL && !getorganslot("breathing_tube")))
losebreath++
+ else if(health <= HEALTH_THRESHOLD_CRIT)
+ losebreath += 0.25
+
//Suffocate
if(losebreath > 0)
- losebreath--
if(prob(10))
emote("gasp")
if(istype(loc, /obj/))
@@ -113,7 +115,9 @@
if(!breath || (breath.total_moles() == 0) || !lungs)
if(reagents.has_reagent("epinephrine") && lungs)
return
- adjustOxyLoss(1)
+ var/oxy_loss = min(losebreath, 1)
+ adjustOxyLoss(oxy_loss)
+ losebreath -= oxy_loss
failed_last_breath = 1
throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
return 0
diff --git a/code/modules/mob/living/carbon/monkey/punpun.dm b/code/modules/mob/living/carbon/monkey/punpun.dm
index 711e771074..52ca8c8226 100644
--- a/code/modules/mob/living/carbon/monkey/punpun.dm
+++ b/code/modules/mob/living/carbon/monkey/punpun.dm
@@ -68,6 +68,6 @@
if(!ancestor_name)
file_data["ancestor_name"] = name
fdel(json_file)
- WRITE_FILE(json_file, json_encode(json_file))
+ WRITE_FILE(json_file, json_encode(file_data))
if(!dead)
memory_saved = 1
\ No newline at end of file
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 522bf5cf57..29022da42d 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -429,6 +429,7 @@
else
return 0
+ var/old_direction = dir
var/atom/movable/pullee = pulling
if(pullee && get_dist(src, pullee) > 1)
stop_pulling()
@@ -444,10 +445,6 @@
var/pull_dir = get_dir(src, pulling)
if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) //puller and pullee more than one tile away or in diagonal position
- if(isliving(pulling))
- var/mob/living/M = pulling
- if(M.lying && !M.buckled && (prob(M.getBruteLoss()*200/M.maxHealth)))
- M.makeTrail(T)
pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up
stop_pulling()
@@ -458,6 +455,10 @@
if (s_active && !(CanReach(s_active,view_only = TRUE)))
s_active.close(src)
+ if(lying && !buckled && prob(getBruteLoss()*200/maxHealth))
+
+ makeTrail(newloc, T, old_direction)
+
/mob/living/movement_delay(ignorewalk = 0)
. = ..()
if(isopenturf(loc) && !is_flying())
@@ -474,31 +475,32 @@
if(MOVE_INTENT_WALK)
. += config.walk_speed
-/mob/living/proc/makeTrail(turf/target_turf)
+/mob/living/proc/makeTrail(turf/target_turf, turf/start, direction)
if(!has_gravity())
return
var/blood_exists = FALSE
- for(var/obj/effect/decal/cleanable/trail_holder/C in loc) //checks for blood splatter already on the floor
+ for(var/obj/effect/decal/cleanable/trail_holder/C in start) //checks for blood splatter already on the floor
blood_exists = TRUE
- if(isturf(loc))
+ if(isturf(start))
var/trail_type = getTrail()
if(trail_type)
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage.
- var/newdir = get_dir(target_turf, loc)
- if(newdir != dir)
- newdir = newdir | dir
+ var/newdir = get_dir(target_turf, start)
+ if(newdir != direction)
+ newdir = newdir | direction
if(newdir == 3) //N + S
newdir = NORTH
else if(newdir == 12) //E + W
newdir = EAST
if((newdir in GLOB.cardinals) && (prob(50)))
- newdir = turn(get_dir(target_turf, loc), 180)
+ newdir = turn(get_dir(target_turf, start), 180)
if(!blood_exists)
- new /obj/effect/decal/cleanable/trail_holder(loc)
- for(var/obj/effect/decal/cleanable/trail_holder/TH in loc)
+ new /obj/effect/decal/cleanable/trail_holder(start)
+
+ for(var/obj/effect/decal/cleanable/trail_holder/TH in start)
if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled)
TH.existing_dirs += newdir
TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir))
diff --git a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm
index 52c06439fb..d41b6f5f29 100644
--- a/code/modules/mob/living/silicon/ai/death.dm
+++ b/code/modules/mob/living/silicon/ai/death.dm
@@ -35,9 +35,9 @@
if(nuking)
set_security_level("red")
nuking = FALSE
- for(var/obj/item/pinpointer/P in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
- P.nuke_warning = FALSE
+ P.alert = FALSE
if(doomsday_device)
doomsday_device.timing = FALSE
diff --git a/code/modules/mob/living/silicon/ai/death.dm.rej b/code/modules/mob/living/silicon/ai/death.dm.rej
new file mode 100644
index 0000000000..40b5625e8c
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/death.dm.rej
@@ -0,0 +1,13 @@
+diff a/code/modules/mob/living/silicon/ai/death.dm b/code/modules/mob/living/silicon/ai/death.dm (rejected hunks)
+@@ -35,9 +35,9 @@
+ if(nuking)
+ set_security_level("red")
+ nuking = FALSE
+- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
+ P.switch_mode_to(TRACK_NUKE_DISK) //Party's over, back to work, everyone
+- P.nuke_warning = FALSE
++ P.alert = FALSE
+
+ if(doomsday_device)
+ doomsday_device.timing = FALSE
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 41fbc69180..af6f3daf92 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -599,7 +599,7 @@
/obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
/obj/item/card/emag,
/obj/item/crowbar/cyborg,
- /obj/item/pinpointer/syndicate/cyborg)
+ /obj/item/pinpointer/syndicate_cyborg)
ratvar_modules = list(
/obj/item/clockwork/slab/cyborg/security,
@@ -625,7 +625,7 @@
/obj/item/roller/robo,
/obj/item/card/emag,
/obj/item/crowbar/cyborg,
- /obj/item/pinpointer/syndicate/cyborg,
+ /obj/item/pinpointer/syndicate_cyborg,
/obj/item/stack/medical/gauze/cyborg,
/obj/item/gun/medbeam)
ratvar_modules = list(
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm.rej b/code/modules/mob/living/silicon/robot/robot_modules.dm.rej
new file mode 100644
index 0000000000..b0f0812dc4
--- /dev/null
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm.rej
@@ -0,0 +1,19 @@
+diff a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm (rejected hunks)
+@@ -519,7 +519,7 @@
+ /obj/item/weapon/gun/ballistic/revolver/grenadelauncher/cyborg,
+ /obj/item/weapon/card/emag,
+ /obj/item/weapon/crowbar/cyborg,
+- /obj/item/weapon/pinpointer/syndicate/cyborg)
++ /obj/item/weapon/pinpointer/syndicate_cyborg)
+
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/security,
+@@ -545,7 +545,7 @@
+ /obj/item/roller/robo,
+ /obj/item/weapon/card/emag,
+ /obj/item/weapon/crowbar/cyborg,
+- /obj/item/weapon/pinpointer/syndicate/cyborg,
++ /obj/item/weapon/pinpointer/syndicate_cyborg,
+ /obj/item/stack/medical/gauze/cyborg,
+ /obj/item/weapon/gun/medbeam)
+ ratvar_modules = list(
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 3b070f1384..b0212e6155 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -874,9 +874,9 @@
occupier.loc = src.loc
occupier.death()
occupier.gib()
- for(var/obj/item/pinpointer/P in GLOB.pinpointer_list)
+ for(var/obj/item/pinpointer/nuke/P in GLOB.pinpointer_list)
P.switch_mode_to(TRACK_NUKE_DISK) //Pinpointers go back to tracking the nuke disk
- P.nuke_warning = FALSE
+ P.alert = FALSE
/obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(card.AI)
diff --git a/code/modules/power/apc.dm.rej b/code/modules/power/apc.dm.rej
new file mode 100644
index 0000000000..9e432f503c
--- /dev/null
+++ b/code/modules/power/apc.dm.rej
@@ -0,0 +1,13 @@
+diff a/code/modules/power/apc.dm b/code/modules/power/apc.dm (rejected hunks)
+@@ -867,9 +867,9 @@
+ occupier.loc = src.loc
+ occupier.death()
+ occupier.gib()
+- for(var/obj/item/weapon/pinpointer/P in GLOB.pinpointer_list)
++ for(var/obj/item/weapon/pinpointer/nuke/P in GLOB.pinpointer_list)
+ P.switch_mode_to(TRACK_NUKE_DISK) //Pinpointers go back to tracking the nuke disk
+- P.nuke_warning = FALSE
++ P.alert = FALSE
+
+ /obj/machinery/power/apc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
+ if(card.AI)
diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm
index e4927349d8..da965aae9d 100644
--- a/code/modules/ruins/lavaland_ruin_code.dm
+++ b/code/modules/ruins/lavaland_ruin_code.dm
@@ -46,71 +46,35 @@
desc = "The incomplete body of a golem. Add ten sheets of any mineral to finish."
var/shell_type = /obj/effect/mob_spawn/human/golem
var/has_owner = FALSE //if the resulting golem obeys someone
- w_class = WEIGHT_CLASS_BULKY
+ w_class = WEIGHT_CLASS_BULKY
/obj/item/golem_shell/attackby(obj/item/I, mob/user, params)
..()
- var/species
- if(istype(I, /obj/item/stack/))
+ var/static/list/golem_shell_species_types = list(
+ /obj/item/stack/sheet/metal = /datum/species/golem,
+ /obj/item/stack/sheet/glass = /datum/species/golem/glass,
+ /obj/item/stack/sheet/plasteel = /datum/species/golem/plasteel,
+ /obj/item/stack/sheet/mineral/sandstone = /datum/species/golem/sand,
+ /obj/item/stack/sheet/mineral/plasma = /datum/species/golem/plasma,
+ /obj/item/stack/sheet/mineral/diamond = /datum/species/golem/diamond,
+ /obj/item/stack/sheet/mineral/gold = /datum/species/golem/gold,
+ /obj/item/stack/sheet/mineral/silver = /datum/species/golem/silver,
+ /obj/item/stack/sheet/mineral/uranium = /datum/species/golem/uranium,
+ /obj/item/stack/sheet/mineral/bananium = /datum/species/golem/bananium,
+ /obj/item/stack/sheet/mineral/titanium = /datum/species/golem/titanium,
+ /obj/item/stack/sheet/mineral/plastitanium = /datum/species/golem/plastitanium,
+ /obj/item/stack/sheet/mineral/abductor = /datum/species/golem/alloy,
+ /obj/item/stack/sheet/mineral/wood = /datum/species/golem/wood,
+ /obj/item/stack/sheet/bluespace_crystal = /datum/species/golem/bluespace,
+ /obj/item/stack/sheet/runed_metal = /datum/species/golem/runic,
+ /obj/item/stack/medical/gauze = /datum/species/golem/cloth,
+ /obj/item/stack/sheet/cloth = /datum/species/golem/cloth,
+ /obj/item/stack/sheet/mineral/adamantine = /datum/species/golem/adamantine,
+ /obj/item/stack/sheet/plastic = /datum/species/golem/plastic)
+
+ if(istype(I, /obj/item/stack))
var/obj/item/stack/O = I
-
- if(istype(O, /obj/item/stack/sheet/metal))
- species = /datum/species/golem
-
- if(istype(O, /obj/item/stack/sheet/glass))
- species = /datum/species/golem/glass
-
- if(istype(O, /obj/item/stack/sheet/plasteel))
- species = /datum/species/golem/plasteel
-
- if(istype(O, /obj/item/stack/sheet/mineral/sandstone))
- species = /datum/species/golem/sand
-
- if(istype(O, /obj/item/stack/sheet/mineral/plasma))
- species = /datum/species/golem/plasma
-
- if(istype(O, /obj/item/stack/sheet/mineral/diamond))
- species = /datum/species/golem/diamond
-
- if(istype(O, /obj/item/stack/sheet/mineral/gold))
- species = /datum/species/golem/gold
-
- if(istype(O, /obj/item/stack/sheet/mineral/silver))
- species = /datum/species/golem/silver
-
- if(istype(O, /obj/item/stack/sheet/mineral/uranium))
- species = /datum/species/golem/uranium
-
- if(istype(O, /obj/item/stack/sheet/mineral/bananium))
- species = /datum/species/golem/bananium
-
- if(istype(O, /obj/item/stack/sheet/mineral/titanium))
- species = /datum/species/golem/titanium
-
- if(istype(O, /obj/item/stack/sheet/mineral/plastitanium))
- species = /datum/species/golem/plastitanium
-
- if(istype(O, /obj/item/stack/sheet/mineral/abductor))
- species = /datum/species/golem/alloy
-
- if(istype(O, /obj/item/stack/sheet/mineral/wood))
- species = /datum/species/golem/wood
-
- if(istype(O, /obj/item/stack/sheet/bluespace_crystal))
- species = /datum/species/golem/bluespace
-
- if(istype(O, /obj/item/stack/sheet/runed_metal))
- species = /datum/species/golem/runic
-
- if(istype(O, /obj/item/stack/medical/gauze) || istype(O, /obj/item/stack/sheet/cloth))
- species = /datum/species/golem/cloth
-
- if(istype(O, /obj/item/stack/sheet/mineral/adamantine))
- species = /datum/species/golem/adamantine
-
- if(istype(O, /obj/item/stack/sheet/plastic))
- species = /datum/species/golem/plastic
-
+ var/species = golem_shell_species_types[O.merge_type]
if(species)
if(O.use(10))
to_chat(user, "You finish up the golem shell with ten sheets of [O].")
diff --git a/html/changelogs/AutoChangeLog-pr-2566.yml b/html/changelogs/AutoChangeLog-pr-2566.yml
new file mode 100644
index 0000000000..6059f590d5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2566.yml
@@ -0,0 +1,5 @@
+author: "Pubby"
+delete-after: True
+changes:
+ - rscadd: "Crew-tracking pinpointers to replace laggy crew monitoring console functionality"
+ - rscadd: "Crew-tracking pinpointers in medical vendors and the detective's office"
diff --git a/html/changelogs/AutoChangeLog-pr-2678.yml b/html/changelogs/AutoChangeLog-pr-2678.yml
new file mode 100644
index 0000000000..cf518a6179
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2678.yml
@@ -0,0 +1,5 @@
+author: "Kor"
+delete-after: True
+changes:
+ - rscadd: "People in soft crit will take oxyloss more slowly than people in full crit if they remain still."
+ - rscadd: "People dragging themselves in critical condition will now leave blood trails. This will rapidly deal oxyloss to you."
diff --git a/html/changelogs/AutoChangeLog-pr-2695.yml b/html/changelogs/AutoChangeLog-pr-2695.yml
new file mode 100644
index 0000000000..64cedc7d0d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-2695.yml
@@ -0,0 +1,7 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - rscadd: "Added Horse and Cow tails"
+ - rscadd: "Added Sergal ears and tails."
+ - tweak: "Fennec Ears a bit cleaner"
+ - tweak: "TRUE/FALSE in Citadel Sprites"
diff --git a/icons/mob/mam_bodyparts.dmi b/icons/mob/mam_bodyparts.dmi
index 8adb82544e..b8491525a7 100644
Binary files a/icons/mob/mam_bodyparts.dmi and b/icons/mob/mam_bodyparts.dmi differ
diff --git a/icons/mob/neck.dmi b/icons/mob/neck.dmi
index 4618dee14b..e7c2d4025d 100644
Binary files a/icons/mob/neck.dmi and b/icons/mob/neck.dmi differ
diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi
index 0f3668ce10..40c4aa03bc 100644
Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 808de69446..79f0a207d4 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/stationobjs.dmi b/icons/obj/stationobjs.dmi
index 28dd158ff7..0f4cda5d8b 100644
Binary files a/icons/obj/stationobjs.dmi and b/icons/obj/stationobjs.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index c38210b6b7..ab1e866b8d 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -798,6 +798,7 @@
#include "code\game\objects\items\mop.dm"
#include "code\game\objects\items\paint.dm"
#include "code\game\objects\items\paiwire.dm"
+#include "code\game\objects\items\pinpointer.dm"
#include "code\game\objects\items\pneumaticCannon.dm"
#include "code\game\objects\items\powerfist.dm"
#include "code\game\objects\items\RCD.dm"
diff --git a/tools/github_webhook_processor.php b/tools/WebhookProcessor/github_webhook_processor.php
similarity index 94%
rename from tools/github_webhook_processor.php
rename to tools/WebhookProcessor/github_webhook_processor.php
index a915c76ad2..0ee66acabf 100644
--- a/tools/github_webhook_processor.php
+++ b/tools/WebhookProcessor/github_webhook_processor.php
@@ -17,33 +17,24 @@
//CONFIG START (all defaults are random examples, do change them)
//Use single quotes for config options that are strings.
-
-//Github lets you have it sign the message with a secret that you can validate. This prevents people from faking events.
-//This var should match the secret you configured for this webhook on github.
-//This is required as otherwise somebody could trick the script into leaking the api key.
+
+//These are all default settings that are described in secret.php
$hookSecret = '08ajh0qj93209qj90jfq932j32r';
-
-$trackPRBalance = true; //set this to false to disable PR balance tracking
-$prBalanceJson = ''; //Set this to the path you'd like the writable pr balance file to be stored, not setting it writes it to the working directory
-$startingPRBalance = 3; //Starting balance for never before seen users
-//team 133041: tgstation/commit-access
-$maintainer_team_id = 133041; //org team id that is exempt from PR balance system, setting this to null will use anyone with write access to the repo. Get from https://api.github.com/orgs/:org/teams
-
-//Api key for pushing changelogs.
$apiKey = '209ab8d879c0f987d06a09b9d879c0f987d06a09b9d8787d0a089c';
-
-//servers to announce PRs to.
+$repoOwnerAndName = "tgstation/tgstation";
$servers = array();
-/*
-$servers[0] = array();
-$servers[0]['address'] = 'game.tgstation13.org';
-$servers[0]['port'] = '1337';
-$servers[0]['comskey'] = '89aj90cq2fm0amc90832mn9rm90';
-$servers[1] = array();
-$servers[1]['address'] = 'game.tgstation13.org';
-$servers[1]['port'] = '2337';
-$servers[1]['comskey'] = '89aj90cq2fm0amc90832mn9rm90';
-*/
+$enable_live_tracking = true;
+$path_to_script = 'tools/WebhookProcessor/github_webhook_processor.php';
+$tracked_branch = "master";
+$trackPRBalance = true;
+$prBalanceJson = '';
+$startingPRBalance = 3;
+$maintainer_team_id = 133041;
+$validation = "org";
+$validation_count = 1;
+$tracked_branch = 'master';
+
+require_once 'secret.php';
//CONFIG END
set_error_handler(function($severity, $message, $file, $line) {
@@ -221,6 +212,7 @@ function handle_pr($payload) {
}
else {
$action = 'merged';
+ auto_update($payload);
checkchangelog($payload, true, true);
update_pr_balance($payload);
$validated = TRUE; //pr merged events always get announced.
@@ -349,6 +341,23 @@ function update_pr_balance($payload) {
fclose($balances_file);
}
+function auto_update($payload){
+ global $enable_live_tracking;
+ global $path_to_script;
+ global $repoOwnerAndName;
+ global $tracked_branch;
+ if(!$enable_live_tracking || !has_tree_been_edited($payload, $path_to_script) || $payload['pull_request']['base']['ref'] != $tracked_branch)
+ return;
+
+ $content = file_get_contents('https://raw.githubusercontent.com/' . $repoOwnerAndName . '/' . $tracked_branch . '/'. $path_to_script);
+
+ create_comment($payload, "Edit detected. Self updating... Here is my new code:\n``" . "`HTML+PHP\n" . $content . "\n``" . '`');
+
+ $code_file = fopen(basename($path_to_script), 'w');
+ fwrite($code_file, $content);
+ fclose($code_file);
+}
+
function has_tree_been_edited($payload, $tree){
//go to the diff url
$url = $payload['pull_request']['diff_url'];
diff --git a/tools/WebhookProcessor/secret.php b/tools/WebhookProcessor/secret.php
new file mode 100644
index 0000000000..abea10564f
--- /dev/null
+++ b/tools/WebhookProcessor/secret.php
@@ -0,0 +1,49 @@
+