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 @@ +