diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt
index 5d3c3ccec2..ce5c2c654d 100644
--- a/SQL/database_changelog.txt
+++ b/SQL/database_changelog.txt
@@ -1,17 +1,114 @@
+
+20th July 2017, by Shadowlight213
+Added role_time table to track time spent playing departments.
+Also, added flags column to the player table.
+
+CREATE TABLE `role_time` ( `ckey` VARCHAR(32) NOT NULL , `job` VARCHAR(128) NOT NULL , `minutes` INT UNSIGNED NOT NULL, PRIMARY KEY (`ckey`, `job`) ) ENGINE = InnoDB;
+
+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?
+
+because:
+15:09 <+MrStonedOne> 1.0 was erro, 2.0 was when i removed erro_, 3.0 was when jordie made all the strings that hold numbers numbers
+
+CREATE TABLE `schema_revision` (
+`major` TINYINT(3) UNSIGNED NOT NULL ,
+`minor` TINYINT(3) UNSIGNED NOT NULL ,
+`date` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
+PRIMARY KEY ( `major`,`minor` )
+) ENGINE = INNODB;
+
+INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 0);
+
+Remember to add a prefix to the table name if you use them.
+
+----------------------------------------------------
+
+26 June 2017, by Jordie0608
+
+Modified table 'poll_option', adding the column 'default_percentage_calc'.
+
+ALTER TABLE `poll_option` ADD COLUMN `default_percentage_calc` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1' AFTER `descmax`
+
+Remember to add a prefix to the table name if you use them.
+
+----------------------------------------------------
+
+22 June 2017, by Jordie0608
+
+Modified table 'poll_option', removing the column 'percentagecalc'.
+
+ALTER TABLE `poll_option` DROP COLUMN `percentagecalc`
+
+Remember to add a prefix to the table name if you use them.
+
+----------------------------------------------------
+
+8 June 2017, by Jordie0608
+
+Modified table 'death', adding column 'round_id', removing column 'gender' and replacing column 'coord' with the columns 'x_coord', 'y_coord' and 'z_coord'.
+
+START TRANSACTION;
+ALTER TABLE `death` DROP COLUMN `gender`, ADD COLUMN `x_coord` SMALLINT(5) UNSIGNED NOT NULL AFTER `coord`, ADD COLUMN `y_coord` SMALLINT(5) UNSIGNED NOT NULL AFTER `x_coord`, ADD COLUMN `z_coord` SMALLINT(5) UNSIGNED NOT NULL AFTER `y_coord`, ADD COLUMN `round_id` INT(11) NOT NULL AFTER `server_port`;
+SET SQL_SAFE_UPDATES = 0;
+UPDATE `death` SET `x_coord` = SUBSTRING_INDEX(`coord`, ',', 1), `y_coord` = SUBSTRING_INDEX(SUBSTRING_INDEX(`coord`, ',', 2), ',', -1), `z_coord` = SUBSTRING_INDEX(`coord`, ',', -1);
+SET SQL_SAFE_UPDATES = 1;
+ALTER TABLE `death` DROP COLUMN `coord`;
+COMMIT;
+
+Remember to add a prefix to the table name if you use them.
+
+---------------------------------------------------
+
+30 May 2017, by MrStonedOne
+
+Z levels changed, this query allows you to convert old ss13 death records:
+
+UPDATE death SET coord = CONCAT(SUBSTRING_INDEX(coord, ',', 2), ', ', CASE TRIM(SUBSTRING_INDEX(coord, ',', -1)) WHEN 1 THEN 2 WHEN 2 THEN 1 ELSE TRIMSUBSTRING_INDEX(coord, ',', -1) END)
+
+---------------------------------------------------
+
+26 May 2017, by Jordie0608
+
+Modified table 'ban', adding the column 'round_id'.
+
+ALTER TABLE `ban` ADD COLUMN `round_id` INT(11) NOT NULL AFTER `server_port`
+
+Remember to add a prefix to the table name if you use them.
+
+----------------------------------------------------
+
20 May 2017, by Jordie0608
Created table `round` to replace tracking of the datapoints 'round_start', 'round_end', 'server_ip', 'game_mode', 'round_end_results', 'end_error', 'end_proper', 'emergency_shuttle', 'map_name' and 'station_renames' in the `feedback` table.
Once created this table is populated with rows from the `feedback` table.
START TRANSACTION;
-CREATE TABLE `feedback`.`round` (`id` INT(11) NOT NULL AUTO_INCREMENT, `start_datetime` DATETIME NOT NULL, `end_datetime` DATETIME NULL, `server_ip` INT(10) UNSIGNED NOT NULL, `server_port` SMALLINT(5) UNSIGNED NOT NULL, `commit_hash` CHAR(40) NULL, `game_mode` VARCHAR(32) NULL, `game_mode_result` VARCHAR(64) NULL, `end_state` VARCHAR(64) NULL, `shuttle_name` VARCHAR(64) NULL, `map_name` VARCHAR(32) NULL, `station_name` VARCHAR(80) NULL, PRIMARY KEY (`id`));
-ALTER TABLE `feedback`.`feedback` ADD INDEX `tmp` (`round_id` ASC, `var_name` ASC);
-INSERT INTO `feedback`.`round`
+CREATE TABLE `round` (`id` INT(11) NOT NULL AUTO_INCREMENT, `start_datetime` DATETIME NOT NULL, `end_datetime` DATETIME NULL, `server_ip` INT(10) UNSIGNED NOT NULL, `server_port` SMALLINT(5) UNSIGNED NOT NULL, `commit_hash` CHAR(40) NULL, `game_mode` VARCHAR(32) NULL, `game_mode_result` VARCHAR(64) NULL, `end_state` VARCHAR(64) NULL, `shuttle_name` VARCHAR(64) NULL, `map_name` VARCHAR(32) NULL, `station_name` VARCHAR(80) NULL, PRIMARY KEY (`id`));
+ALTER TABLE `feedback` ADD INDEX `tmp` (`round_id` ASC, `var_name` ASC);
+INSERT INTO `round`
(`id`, `start_datetime`, `end_datetime`, `server_ip`, `server_port`, `commit_hash`, `game_mode`, `game_mode_result`, `end_state`, `shuttle_name`, `map_name`, `station_name`)
SELECT DISTINCT ri.round_id, IFNULL(STR_TO_DATE(st.details,'%a %b %e %H:%i:%s %Y'), TIMESTAMP(0)), STR_TO_DATE(et.details,'%a %b %e %H:%i:%s %Y'), IFNULL(INET_ATON(SUBSTRING_INDEX(IF(si.details = '', '0', IF(SUBSTRING_INDEX(si.details, ':', 1) LIKE '%_._%', si.details, '0')), ':', 1)), INET_ATON(0)), IFNULL(IF(si.details LIKE '%:_%', CAST(SUBSTRING_INDEX(si.details, ':', -1) AS UNSIGNED), '0'), '0'), ch.details, gm.details, mr.details, IFNULL(es.details, ep.details), ss.details, mn.details, sn.details
-FROM `feedback`.`feedback`AS ri
-LEFT JOIN `feedback`.`feedback` AS st ON ri.round_id = st.round_id AND st.var_name = "round_start" LEFT JOIN `feedback`.`feedback` AS et ON ri.round_id = et.round_id AND et.var_name = "round_end" LEFT JOIN `feedback`.`feedback` AS si ON ri.round_id = si.round_id AND si.var_name = "server_ip" LEFT JOIN `feedback`.`feedback` AS ch ON ri.round_id = ch.round_id AND ch.var_name = "revision" LEFT JOIN `feedback`.`feedback` AS gm ON ri.round_id = gm.round_id AND gm.var_name = "game_mode" LEFT JOIN `feedback`.`feedback` AS mr ON ri.round_id = mr.round_id AND mr.var_name = "round_end_result" LEFT JOIN `feedback`.`feedback` AS es ON ri.round_id = es.round_id AND es.var_name = "end_state" LEFT JOIN `feedback`.`feedback` AS ep ON ri.round_id = ep.round_id AND ep.var_name = "end_proper" LEFT JOIN `feedback`.`feedback` AS ss ON ri.round_id = ss.round_id AND ss.var_name = "emergency_shuttle" LEFT JOIN `feedback`.`feedback` AS mn ON ri.round_id = mn.round_id AND mn.var_name = "map_name" LEFT JOIN `feedback`.`feedback` AS sn ON ri.round_id = sn.round_id AND sn.var_name = "station_renames";
-ALTER TABLE `feedback`.`feedback` DROP INDEX `tmp`;
+FROM `feedback`AS ri
+LEFT JOIN `feedback` AS st ON ri.round_id = st.round_id AND st.var_name = "round_start" LEFT JOIN `feedback` AS et ON ri.round_id = et.round_id AND et.var_name = "round_end" LEFT JOIN `feedback` AS si ON ri.round_id = si.round_id AND si.var_name = "server_ip" LEFT JOIN `feedback` AS ch ON ri.round_id = ch.round_id AND ch.var_name = "revision" LEFT JOIN `feedback` AS gm ON ri.round_id = gm.round_id AND gm.var_name = "game_mode" LEFT JOIN `feedback` AS mr ON ri.round_id = mr.round_id AND mr.var_name = "round_end_result" LEFT JOIN `feedback` AS es ON ri.round_id = es.round_id AND es.var_name = "end_state" LEFT JOIN `feedback` AS ep ON ri.round_id = ep.round_id AND ep.var_name = "end_proper" LEFT JOIN `feedback` AS ss ON ri.round_id = ss.round_id AND ss.var_name = "emergency_shuttle" LEFT JOIN `feedback` AS mn ON ri.round_id = mn.round_id AND mn.var_name = "map_name" LEFT JOIN `feedback` AS sn ON ri.round_id = sn.round_id AND sn.var_name = "station_renames";
+ALTER TABLE `feedback` DROP INDEX `tmp`;
COMMIT;
It's not necessary to delete the rows from the `feedback` table but henceforth these datapoints will be in the `round` table.
@@ -24,19 +121,18 @@ Remember to add a prefix to the table names if you use them
Modified table 'player', adding the column 'accountjoindate', removing the column 'id' and making the column 'ckey' the primary key.
-ALTER TABLE `feedback`.`player` DROP COLUMN `id`, ADD COLUMN `accountjoindate` DATE NULL AFTER `lastadminrank`, DROP PRIMARY KEY, ADD PRIMARY KEY (`ckey`), DROP INDEX `ckey`;
+ALTER TABLE `player` DROP COLUMN `id`, ADD COLUMN `accountjoindate` DATE NULL AFTER `lastadminrank`, DROP PRIMARY KEY, ADD PRIMARY KEY (`ckey`), DROP INDEX `ckey`;
Remember to add a prefix to the table name if you use them.
----------------------------------------------------
-
10 March 2017, by Jordie0608
Modified table 'death', adding the columns 'toxloss', 'cloneloss', and 'staminaloss' and table 'legacy_population', adding the columns 'server_ip' and 'server_port'.
-ALTER TABLE `feedback`.`death` ADD COLUMN `toxloss` SMALLINT(5) UNSIGNED NOT NULL AFTER `oxyloss`, ADD COLUMN `cloneloss` SMALLINT(5) UNSIGNED NOT NULL AFTER `toxloss`, ADD COLUMN `staminaloss` SMALLINT(5) UNSIGNED NOT NULL AFTER `cloneloss`;
+ALTER TABLE `death` ADD COLUMN `toxloss` SMALLINT(5) UNSIGNED NOT NULL AFTER `oxyloss`, ADD COLUMN `cloneloss` SMALLINT(5) UNSIGNED NOT NULL AFTER `toxloss`, ADD COLUMN `staminaloss` SMALLINT(5) UNSIGNED NOT NULL AFTER `cloneloss`;
-ALTER TABLE `feedback`.`legacy_population` ADD COLUMN `server_ip` INT(10) UNSIGNED NOT NULL AFTER `time`, ADD COLUMN `server_port` SMALLINT(5) UNSIGNED NOT NULL AFTER `server_ip`;
+ALTER TABLE `legacy_population` ADD COLUMN `server_ip` INT(10) UNSIGNED NOT NULL AFTER `time`, ADD COLUMN `server_port` SMALLINT(5) UNSIGNED NOT NULL AFTER `server_ip`;
Remember to add a prefix to the table name if you use them.
@@ -68,18 +164,18 @@ Created table 'messages' to supersede the 'notes', 'memos', and 'watchlist' tabl
To create this new table run the following command:
-CREATE TABLE `feedback`.`messages` (`id` INT(11) NOT NULL AUTO_INCREMENT , `type` VARCHAR(32) NOT NULL , `targetckey` VARCHAR(32) NOT NULL , `adminckey` VARCHAR(32) NOT NULL , `text` TEXT NOT NULL , `timestamp` DATETIME NOT NULL , `server` VARCHAR(32) NULL , `secret` TINYINT(1) NULL DEFAULT 1 , `lasteditor` VARCHAR(32) NULL , `edits` TEXT NULL , PRIMARY KEY (`id`) )
+CREATE TABLE `messages` (`id` INT(11) NOT NULL AUTO_INCREMENT , `type` VARCHAR(32) NOT NULL , `targetckey` VARCHAR(32) NOT NULL , `adminckey` VARCHAR(32) NOT NULL , `text` TEXT NOT NULL , `timestamp` DATETIME NOT NULL , `server` VARCHAR(32) NULL , `secret` TINYINT(1) NULL DEFAULT 1 , `lasteditor` VARCHAR(32) NULL , `edits` TEXT NULL , PRIMARY KEY (`id`) )
To copy the contents of the 'notes', 'memos', and 'watchlist' tables to this new table run the following commands:
-INSERT INTO `feedback`.`messages`
-(`id`,`type`,`targetckey`,`adminckey`,`text`,`timestamp`,`server`,`secret`,`lasteditor`,`edits`) SELECT `id`, "note", `ckey`, `adminckey`, `notetext`, `timestamp`, `server`, `secret`, `last_editor`, `edits` FROM `feedback`.`notes`
+INSERT INTO `messages`
+(`id`,`type`,`targetckey`,`adminckey`,`text`,`timestamp`,`server`,`secret`,`lasteditor`,`edits`) SELECT `id`, "note", `ckey`, `adminckey`, `notetext`, `timestamp`, `server`, `secret`, `last_editor`, `edits` FROM `notes`
-INSERT INTO `feedback`.`messages`
-(`type`,`targetckey`,`adminckey`,`text`,`timestamp`,`lasteditor`,`edits`) SELECT "memo", `ckey`, `ckey`, `memotext`, `timestamp`, `last_editor`, `edits` FROM `feedback`.`memo`
+INSERT INTO `messages`
+(`type`,`targetckey`,`adminckey`,`text`,`timestamp`,`lasteditor`,`edits`) SELECT "memo", `ckey`, `ckey`, `memotext`, `timestamp`, `last_editor`, `edits` FROM `memo`
-INSERT INTO `feedback`.`messages`
-(`type`,`targetckey`,`adminckey`,`text`,`timestamp`,`lasteditor`,`edits`) SELECT "watchlist entry", `ckey`, `adminckey`, `reason`, `timestamp`, `last_editor`, `edits` FROM `feedback`.`watch`
+INSERT INTO `messages`
+(`type`,`targetckey`,`adminckey`,`text`,`timestamp`,`lasteditor`,`edits`) SELECT "watchlist entry", `ckey`, `adminckey`, `reason`, `timestamp`, `last_editor`, `edits` FROM `watch`
It's not necessary to delete the 'notes', 'memos', and 'watchlist' tables but they will no longer be used.
@@ -91,7 +187,7 @@ Remember to add a prefix to the table names if you use them
Modified table 'notes', adding column 'secret'.
-ALTER TABLE `feedback`.`notes` ADD COLUMN `secret` TINYINT(1) NOT NULL DEFAULT '1' AFTER `server`
+ALTER TABLE `notes` ADD COLUMN `secret` TINYINT(1) NOT NULL DEFAULT '1' AFTER `server`
Remember to add a prefix to the table name if you use them
@@ -101,7 +197,7 @@ Remember to add a prefix to the table name if you use them
Changed appearance bans to be jobbans.
-UPDATE 'feedback'.`ban` SET `job` = "appearance", `bantype` = "JOB_PERMABAN" WHERE `bantype` = "APPEARANCE_PERMABAN"
+UPDATE `ban` SET `job` = "appearance", `bantype` = "JOB_PERMABAN" WHERE `bantype` = "APPEARANCE_PERMABAN"
Remember to add a prefix to the table name if you use them
@@ -111,7 +207,7 @@ Remember to add a prefix to the table name if you use them
Modified table 'poll_question', adding column 'dontshow' which was recently added to the server schema.
-ALTER TABLE `feedback`.`poll_question` ADD COLUMN `dontshow` TINYINT(1) NOT NULL DEFAULT '0' AFTER `for_trialmin`
+ALTER TABLE `poll_question` ADD COLUMN `dontshow` TINYINT(1) NOT NULL DEFAULT '0' AFTER `for_trialmin`
Remember to add a prefix to the table name if you use them
@@ -121,7 +217,7 @@ Remember to add a prefix to the table name if you use them
Added ipintel table, only required if ip intel is enabled in the config
-CREATE TABLE `ipintel` (
+CREATE TABLE `ipintel` (
`ip` INT UNSIGNED NOT NULL ,
`date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL ,
`intel` REAL NOT NULL DEFAULT '0',
@@ -134,7 +230,7 @@ PRIMARY KEY ( `ip` )
Modified table 'poll_question', adding columns 'createdby_ckey', 'createdby_ip' and 'for_trialmin' to bring it inline with the schema used by the tg servers.
-ALTER TABLE `feedback`.`poll_question` ADD COLUMN `createdby_ckey` VARCHAR(45) NULL DEFAULT NULL AFTER `multiplechoiceoptions`, ADD COLUMN `createdby_ip` VARCHAR(45) NULL DEFAULT NULL AFTER `createdby_ckey`, ADD COLUMN `for_trialmin` VARCHAR(45) NULL DEFAULT NULL AFTER `createdby_ip`
+ALTER TABLE `poll_question` ADD COLUMN `createdby_ckey` VARCHAR(45) NULL DEFAULT NULL AFTER `multiplechoiceoptions`, ADD COLUMN `createdby_ip` VARCHAR(45) NULL DEFAULT NULL AFTER `createdby_ckey`, ADD COLUMN `for_trialmin` VARCHAR(45) NULL DEFAULT NULL AFTER `createdby_ip`
Remember to add a prefix to the table name if you use them
@@ -144,7 +240,7 @@ Remember to add a prefix to the table name if you use them
Modified table 'watch', removing 'id' column, making 'ckey' primary and adding the columns 'timestamp', 'adminckey', 'last_editor' and 'edits'.
-ALTER TABLE `feedback`.`watch` DROP COLUMN `id`, ADD COLUMN `timestamp` datetime NOT NULL AFTER `reason`, ADD COLUMN `adminckey` varchar(32) NOT NULL AFTER `timestamp`, ADD COLUMN `last_editor` varchar(32) NULL AFTER `adminckey`, ADD COLUMN `edits` text NULL AFTER `last_editor`, DROP PRIMARY KEY, ADD PRIMARY KEY (`ckey`)
+ALTER TABLE `watch` DROP COLUMN `id`, ADD COLUMN `timestamp` datetime NOT NULL AFTER `reason`, ADD COLUMN `adminckey` varchar(32) NOT NULL AFTER `timestamp`, ADD COLUMN `last_editor` varchar(32) NULL AFTER `adminckey`, ADD COLUMN `edits` text NULL AFTER `last_editor`, DROP PRIMARY KEY, ADD PRIMARY KEY (`ckey`)
Remember to add a prefix to the table name if you use them.
@@ -166,7 +262,7 @@ Remember to add prefix to the table name if you use them.
Modified table 'memo', removing 'id' column and making 'ckey' primary.
-ALTER TABLE `feedback`.`memo` DROP COLUMN `id`, DROP PRIMARY KEY, ADD PRIMARY KEY (`ckey`)
+ALTER TABLE `memo` DROP COLUMN `id`, DROP PRIMARY KEY, ADD PRIMARY KEY (`ckey`)
Remember to add prefix to the table name if you use them.
diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql
index 4c76e1f275..9795b90672 100644
--- a/SQL/tgstation_schema.sql
+++ b/SQL/tgstation_schema.sql
@@ -1,6 +1,3 @@
-CREATE DATABASE IF NOT EXISTS `feedback` /*!40100 DEFAULT CHARACTER SET latin1 */;
-USE `feedback`;
-
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
@@ -74,6 +71,7 @@ CREATE TABLE `ban` (
`bantime` datetime NOT NULL,
`server_ip` int(10) unsigned NOT NULL,
`server_port` smallint(5) unsigned NOT NULL,
+ `round_id` int(11) NOT NULL,
`bantype` enum('PERMABAN','TEMPBAN','JOB_PERMABAN','JOB_TEMPBAN','ADMIN_PERMABAN','ADMIN_TEMPBAN') NOT NULL,
`reason` varchar(2048) NOT NULL,
`job` varchar(32) DEFAULT NULL,
@@ -119,7 +117,6 @@ CREATE TABLE `connection_log` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
-
--
-- Table structure for table `death`
--
@@ -136,7 +133,7 @@ CREATE TABLE `death` (
`mapname` varchar(32) NOT NULL,
`server_ip` int(10) unsigned NOT NULL,
`server_port` smallint(5) unsigned NOT NULL,
- `round_id` int(11) NOT NULL
+ `round_id` int(11) NOT NULL,
`tod` datetime NOT NULL COMMENT 'Time of death',
`job` varchar(32) NOT NULL,
`special` varchar(32) DEFAULT NULL,
@@ -155,7 +152,6 @@ CREATE TABLE `death` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
-
--
-- Table structure for table `feedback`
--
@@ -257,6 +253,21 @@ CREATE TABLE `messages` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `role_time`
+--
+
+DROP TABLE IF EXISTS `role_time`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+
+CREATE TABLE `role_time`
+( `ckey` VARCHAR(32) NOT NULL ,
+ `job` VARCHAR(32) NOT NULL ,
+ `minutes` INT UNSIGNED NOT NULL,
+ PRIMARY KEY (`ckey`, `job`)
+ ) ENGINE = InnoDB;
+
--
-- Table structure for table `player`
--
@@ -272,6 +283,7 @@ CREATE TABLE `player` (
`computerid` varchar(32) NOT NULL,
`lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
`accountjoindate` DATE DEFAULT NULL,
+ `flags` smallint(5) unsigned DEFAULT '0' NOT NULL,
PRIMARY KEY (`ckey`),
KEY `idx_player_cid_ckey` (`computerid`,`ckey`),
KEY `idx_player_ip_ckey` (`ip`,`ckey`)
@@ -289,12 +301,12 @@ CREATE TABLE `poll_option` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pollid` int(11) NOT NULL,
`text` varchar(255) NOT NULL,
- `percentagecalc` tinyint(1) NOT NULL DEFAULT '1',
`minval` int(3) DEFAULT NULL,
`maxval` int(3) DEFAULT NULL,
`descmin` varchar(32) DEFAULT NULL,
`descmid` varchar(32) DEFAULT NULL,
`descmax` varchar(32) DEFAULT NULL,
+ `default_percentage_calc` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `idx_pop_pollid` (`pollid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@@ -391,6 +403,17 @@ CREATE TABLE `round` (
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+--
+-- Table structure for table `schema_revision`
+--
+DROP TABLE IF EXISTS `schema_revision`;
+CREATE TABLE `schema_revision` (
+ `major` TINYINT(3) unsigned NOT NULL,
+ `minor` TINYINT(3) unsigned NOT NULL,
+ `date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`major`, `minor`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
diff --git a/SQL/tgstation_schema.sql.rej b/SQL/tgstation_schema.sql.rej
new file mode 100644
index 0000000000..51068bed4e
--- /dev/null
+++ b/SQL/tgstation_schema.sql.rej
@@ -0,0 +1,9 @@
+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 f717bf96ad..b810a82ca3 100644
--- a/SQL/tgstation_schema_prefixed.sql
+++ b/SQL/tgstation_schema_prefixed.sql
@@ -1,6 +1,3 @@
-CREATE DATABASE IF NOT EXISTS `feedback` /*!40100 DEFAULT CHARACTER SET latin1 */;
-USE `feedback`;
-
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
@@ -74,6 +71,7 @@ CREATE TABLE `SS13_ban` (
`bantime` datetime NOT NULL,
`server_ip` int(10) unsigned NOT NULL,
`server_port` smallint(5) unsigned NOT NULL,
+ `round_id` int(11) NOT NULL,
`bantype` enum('PERMABAN','TEMPBAN','JOB_PERMABAN','JOB_TEMPBAN','ADMIN_PERMABAN','ADMIN_TEMPBAN') NOT NULL,
`reason` varchar(2048) NOT NULL,
`job` varchar(32) DEFAULT NULL,
@@ -129,10 +127,13 @@ DROP TABLE IF EXISTS `SS13_death`;
CREATE TABLE `SS13_death` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pod` varchar(50) NOT NULL,
- `coord` varchar(32) NOT NULL,
+ `x_coord` smallint(5) unsigned NOT NULL,
+ `y_coord` smallint(5) unsigned NOT NULL,
+ `z_coord` smallint(5) unsigned NOT NULL,
`mapname` varchar(32) NOT NULL,
`server_ip` int(10) unsigned NOT NULL,
`server_port` smallint(5) unsigned NOT NULL,
+ `round_id` int(11) NOT NULL,
`tod` datetime NOT NULL COMMENT 'Time of death',
`job` varchar(32) NOT NULL,
`special` varchar(32) DEFAULT NULL,
@@ -140,7 +141,6 @@ CREATE TABLE `SS13_death` (
`byondkey` varchar(32) NOT NULL,
`laname` varchar(96) DEFAULT NULL,
`lakey` varchar(32) DEFAULT NULL,
- `gender` enum('neuter','male','female','plural') NOT NULL,
`bruteloss` smallint(5) unsigned NOT NULL,
`brainloss` smallint(5) unsigned NOT NULL,
`fireloss` smallint(5) unsigned NOT NULL,
@@ -253,6 +253,21 @@ CREATE TABLE `SS13_messages` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `SS13_role_time`
+--
+
+DROP TABLE IF EXISTS `SS13_role_time`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+
+CREATE TABLE `SS13_role_time`
+( `ckey` VARCHAR(32) NOT NULL ,
+ `job` VARCHAR(32) NOT NULL ,
+ `minutes` INT UNSIGNED NOT NULL,
+ PRIMARY KEY (`ckey`, `job`)
+ ) ENGINE = InnoDB;
+
--
-- Table structure for table `SS13_player`
--
@@ -268,6 +283,7 @@ CREATE TABLE `SS13_player` (
`computerid` varchar(32) NOT NULL,
`lastadminrank` varchar(32) NOT NULL DEFAULT 'Player',
`accountjoindate` DATE DEFAULT NULL,
+ `flags` smallint(5) unsigned DEFAULT '0' NOT NULL,
PRIMARY KEY (`ckey`),
KEY `idx_player_cid_ckey` (`computerid`,`ckey`),
KEY `idx_player_ip_ckey` (`ip`,`ckey`)
@@ -285,12 +301,12 @@ CREATE TABLE `SS13_poll_option` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pollid` int(11) NOT NULL,
`text` varchar(255) NOT NULL,
- `percentagecalc` tinyint(1) NOT NULL DEFAULT '1',
`minval` int(3) DEFAULT NULL,
`maxval` int(3) DEFAULT NULL,
`descmin` varchar(32) DEFAULT NULL,
`descmid` varchar(32) DEFAULT NULL,
`descmax` varchar(32) DEFAULT NULL,
+ `default_percentage_calc` tinyint(1) unsigned NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `idx_pop_pollid` (`pollid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@@ -387,6 +403,17 @@ CREATE TABLE `SS13_round` (
/*!40101 SET character_set_client = @saved_cs_client */;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+--
+-- Table structure for table `SS13_schema_revision`
+--
+DROP TABLE IF EXISTS `SS13_schema_revision`;
+CREATE TABLE `SS13_schema_revision` (
+ `major` TINYINT(3) unsigned NOT NULL,
+ `minor` TINYINT(3) unsigned NOT NULL,
+ `date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ PRIMARY KEY (`major`,`minor`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
diff --git a/SQL/tgstation_schema_prefixed.sql.rej b/SQL/tgstation_schema_prefixed.sql.rej
new file mode 100644
index 0000000000..dd4bc6a7f5
--- /dev/null
+++ b/SQL/tgstation_schema_prefixed.sql.rej
@@ -0,0 +1,9 @@
+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/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index f26b750492..b6133df287 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -47,4 +47,22 @@
#define SEC_DEPT_ENGINEERING "Engineering"
#define SEC_DEPT_MEDICAL "Medical"
#define SEC_DEPT_SCIENCE "Science"
-#define SEC_DEPT_SUPPLY "Supply"
\ No newline at end of file
+#define SEC_DEPT_SUPPLY "Supply"
+
+// Playtime tracking system, see jobs_exp.dm
+#define EXP_TYPE_LIVING "Living"
+#define EXP_TYPE_CREW "Crew"
+#define EXP_TYPE_COMMAND "Command"
+#define EXP_TYPE_ENGINEERING "Engineering"
+#define EXP_TYPE_MEDICAL "Medical"
+#define EXP_TYPE_SCIENCE "Science"
+#define EXP_TYPE_SUPPLY "Supply"
+#define EXP_TYPE_SECURITY "Security"
+#define EXP_TYPE_SILICON "Silicon"
+#define EXP_TYPE_SERVICE "Service"
+#define EXP_TYPE_ANTAG "Antag"
+#define EXP_TYPE_SPECIAL "Special"
+#define EXP_TYPE_GHOST "Ghost"
+
+//Flags in the players table in the db
+#define DB_FLAG_EXEMPT 1
\ No newline at end of file
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index c1f02856a7..54459da0b5 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -72,4 +72,4 @@
//Update this whenever the db schema changes
//make sure you add an update to the schema_version stable in the db changelog
#define DB_MAJOR_VERSION 3
-#define DB_MINOR_VERSION 0
+#define DB_MINOR_VERSION 1
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 43b523fcd1..1d8f7add38 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -103,6 +103,13 @@
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/use_exp_tracking = FALSE
+ var/use_exp_restrictions_heads = FALSE
+ var/use_exp_restrictions_heads_hours = 0
+ var/use_exp_restrictions_heads_department = FALSE
+ var/use_exp_restrictions_other = FALSE
+ var/use_exp_restrictions_admin_bypass = FALSE
+
//Population cap vars
var/soft_popcap = 0
var/hard_popcap = 0
@@ -337,6 +344,18 @@
use_age_restriction_for_jobs = 1
if("use_account_age_for_jobs")
use_account_age_for_jobs = 1
+ if("use_exp_tracking")
+ use_exp_tracking = TRUE
+ if("use_exp_restrictions_heads")
+ use_exp_restrictions_heads = TRUE
+ if("use_exp_restrictions_heads_hours")
+ use_exp_restrictions_heads_hours = text2num(value)
+ if("use_exp_restrictions_heads_department")
+ use_exp_restrictions_heads_department = TRUE
+ if("use_exp_restrictions_other")
+ use_exp_restrictions_other = TRUE
+ if("use_exp_restrictions_admin_bypass")
+ use_exp_restrictions_admin_bypass = TRUE
if("lobby_countdown")
lobby_countdown = text2num(value)
if("round_end_countdown")
diff --git a/code/controllers/configuration.dm.rej b/code/controllers/configuration.dm.rej
new file mode 100644
index 0000000000..5d5c2c5055
--- /dev/null
+++ b/code/controllers/configuration.dm.rej
@@ -0,0 +1,24 @@
+diff a/code/controllers/configuration.dm b/code/controllers/configuration.dm (rejected hunks)
+@@ -337,17 +337,17 @@
+ if("use_account_age_for_jobs")
+ use_account_age_for_jobs = 1
+ if("use_exp_tracking")
+- use_exp_tracking = 1
++ use_exp_tracking = TRUE
+ if("use_exp_restrictions_heads")
+- use_exp_restrictions_heads = 1
++ use_exp_restrictions_heads = TRUE
+ if("use_exp_restrictions_heads_hours")
+ use_exp_restrictions_heads_hours = text2num(value)
+ if("use_exp_restrictions_heads_department")
+- use_exp_restrictions_heads_department = 1
++ use_exp_restrictions_heads_department = TRUE
+ if("use_exp_restrictions_other")
+- use_exp_restrictions_other = 1
++ use_exp_restrictions_other = TRUE
+ if("use_exp_restrictions_admin_bypass")
+- use_exp_restrictions_admin_bypass = 1
++ use_exp_restrictions_admin_bypass = TRUE
+ if("lobby_countdown")
+ lobby_countdown = text2num(value)
+ if("round_end_countdown")
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 74536c7f0f..b85e99a0b9 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -1,269 +1,285 @@
-SUBSYSTEM_DEF(blackbox)
- name = "Blackbox"
- wait = 6000
- flags = SS_NO_TICK_CHECK | SS_NO_INIT
- runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
- init_order = INIT_ORDER_BLACKBOX
-
- var/list/msg_common = list()
- var/list/msg_science = list()
- var/list/msg_command = list()
- var/list/msg_medical = list()
- var/list/msg_engineering = list()
- var/list/msg_security = list()
- var/list/msg_deathsquad = list()
- var/list/msg_syndicate = list()
- var/list/msg_service = list()
- var/list/msg_cargo = list()
- var/list/msg_other = list()
-
- var/list/feedback = list() //list of datum/feedback_variable
-
- var/sealed = FALSE //time to stop tracking stats?
-
-//poll population
-/datum/controller/subsystem/blackbox/fire()
- if(!SSdbcore.Connect())
- return
- var/playercount = 0
- for(var/mob/M in GLOB.player_list)
- if(M.client)
- playercount += 1
- var/admincount = GLOB.admins.len
- var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
- query_record_playercount.Execute()
-
-/datum/controller/subsystem/blackbox/Recover()
- msg_common = SSblackbox.msg_common
- msg_science = SSblackbox.msg_science
- msg_command = SSblackbox.msg_command
- msg_medical = SSblackbox.msg_medical
- msg_engineering = SSblackbox.msg_engineering
- msg_security = SSblackbox.msg_security
- msg_deathsquad = SSblackbox.msg_deathsquad
- msg_syndicate = SSblackbox.msg_syndicate
- msg_service = SSblackbox.msg_service
- msg_cargo = SSblackbox.msg_cargo
- msg_other = SSblackbox.msg_other
-
- feedback = SSblackbox.feedback
-
- sealed = SSblackbox.sealed
-
-//no touchie
-/datum/controller/subsystem/blackbox/can_vv_get(var_name)
- if(var_name == "feedback")
- return FALSE
- return ..()
-
-/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
- return FALSE
-
-/datum/controller/subsystem/blackbox/Shutdown()
- sealed = FALSE
- set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len)
-
- var/pda_msg_amt = 0
- var/rc_msg_amt = 0
-
- for (var/obj/machinery/message_server/MS in GLOB.message_servers)
- if (MS.pda_msgs.len > pda_msg_amt)
- pda_msg_amt = MS.pda_msgs.len
- if (MS.rc_msgs.len > rc_msg_amt)
- rc_msg_amt = MS.rc_msgs.len
-
- set_details("radio_usage","")
-
- add_details("radio_usage","COM-[msg_common.len]")
- add_details("radio_usage","SCI-[msg_science.len]")
- add_details("radio_usage","HEA-[msg_command.len]")
- add_details("radio_usage","MED-[msg_medical.len]")
- add_details("radio_usage","ENG-[msg_engineering.len]")
- add_details("radio_usage","SEC-[msg_security.len]")
- add_details("radio_usage","DTH-[msg_deathsquad.len]")
- add_details("radio_usage","SYN-[msg_syndicate.len]")
- add_details("radio_usage","SRV-[msg_service.len]")
- add_details("radio_usage","CAR-[msg_cargo.len]")
- add_details("radio_usage","OTH-[msg_other.len]")
- add_details("radio_usage","PDA-[pda_msg_amt]")
- add_details("radio_usage","RC-[rc_msg_amt]")
-
- if (!SSdbcore.Connect())
- return
-
- var/list/sqlrowlist = list()
-
- for (var/datum/feedback_variable/FV in feedback)
- sqlrowlist += list(list("time" = "Now()", "round_id" = GLOB.round_id, "var_name" = "'[sanitizeSQL(FV.get_variable())]'", "var_value" = FV.get_value(), "details" = "'[sanitizeSQL(FV.get_details())]'"))
-
- if (!length(sqlrowlist))
- return
-
- SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
-
-
-/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
- if(sealed)
- return
- switch(freq)
- if(1459)
- msg_common += blackbox_msg
- if(1351)
- msg_science += blackbox_msg
- if(1353)
- msg_command += blackbox_msg
- if(1355)
- msg_medical += blackbox_msg
- if(1357)
- msg_engineering += blackbox_msg
- if(1359)
- msg_security += blackbox_msg
- if(1441)
- msg_deathsquad += blackbox_msg
- if(1213)
- msg_syndicate += blackbox_msg
- if(1349)
- msg_service += blackbox_msg
- if(1347)
- msg_cargo += blackbox_msg
- else
- msg_other += blackbox_msg
-
-/datum/controller/subsystem/blackbox/proc/find_feedback_datum(variable)
- for(var/datum/feedback_variable/FV in feedback)
- if(FV.get_variable() == variable)
- return FV
-
- var/datum/feedback_variable/FV = new(variable)
- feedback += FV
- return FV
-
-/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
- if(sealed)
- return
- var/datum/feedback_variable/FV = find_feedback_datum(variable)
- FV.set_value(value)
-
-/datum/controller/subsystem/blackbox/proc/inc(variable, value)
- if(sealed)
- return
- var/datum/feedback_variable/FV = find_feedback_datum(variable)
- FV.inc(value)
-
-/datum/controller/subsystem/blackbox/proc/dec(variable,value)
- if(sealed)
- return
- var/datum/feedback_variable/FV = find_feedback_datum(variable)
- FV.dec(value)
-
-/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
- if(sealed)
- return
- var/datum/feedback_variable/FV = find_feedback_datum(variable)
- FV.set_details(details)
-
-/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
- if(sealed)
- return
- var/datum/feedback_variable/FV = find_feedback_datum(variable)
- FV.add_details(details)
-
-/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
- if(sealed)
- return
- if(!SSdbcore.Connect())
- return
- if(!L || !L.key || !L.mind)
- return
- var/turf/T = get_turf(L)
- var/area/placeofdeath = get_area(T.loc)
- var/sqlname = sanitizeSQL(L.real_name)
- var/sqlkey = sanitizeSQL(L.ckey)
- var/sqljob = sanitizeSQL(L.mind.assigned_role)
- var/sqlspecial = sanitizeSQL(L.mind.special_role)
- var/sqlpod = sanitizeSQL(placeofdeath.name)
- var/laname
- var/lakey
- if(L.lastattacker && ismob(L.lastattacker))
- var/mob/LA = L.lastattacker
- laname = sanitizeSQL(LA.real_name)
- lakey = sanitizeSQL(LA.key)
- var/sqlbrute = sanitizeSQL(L.getBruteLoss())
- var/sqlfire = sanitizeSQL(L.getFireLoss())
- var/sqlbrain = sanitizeSQL(L.getBrainLoss())
- var/sqloxy = sanitizeSQL(L.getOxyLoss())
- var/sqltox = sanitizeSQL(L.getToxLoss())
- var/sqlclone = sanitizeSQL(L.getCloneLoss())
- var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
- var/x_coord = sanitizeSQL(L.x)
- var/y_coord = sanitizeSQL(L.y)
- var/z_coord = sanitizeSQL(L.z)
- var/map = sanitizeSQL(SSmapping.config.map_name)
- var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina])")
- query_report_death.Execute()
-
-/datum/controller/subsystem/blackbox/proc/Seal()
- if(sealed)
- return
- if(IsAdminAdvancedProcCall())
- var/msg = "[key_name_admin(usr)] sealed the blackbox!"
- message_admins(msg)
- log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
- sealed = TRUE
-
-//feedback variable datum, for storing all kinds of data
-/datum/feedback_variable
- var/variable
- var/value
- var/details
-
-/datum/feedback_variable/New(param_variable, param_value = 0)
- variable = param_variable
- value = param_value
-
-/datum/feedback_variable/proc/inc(num = 1)
- if (isnum(value))
- value += num
- else
- value = text2num(value)
- if (isnum(value))
- value += num
- else
- value = num
-
-/datum/feedback_variable/proc/dec(num = 1)
- if (isnum(value))
- value -= num
- else
- value = text2num(value)
- if (isnum(value))
- value -= num
- else
- value = -num
-
-/datum/feedback_variable/proc/set_value(num)
- if (isnum(num))
- value = num
-
-/datum/feedback_variable/proc/get_value()
- if (!isnum(value))
- return 0
- return value
-
-/datum/feedback_variable/proc/get_variable()
- return variable
-
-/datum/feedback_variable/proc/set_details(deets)
- details = "\"[deets]\""
+SUBSYSTEM_DEF(blackbox)
+ name = "Blackbox"
+ wait = 6000
+ flags = SS_NO_TICK_CHECK
+ runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
+ init_order = INIT_ORDER_BLACKBOX
-/datum/feedback_variable/proc/add_details(deets)
- if (!details)
- set_details(deets)
+ var/list/msg_common = list()
+ var/list/msg_science = list()
+ var/list/msg_command = list()
+ var/list/msg_medical = list()
+ var/list/msg_engineering = list()
+ var/list/msg_security = list()
+ var/list/msg_deathsquad = list()
+ var/list/msg_syndicate = list()
+ var/list/msg_service = list()
+ var/list/msg_cargo = list()
+ var/list/msg_other = list()
+
+ var/list/feedback = list() //list of datum/feedback_variable
+
+ var/triggertime = 0
+ var/sealed = FALSE //time to stop tracking stats?
+
+
+/datum/controller/subsystem/blackbox/Initialize()
+ triggertime = world.time
+ . = ..()
+
+
+//poll population
+/datum/controller/subsystem/blackbox/fire()
+ if(!SSdbcore.Connect())
+ return
+ var/playercount = 0
+ for(var/mob/M in GLOB.player_list)
+ if(M.client)
+ playercount += 1
+ var/admincount = GLOB.admins.len
+ var/datum/DBQuery/query_record_playercount = SSdbcore.NewQuery("INSERT INTO [format_table_name("legacy_population")] (playercount, admincount, time, server_ip, server_port) VALUES ([playercount], [admincount], '[SQLtime()]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]')")
+ query_record_playercount.Execute()
+
+
+ if(config.use_exp_tracking)
+ if((triggertime < 0) || (world.time > (triggertime +3000))) //subsystem fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire. The <0 is midnight rollover check
+ update_exp(10,FALSE)
+
+
+
+/datum/controller/subsystem/blackbox/Recover()
+ msg_common = SSblackbox.msg_common
+ msg_science = SSblackbox.msg_science
+ msg_command = SSblackbox.msg_command
+ msg_medical = SSblackbox.msg_medical
+ msg_engineering = SSblackbox.msg_engineering
+ msg_security = SSblackbox.msg_security
+ msg_deathsquad = SSblackbox.msg_deathsquad
+ msg_syndicate = SSblackbox.msg_syndicate
+ msg_service = SSblackbox.msg_service
+ msg_cargo = SSblackbox.msg_cargo
+ msg_other = SSblackbox.msg_other
+
+ feedback = SSblackbox.feedback
+
+ sealed = SSblackbox.sealed
+
+//no touchie
+/datum/controller/subsystem/blackbox/can_vv_get(var_name)
+ if(var_name == "feedback")
+ return FALSE
+ return ..()
+
+/datum/controller/subsystem/blackbox/vv_edit_var(var_name, var_value)
+ return FALSE
+
+/datum/controller/subsystem/blackbox/Shutdown()
+ sealed = FALSE
+ set_val("ahelp_unresolved", GLOB.ahelp_tickets.active_tickets.len)
+
+ var/pda_msg_amt = 0
+ var/rc_msg_amt = 0
+
+ for (var/obj/machinery/message_server/MS in GLOB.message_servers)
+ if (MS.pda_msgs.len > pda_msg_amt)
+ pda_msg_amt = MS.pda_msgs.len
+ if (MS.rc_msgs.len > rc_msg_amt)
+ rc_msg_amt = MS.rc_msgs.len
+
+ set_details("radio_usage","")
+
+ add_details("radio_usage","COM-[msg_common.len]")
+ add_details("radio_usage","SCI-[msg_science.len]")
+ add_details("radio_usage","HEA-[msg_command.len]")
+ add_details("radio_usage","MED-[msg_medical.len]")
+ add_details("radio_usage","ENG-[msg_engineering.len]")
+ add_details("radio_usage","SEC-[msg_security.len]")
+ add_details("radio_usage","DTH-[msg_deathsquad.len]")
+ add_details("radio_usage","SYN-[msg_syndicate.len]")
+ add_details("radio_usage","SRV-[msg_service.len]")
+ add_details("radio_usage","CAR-[msg_cargo.len]")
+ add_details("radio_usage","OTH-[msg_other.len]")
+ add_details("radio_usage","PDA-[pda_msg_amt]")
+ add_details("radio_usage","RC-[rc_msg_amt]")
+
+ if (!SSdbcore.Connect())
+ return
+
+ var/list/sqlrowlist = list()
+
+ for (var/datum/feedback_variable/FV in feedback)
+ sqlrowlist += list(list("time" = "Now()", "round_id" = GLOB.round_id, "var_name" = "'[sanitizeSQL(FV.get_variable())]'", "var_value" = FV.get_value(), "details" = "'[sanitizeSQL(FV.get_details())]'"))
+
+ if (!length(sqlrowlist))
+ return
+
+ SSdbcore.MassInsert(format_table_name("feedback"), sqlrowlist, ignore_errors = TRUE, delayed = TRUE)
+
+
+/datum/controller/subsystem/blackbox/proc/LogBroadcast(blackbox_msg, freq)
+ if(sealed)
+ return
+ switch(freq)
+ if(1459)
+ msg_common += blackbox_msg
+ if(1351)
+ msg_science += blackbox_msg
+ if(1353)
+ msg_command += blackbox_msg
+ if(1355)
+ msg_medical += blackbox_msg
+ if(1357)
+ msg_engineering += blackbox_msg
+ if(1359)
+ msg_security += blackbox_msg
+ if(1441)
+ msg_deathsquad += blackbox_msg
+ if(1213)
+ msg_syndicate += blackbox_msg
+ if(1349)
+ msg_service += blackbox_msg
+ if(1347)
+ msg_cargo += blackbox_msg
+ else
+ msg_other += blackbox_msg
+
+/datum/controller/subsystem/blackbox/proc/find_feedback_datum(variable)
+ for(var/datum/feedback_variable/FV in feedback)
+ if(FV.get_variable() == variable)
+ return FV
+
+ var/datum/feedback_variable/FV = new(variable)
+ feedback += FV
+ return FV
+
+/datum/controller/subsystem/blackbox/proc/set_val(variable, value)
+ if(sealed)
+ return
+ var/datum/feedback_variable/FV = find_feedback_datum(variable)
+ FV.set_value(value)
+
+/datum/controller/subsystem/blackbox/proc/inc(variable, value)
+ if(sealed)
+ return
+ var/datum/feedback_variable/FV = find_feedback_datum(variable)
+ FV.inc(value)
+
+/datum/controller/subsystem/blackbox/proc/dec(variable,value)
+ if(sealed)
+ return
+ var/datum/feedback_variable/FV = find_feedback_datum(variable)
+ FV.dec(value)
+
+/datum/controller/subsystem/blackbox/proc/set_details(variable,details)
+ if(sealed)
+ return
+ var/datum/feedback_variable/FV = find_feedback_datum(variable)
+ FV.set_details(details)
+
+/datum/controller/subsystem/blackbox/proc/add_details(variable,details)
+ if(sealed)
+ return
+ var/datum/feedback_variable/FV = find_feedback_datum(variable)
+ FV.add_details(details)
+
+/datum/controller/subsystem/blackbox/proc/ReportDeath(mob/living/L)
+ if(sealed)
+ return
+ if(!SSdbcore.Connect())
+ return
+ if(!L || !L.key || !L.mind)
+ return
+ var/turf/T = get_turf(L)
+ var/area/placeofdeath = get_area(T.loc)
+ var/sqlname = sanitizeSQL(L.real_name)
+ var/sqlkey = sanitizeSQL(L.ckey)
+ var/sqljob = sanitizeSQL(L.mind.assigned_role)
+ var/sqlspecial = sanitizeSQL(L.mind.special_role)
+ var/sqlpod = sanitizeSQL(placeofdeath.name)
+ var/laname
+ var/lakey
+ if(L.lastattacker && ismob(L.lastattacker))
+ var/mob/LA = L.lastattacker
+ laname = sanitizeSQL(LA.real_name)
+ lakey = sanitizeSQL(LA.key)
+ var/sqlbrute = sanitizeSQL(L.getBruteLoss())
+ var/sqlfire = sanitizeSQL(L.getFireLoss())
+ var/sqlbrain = sanitizeSQL(L.getBrainLoss())
+ var/sqloxy = sanitizeSQL(L.getOxyLoss())
+ var/sqltox = sanitizeSQL(L.getToxLoss())
+ var/sqlclone = sanitizeSQL(L.getCloneLoss())
+ var/sqlstamina = sanitizeSQL(L.getStaminaLoss())
+ var/x_coord = sanitizeSQL(L.x)
+ var/y_coord = sanitizeSQL(L.y)
+ var/z_coord = sanitizeSQL(L.z)
+ var/map = sanitizeSQL(SSmapping.config.map_name)
+ var/datum/DBQuery/query_report_death = SSdbcore.NewQuery("INSERT INTO [format_table_name("death")] (pod, x_coord, y_coord, z_coord, mapname, server_ip, server_port, round_id, tod, job, special, name, byondkey, laname, lakey, bruteloss, fireloss, brainloss, oxyloss, toxloss, cloneloss, staminaloss) VALUES ('[sqlpod]', '[x_coord]', '[y_coord]', '[z_coord]', '[map]', INET_ATON(IF('[world.internet_address]' LIKE '', '0', '[world.internet_address]')), '[world.port]', [GLOB.round_id], '[SQLtime()]', '[sqljob]', '[sqlspecial]', '[sqlname]', '[sqlkey]', '[laname]', '[lakey]', [sqlbrute], [sqlfire], [sqlbrain], [sqloxy], [sqltox], [sqlclone], [sqlstamina])")
+ query_report_death.Execute()
+
+/datum/controller/subsystem/blackbox/proc/Seal()
+ if(sealed)
+ return
+ if(IsAdminAdvancedProcCall())
+ var/msg = "[key_name_admin(usr)] sealed the blackbox!"
+ message_admins(msg)
+ log_game("Blackbox sealed[IsAdminAdvancedProcCall() ? " by [key_name(usr)]" : ""].")
+ sealed = TRUE
+
+//feedback variable datum, for storing all kinds of data
+/datum/feedback_variable
+ var/variable
+ var/value
+ var/details
+
+/datum/feedback_variable/New(param_variable, param_value = 0)
+ variable = param_variable
+ value = param_value
+
+/datum/feedback_variable/proc/inc(num = 1)
+ if (isnum(value))
+ value += num
else
- details += " | \"[deets]\""
-
-/datum/feedback_variable/proc/get_details()
- return details
-
-/datum/feedback_variable/proc/get_parsed()
+ value = text2num(value)
+ if (isnum(value))
+ value += num
+ else
+ value = num
+
+/datum/feedback_variable/proc/dec(num = 1)
+ if (isnum(value))
+ value -= num
+ else
+ value = text2num(value)
+ if (isnum(value))
+ value -= num
+ else
+ value = -num
+
+/datum/feedback_variable/proc/set_value(num)
+ if (isnum(num))
+ value = num
+
+/datum/feedback_variable/proc/get_value()
+ if (!isnum(value))
+ return 0
+ return value
+
+/datum/feedback_variable/proc/get_variable()
+ return variable
+
+/datum/feedback_variable/proc/set_details(text)
+ if (istext(text))
+ details = text
+
+/datum/feedback_variable/proc/add_details(text)
+ if (istext(text))
+ if (!details)
+ details = "\"[text]\""
+ else
+ details += " | \"[text]\""
+
+/datum/feedback_variable/proc/get_details()
+ return details
+
+/datum/feedback_variable/proc/get_parsed()
return list(variable,value,details)
\ No newline at end of file
diff --git a/code/controllers/subsystem/blackbox.dm.rej b/code/controllers/subsystem/blackbox.dm.rej
new file mode 100644
index 0000000000..5bd713172b
--- /dev/null
+++ b/code/controllers/subsystem/blackbox.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm (rejected hunks)
+@@ -40,7 +40,7 @@ SUBSYSTEM_DEF(blackbox)
+
+ if(config.use_exp_tracking)
+ if((triggertime < 0) || (world.time > (triggertime +3000))) //subsystem fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire. The <0 is midnight rollover check
+- SSblackbox.update_exp(10,FALSE)
++ update_exp(10,FALSE)
+
+
+ /datum/controller/subsystem/blackbox/Recover()
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index 012c2e33af..d64739698a 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -73,6 +73,8 @@ SUBSYSTEM_DEF(job)
return 0
if(!job.player_old_enough(player.client))
return 0
+ if(job.required_playtime_remaining(player.client))
+ return 0
var/position_limit = job.total_positions
if(!latejoin)
position_limit = job.spawn_positions
@@ -95,6 +97,9 @@ SUBSYSTEM_DEF(job)
if(!job.player_old_enough(player.client))
Debug("FOC player not old enough, Player: [player]")
continue
+ if(job.required_playtime_remaining(player.client))
+ Debug("FOC player not enough xp, Player: [player]")
+ continue
if(flag && (!(flag in player.client.prefs.be_special)))
Debug("FOC flag failed, Player: [player], Flag: [flag], ")
continue
@@ -130,6 +135,10 @@ SUBSYSTEM_DEF(job)
Debug("GRJ player not old enough, Player: [player]")
continue
+ if(job.required_playtime_remaining(player.client))
+ Debug("GRJ player not enough xp, Player: [player]")
+ continue
+
if(player.mind && job.title in player.mind.restricted_roles)
Debug("GRJ incompatible with antagonist role, Player: [player], Job: [job.title]")
continue
@@ -300,6 +309,10 @@ SUBSYSTEM_DEF(job)
Debug("DO player not old enough, Player: [player], Job:[job.title]")
continue
+ if(job.required_playtime_remaining(player.client))
+ Debug("DO player not enough xp, Player: [player], Job:[job.title]")
+ continue
+
if(player.mind && job.title in player.mind.restricted_roles)
Debug("DO incompatible with antagonist role, Player: [player], Job:[job.title]")
continue
@@ -463,6 +476,9 @@ SUBSYSTEM_DEF(job)
if(!job.player_old_enough(player.client))
level6++
continue
+ if(job.required_playtime_remaining(player.client))
+ level6++
+ continue
if(player.client.prefs.GetJobDepartment(job, 1) & job.flag)
level1++
else if(player.client.prefs.GetJobDepartment(job, 2) & job.flag)
diff --git a/code/controllers/subsystem/server_maint.dm.rej b/code/controllers/subsystem/server_maint.dm.rej
new file mode 100644
index 0000000000..486375b505
--- /dev/null
+++ b/code/controllers/subsystem/server_maint.dm.rej
@@ -0,0 +1,30 @@
+diff a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm (rejected hunks)
+@@ -6,18 +6,16 @@ SUBSYSTEM_DEF(server_maint)
+ flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
+ priority = 10
+ var/list/currentrun
+- var/triggertime = null
+
+ /datum/controller/subsystem/server_maint/Initialize(timeofday)
+ if (config.hub)
+ world.visibility = 1
+- triggertime = REALTIMEOFDAY
+ ..()
+
+ /datum/controller/subsystem/server_maint/fire(resumed = FALSE)
+ if(!resumed)
+ src.currentrun = GLOB.clients.Copy()
+-
++
+ var/list/currentrun = src.currentrun
+ var/round_started = SSticker.HasRoundStarted()
+
+@@ -39,8 +37,3 @@ SUBSYSTEM_DEF(server_maint)
+ return
+
+ #undef PING_BUFFER_TIME
+- if(config.sql_enabled)
+- sql_poll_population()
+- if(config.use_exp_tracking)
+- if(REALTIMEOFDAY > (triggertime +3000)) //server maint fires once at roundstart then once every 10 minutes. a 5 min check skips the first fire
+- update_exp(10,0)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 66e0a1f922..78a402a2dc 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -1481,6 +1481,7 @@
if(!(src in SSticker.mode.syndicates))
SSticker.mode.syndicates += src
SSticker.mode.update_synd_icons_added(src)
+ assigned_role = "Syndicate"
special_role = "Syndicate"
SSticker.mode.forge_syndicate_objectives(src)
SSticker.mode.greet_syndicate(src)
@@ -1728,7 +1729,7 @@
/mob/living/carbon/human/mind_initialize()
..()
if(!mind.assigned_role)
- mind.assigned_role = "Assistant" //defualt
+ mind.assigned_role = "Unassigned" //default
//XENO
/mob/living/carbon/alien/mind_initialize()
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index a485bc2d1a..ab9c041efe 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -108,6 +108,7 @@
new_objective.explanation_text = "Protect [usr.real_name], the wizard."
M.mind.objectives += new_objective
SSticker.mode.apprentices += M.mind
+ M.mind.assigned_role = "Apprentice"
M.mind.special_role = "apprentice"
SSticker.mode.update_wiz_icons_added(M.mind)
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
diff --git a/code/game/gamemodes/antag_spawner.dm.rej b/code/game/gamemodes/antag_spawner.dm.rej
new file mode 100644
index 0000000000..ea9a00132a
--- /dev/null
+++ b/code/game/gamemodes/antag_spawner.dm.rej
@@ -0,0 +1,9 @@
+diff a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm (rejected hunks)
+@@ -108,6 +108,7 @@
+ new_objective.explanation_text = "Protect [usr.real_name], the wizard."
+ M.mind.objectives += new_objective
+ SSticker.mode.apprentices += M.mind
++ M.mind.assigned_role = "Apprentice"
+ M.mind.special_role = "apprentice"
+ SSticker.mode.update_wiz_icons_added(M.mind)
+ M << sound('sound/effects/magic.ogg')
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 5943e753a0..b88451b724 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -31,6 +31,8 @@
if(M.client)
body += " played by [M.client] "
body += "\[[M.client.holder ? M.client.holder.rank : "Player"]\]"
+ if(config.use_exp_tracking)
+ body += "\[" + M.client.get_exp_living() + "\]"
if(isnewplayer(M))
body += " Hasn't Entered Game "
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 5507d856f6..f8e5c31687 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -61,6 +61,7 @@ GLOBAL_LIST_INIT(admin_verbs_admin, world.AVerbsAdmin())
/client/proc/cmd_admin_local_narrate, /*sends text to all mobs within view of atom*/
/client/proc/cmd_admin_create_centcom_report,
/client/proc/cmd_change_command_name,
+ /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
/client/proc/toggle_antag_hud, /*toggle display of the admin antag hud*/
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
/client/proc/customiseSNPC, /* Customise any interactive crewmembers in the world */
diff --git a/code/modules/admin/admin_verbs.dm.rej b/code/modules/admin/admin_verbs.dm.rej
new file mode 100644
index 0000000000..c2f884d37c
--- /dev/null
+++ b/code/modules/admin/admin_verbs.dm.rej
@@ -0,0 +1,10 @@
+diff a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm (rejected hunks)
+@@ -663,7 +664,7 @@ GLOBAL_LIST_INIT(admin_verbs_hideable, AVerbsHideable())
+
+ if(!holder)
+ return
+-
++
+ if(has_antag_hud())
+ toggle_antag_hud()
+
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index f3de43b6c6..f7aa6caaf6 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -22,6 +22,24 @@
else if(href_list["stickyban"])
stickyban(href_list["stickyban"],href_list)
+ else if(href_list["getplaytimewindow"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/mob/M = locate(href_list["getplaytimewindow"]) in GLOB.mob_list
+ if(!M)
+ to_chat(usr, "ERROR: Mob not found.")
+ return
+ cmd_show_exp_panel(M.client)
+
+ else if(href_list["toggleexempt"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/client/C = locate(href_list["toggleexempt"]) in GLOB.clients
+ if(!C)
+ to_chat(usr, "ERROR: Client not found.")
+ return
+ toggle_exempt_status(C)
+
else if(href_list["makeAntag"])
if (!SSticker.mode)
to_chat(usr, "Not until the round starts!")
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 3d89cd49f5..62f3cab1d1 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -1,1213 +1,1260 @@
-/client/proc/cmd_admin_drop_everything(mob/M in GLOB.mob_list)
- set category = null
- set name = "Drop Everything"
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/confirm = alert(src, "Make [M] drop everything?", "Message", "Yes", "No")
- if(confirm != "Yes")
- return
-
- for(var/obj/item/W in M)
- if(!M.dropItemToGround(W))
- qdel(W)
- M.regenerate_icons()
-
- log_admin("[key_name(usr)] made [key_name(M)] drop everything!")
- var/msg = "[key_name_admin(usr)] made [key_name_admin(M)] drop everything!"
- message_admins(msg)
- admin_ticket_log(M, msg)
- SSblackbox.add_details("admin_verb","Drop Everything") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list)
- set category = "Special Verbs"
- set name = "Subtle Message"
-
- if(!ismob(M))
- return
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- message_admins("[key_name_admin(src)] has started answering [key_name(M.key, 0, 0)]'s prayer.")
- var/msg = input("Message:", text("Subtle PM to [M.key]")) as text
-
- if (!msg)
- message_admins("[key_name_admin(src)] decided not to answer [key_name(M.key, 0, 0)]'s prayer")
- return
- if(usr)
- if (usr.client)
- if(usr.client.holder)
- to_chat(M, "You hear a voice in your head... [msg]")
-
- log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]")
- msg = " SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]"
- message_admins(msg)
- admin_ticket_log(M, msg)
- SSblackbox.add_details("admin_verb","Subtle Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_world_narrate()
- set category = "Special Verbs"
- set name = "Global Narrate"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/msg = input("Message:", text("Enter the text you wish to appear to everyone:")) as text
-
- if (!msg)
- return
- to_chat(world, "[msg]")
- log_admin("GlobalNarrate: [key_name(usr)] : [msg]")
- message_admins("[key_name_admin(usr)] Sent a global narrate")
- SSblackbox.add_details("admin_verb","Global Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_direct_narrate(mob/M)
- set category = "Special Verbs"
- set name = "Direct Narrate"
-
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- if(!M)
- M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list
-
- if(!M)
- return
-
- var/msg = input("Message:", text("Enter the text you wish to appear to your target:")) as text
-
- if( !msg )
- return
-
- to_chat(M, msg)
- log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]")
- msg = " DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
"
- message_admins(msg)
- admin_ticket_log(M, msg)
- SSblackbox.add_details("admin_verb","Direct Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_local_narrate(atom/A)
- set category = "Special Verbs"
- set name = "Local Narrate"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- if(!A)
- return
- var/range = input("Range:", "Narrate to mobs within how many tiles:", 7) as num
- if(!range)
- return
- var/msg = input("Message:", text("Enter the text you wish to appear to everyone within view:")) as text
- if (!msg)
- return
- for(var/mob/M in view(range,A))
- to_chat(M, msg)
-
- log_admin("LocalNarrate: [key_name(usr)] at [get_area(A)][COORD(A)]: [msg]")
- message_admins(" LocalNarrate: [key_name_admin(usr)] at [get_area(A)][ADMIN_JMP(A)]: [msg]
")
- SSblackbox.add_details("admin_verb","Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list)
- set category = "Special Verbs"
- set name = "Godmode"
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- M.status_flags ^= GODMODE
- to_chat(usr, "Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]")
-
- log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]")
- var/msg = "[key_name_admin(usr)] has toggled [key_name_admin(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]"
- message_admins(msg)
- admin_ticket_log(M, msg)
- SSblackbox.add_details("admin_toggle","Godmode|[M.status_flags & GODMODE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-
-/proc/cmd_admin_mute(whom, mute_type, automute = 0)
- if(!whom)
- return
-
- var/muteunmute
- var/mute_string
- var/feedback_string
- switch(mute_type)
- if(MUTE_IC)
- mute_string = "IC (say and emote)"
- feedback_string = "IC"
- if(MUTE_OOC)
- mute_string = "OOC"
- feedback_string = "OOC"
- if(MUTE_PRAY)
- mute_string = "pray"
- feedback_string = "Pray"
- if(MUTE_ADMINHELP)
- mute_string = "adminhelp, admin PM and ASAY"
- feedback_string = "Adminhelp"
- if(MUTE_DEADCHAT)
- mute_string = "deadchat and DSAY"
- feedback_string = "Deadchat"
- if(MUTE_ALL)
- mute_string = "everything"
- feedback_string = "Everything"
- else
- return
-
- var/client/C
- if(istype(whom, /client))
- C = whom
- else if(istext(whom))
- C = GLOB.directory[whom]
- else
- return
-
- var/datum/preferences/P
- if(C)
- P = C.prefs
- else
- P = GLOB.preferences_datums[whom]
- if(!P)
- return
-
- if(automute)
- if(!config.automute_on)
- return
- else
- if(!check_rights())
- return
-
- if(automute)
- muteunmute = "auto-muted"
- P.muted |= mute_type
- log_admin("SPAM AUTOMUTE: [muteunmute] [key_name(whom)] from [mute_string]")
- message_admins("SPAM AUTOMUTE: [muteunmute] [key_name_admin(whom)] from [mute_string].")
- if(C)
- to_chat(C, "You have been [muteunmute] from [mute_string] by the SPAM AUTOMUTE system. Contact an admin.")
- SSblackbox.add_details("admin_toggle","Auto Mute [feedback_string]|1") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- return
-
- if(P.muted & mute_type)
- muteunmute = "unmuted"
- P.muted &= ~mute_type
- else
- muteunmute = "muted"
- P.muted |= mute_type
-
- log_admin("[key_name(usr)] has [muteunmute] [key_name(whom)] from [mute_string]")
- message_admins("[key_name_admin(usr)] has [muteunmute] [key_name_admin(whom)] from [mute_string].")
- if(C)
- to_chat(C, "You have been [muteunmute] from [mute_string] by [key_name(usr, include_name = FALSE)].")
- SSblackbox.add_details("admin_toggle","Mute [feedback_string]|[P.muted & mute_type]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-
-//I use this proc for respawn character too. /N
-/proc/create_xeno(ckey)
- if(!ckey)
- var/list/candidates = list()
- for(var/mob/M in GLOB.player_list)
- if(M.stat != DEAD)
- continue //we are not dead!
- if(!(ROLE_ALIEN in M.client.prefs.be_special))
- continue //we don't want to be an alium
- if(M.client.is_afk())
- continue //we are afk
- if(M.mind && M.mind.current && M.mind.current.stat != DEAD)
- continue //we have a live body we are tied to
- candidates += M.ckey
- if(candidates.len)
- ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in candidates
- else
- to_chat(usr, "Error: create_xeno(): no suitable candidates.")
- if(!istext(ckey))
- return 0
-
- var/alien_caste = input(usr, "Please choose which caste to spawn.","Pick a caste",null) as null|anything in list("Queen","Praetorian","Hunter","Sentinel","Drone","Larva")
- var/obj/effect/landmark/spawn_here = GLOB.xeno_spawn.len ? pick(GLOB.xeno_spawn) : null
- var/mob/living/carbon/alien/new_xeno
- switch(alien_caste)
- if("Queen")
- new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(spawn_here)
- if("Praetorian")
- new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(spawn_here)
- if("Hunter")
- new_xeno = new /mob/living/carbon/alien/humanoid/hunter(spawn_here)
- if("Sentinel")
- new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(spawn_here)
- if("Drone")
- new_xeno = new /mob/living/carbon/alien/humanoid/drone(spawn_here)
- if("Larva")
- new_xeno = new /mob/living/carbon/alien/larva(spawn_here)
- else
- return 0
- if(!spawn_here)
- SSjob.SendToLateJoin(new_xeno, FALSE)
-
- new_xeno.ckey = ckey
- var/msg = "[key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste]."
- message_admins(msg)
- admin_ticket_log(new_xeno, msg)
- return 1
-
-/*
-If a guy was gibbed and you want to revive him, this is a good way to do so.
-Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one.
-Traitors and the like can also be revived with the previous role mostly intact.
-/N */
-/client/proc/respawn_character()
- set category = "Special Verbs"
- set name = "Respawn Character"
- set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into."
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", ""))
- if(!input)
- return
-
- var/mob/dead/observer/G_found
- for(var/mob/dead/observer/G in GLOB.player_list)
- if(G.ckey == input)
- G_found = G
- break
-
- if(!G_found)//If a ghost was not found.
- to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.")
- return
-
- if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something
- //Check if they were an alien
- if(G_found.mind.assigned_role=="Alien")
- if(alert("This character appears to have been an alien. Would you like to respawn them as such?",,"Yes","No")=="Yes")
- var/turf/T
- if(GLOB.xeno_spawn.len)
- T = pick(GLOB.xeno_spawn)
-
- var/mob/living/carbon/alien/new_xeno
- switch(G_found.mind.special_role)//If they have a mind, we can determine which caste they were.
- if("Hunter")
- new_xeno = new /mob/living/carbon/alien/humanoid/hunter(T)
- if("Sentinel")
- new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(T)
- if("Drone")
- new_xeno = new /mob/living/carbon/alien/humanoid/drone(T)
- if("Praetorian")
- new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(T)
- if("Queen")
- new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(T)
- else//If we don't know what special role they have, for whatever reason, or they're a larva.
- create_xeno(G_found.ckey)
- return
-
- if(!T)
- SSjob.SendToLateJoin(new_xeno, FALSE)
-
- //Now to give them their mind back.
- G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use
- new_xeno.key = G_found.key
- to_chat(new_xeno, "You have been fully respawned. Enjoy the game.")
- var/msg = "[key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno."
- message_admins(msg)
- admin_ticket_log(new_xeno, msg)
- return //all done. The ghost is auto-deleted
-
- //check if they were a monkey
- else if(findtext(G_found.real_name,"monkey"))
- if(alert("This character appears to have been a monkey. Would you like to respawn them as such?",,"Yes","No")=="Yes")
- var/mob/living/carbon/monkey/new_monkey = new
- SSjob.SendToLateJoin(new_monkey)
- G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use
- new_monkey.key = G_found.key
- to_chat(new_monkey, "You have been fully respawned. Enjoy the game.")
- var/msg = "[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy xeno."
- message_admins(msg)
- admin_ticket_log(new_monkey, msg)
- return //all done. The ghost is auto-deleted
-
-
- //Ok, it's not a xeno or a monkey. So, spawn a human.
- var/mob/living/carbon/human/new_character = new//The mob being spawned.
- SSjob.SendToLateJoin(new_character)
-
- var/datum/data/record/record_found //Referenced to later to either randomize or not randomize the character.
- if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something
- /*Try and locate a record for the person being respawned through GLOB.data_core.
- This isn't an exact science but it does the trick more often than not.*/
- var/id = md5("[G_found.real_name][G_found.mind.assigned_role]")
-
- record_found = find_record("id", id, GLOB.data_core.locked)
-
- if(record_found)//If they have a record we can determine a few things.
- new_character.real_name = record_found.fields["name"]
- new_character.gender = record_found.fields["sex"]
- new_character.age = record_found.fields["age"]
- new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], record_found.fields["species"], record_found.fields["features"])
- else
- var/datum/preferences/A = new()
- A.copy_to(new_character)
- A.real_name = G_found.real_name
- new_character.dna.update_dna_identity()
-
- new_character.name = new_character.real_name
-
- if(G_found.mind && !G_found.mind.active)
- G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use
- else
- new_character.mind_initialize()
- if(!new_character.mind.assigned_role)
- new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role.
-
- new_character.key = G_found.key
-
- /*
- The code below functions with the assumption that the mob is already a traitor if they have a special role.
- So all it does is re-equip the mob with powers and/or items. Or not, if they have no special role.
- If they don't have a mind, they obviously don't have a special role.
- */
-
- //Two variables to properly announce later on.
- var/admin = key_name_admin(src)
- var/player_key = G_found.key
-
- //Now for special roles and equipment.
- var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(ANTAG_DATUM_TRAITOR)
- if(traitordatum)
- SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)
- traitordatum.equip()
-
-
- switch(new_character.mind.special_role)
- if("Wizard")
- new_character.loc = pick(GLOB.wizardstart)
- //SSticker.mode.learn_basic_spells(new_character)
- SSticker.mode.equip_wizard(new_character)
- if("Syndicate")
- var/obj/effect/landmark/synd_spawn = locate("landmark*Syndicate-Spawn")
- if(synd_spawn)
- new_character.loc = get_turf(synd_spawn)
- call(/datum/game_mode/proc/equip_syndicate)(new_character)
- if("Space Ninja")
- var/list/ninja_spawn = list()
- for(var/obj/effect/landmark/L in GLOB.landmarks_list)
- if(L.name=="carpspawn")
- ninja_spawn += L
- var/datum/antagonist/ninja/ninjadatum = new_character.mind.has_antag_datum(ANTAG_DATUM_NINJA)
- ninjadatum.equip_space_ninja()
- if(ninja_spawn.len)
- var/obj/effect/landmark/ninja_spawn_here = pick(ninja_spawn)
- new_character.loc = ninja_spawn_here.loc
-
- else//They may also be a cyborg or AI.
- switch(new_character.mind.assigned_role)
- if("Cyborg")//More rigging to make em' work and check if they're traitor.
- new_character = new_character.Robotize()
- if("AI")
- new_character = new_character.AIize()
- else
- SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)//Or we simply equip them.
-
- //Announces the character on all the systems, based on the record.
- if(!issilicon(new_character))//If they are not a cyborg/AI.
- if(!record_found&&new_character.mind.assigned_role!=new_character.mind.special_role)//If there are no records for them. If they have a record, this info is already in there. MODE people are not announced anyway.
- //Power to the user!
- if(alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,"No","Yes")=="Yes")
- GLOB.data_core.manifest_inject(new_character)
-
- if(alert(new_character,"Would you like an active AI to announce this character?",,"No","Yes")=="Yes")
- AnnounceArrival(new_character, new_character.mind.assigned_role)
-
- var/msg = "[admin] has respawned [player_key] as [new_character.real_name]."
- message_admins(msg)
- admin_ticket_log(new_character, msg)
-
- to_chat(new_character, "You have been fully respawned. Enjoy the game.")
-
- SSblackbox.add_details("admin_verb","Respawn Character") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- return new_character
-
-/client/proc/cmd_admin_add_freeform_ai_law()
- set category = "Fun"
- set name = "Add Custom AI law"
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- var/input = input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null
- if(!input)
- return
-
- log_admin("Admin [key_name(usr)] has added a new AI law - [input]")
- message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]")
-
- var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No")
- var/announce_ion_laws = (show_log == "Yes" ? 1 : -1)
-
- var/datum/round_event/ion_storm/add_law_only/ion = new()
- ion.announceEvent = announce_ion_laws
- ion.ionMessage = input
-
- SSblackbox.add_details("admin_verb","Add Custom AI Law") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_rejuvenate(mob/living/M in GLOB.mob_list)
- set category = "Special Verbs"
- set name = "Rejuvenate"
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- if(!mob)
- return
- if(!istype(M))
- alert("Cannot revive a ghost")
- return
- M.revive(full_heal = 1, admin_revive = 1)
-
- log_admin("[key_name(usr)] healed / revived [key_name(M)]")
- var/msg = "Admin [key_name_admin(usr)] healed / revived [key_name_admin(M)]!"
- message_admins(msg)
- admin_ticket_log(M, msg)
- SSblackbox.add_details("admin_verb","Rejuvinate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_create_centcom_report()
- set category = "Special Verbs"
- set name = "Create Command Report"
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- var/input = input(usr, "Please enter anything you want. Anything. Serious.", "What?", "") as message|null
- if(!input)
- return
-
- var/confirm = alert(src, "Do you want to announce the contents of the report to the crew?", "Announce", "Yes", "No", "Cancel")
- var/announce_command_report = TRUE
- switch(confirm)
- if("Yes")
- priority_announce(input, null, 'sound/ai/commandreport.ogg')
- announce_command_report = FALSE
- if("Cancel")
- return
-
- print_command_report(input, "[announce_command_report ? "Classified " : ""][command_name()] Update", announce_command_report)
-
- log_admin("[key_name(src)] has created a command report: [input]")
- message_admins("[key_name_admin(src)] has created a command report")
- SSblackbox.add_details("admin_verb","Create Command Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_change_command_name()
- set category = "Special Verbs"
- set name = "Change Command Name"
- if(!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- var/input = input(usr, "Please input a new name for Central Command.", "What?", "") as text|null
- if(!input)
- return
- change_command_name(input)
- message_admins("[key_name_admin(src)] has changed Central Command's name to [input]")
- log_admin("[key_name(src)] has changed the Central Command name to: [input]")
-
-/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in world)
- set category = "Admin"
- set name = "Delete"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- admin_delete(A)
-
-/client/proc/admin_delete(datum/D)
- var/atom/A = D
- var/coords = istype(A) ? " at ([A.x], [A.y], [A.z])" : ""
- if (alert(src, "Are you sure you want to delete:\n[D]\nat[coords]?", "Confirmation", "Yes", "No") == "Yes")
- log_admin("[key_name(usr)] deleted [D][coords]")
- message_admins("[key_name_admin(usr)] deleted [D][coords]")
- SSblackbox.add_details("admin_verb","Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- if(isturf(D))
- var/turf/T = D
- T.ChangeTurf(T.baseturf)
- else
- qdel(D)
-
-/client/proc/cmd_admin_list_open_jobs()
- set category = "Admin"
- set name = "Manage Job Slots"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
- holder.manage_free_slots()
- SSblackbox.add_details("admin_verb","Manage Job Slots") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world)
- set category = "Special Verbs"
- set name = "Explosion"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null
- if(devastation == null) return
- var/heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null
- if(heavy == null) return
- var/light = input("Range of light impact. -1 to none", text("Input")) as num|null
- if(light == null) return
- var/flash = input("Range of flash. -1 to none", text("Input")) as num|null
- if(flash == null) return
- var/flames = input("Range of flames. -1 to none", text("Input")) as num|null
- if(flames == null) return
-
- if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1) || (flames != -1))
- if ((devastation > 20) || (heavy > 20) || (light > 20) || (flames > 20))
- if (alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", "Yes", "No") == "No")
- return
-
- explosion(O, devastation, heavy, light, flash, null, null,flames)
- log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at ([O.x],[O.y],[O.z])")
- message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at ([O.x],[O.y],[O.z])")
- SSblackbox.add_details("admin_verb","Explosion") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- return
- else
- return
-
-/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world)
- set category = "Special Verbs"
- set name = "EM Pulse"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/heavy = input("Range of heavy pulse.", text("Input")) as num|null
- if(heavy == null) return
- var/light = input("Range of light pulse.", text("Input")) as num|null
- if(light == null) return
-
- if (heavy || light)
-
- empulse(O, heavy, light)
- log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
- message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
- SSblackbox.add_details("admin_verb","EM Pulse") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
- return
- else
- return
-
-/client/proc/cmd_admin_gib(mob/M in GLOB.mob_list)
- set category = "Special Verbs"
- set name = "Gib"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/confirm = alert(src, "Drop a brain?", "Confirm", "Yes", "No","Cancel")
- if(confirm == "Cancel")
- return
- //Due to the delay here its easy for something to have happened to the mob
- if(!M)
- return
-
- log_admin("[key_name(usr)] has gibbed [key_name(M)]")
- message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]")
-
- if(isobserver(M))
+/client/proc/cmd_admin_drop_everything(mob/M in GLOB.mob_list)
+ set category = null
+ set name = "Drop Everything"
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ var/confirm = alert(src, "Make [M] drop everything?", "Message", "Yes", "No")
+ if(confirm != "Yes")
+ return
+
+ for(var/obj/item/W in M)
+ if(!M.dropItemToGround(W))
+ qdel(W)
+ M.regenerate_icons()
+
+ log_admin("[key_name(usr)] made [key_name(M)] drop everything!")
+ var/msg = "[key_name_admin(usr)] made [key_name_admin(M)] drop everything!"
+ message_admins(msg)
+ admin_ticket_log(M, msg)
+ SSblackbox.add_details("admin_verb","Drop Everything") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_subtle_message(mob/M in GLOB.mob_list)
+ set category = "Special Verbs"
+ set name = "Subtle Message"
+
+ if(!ismob(M))
+ return
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ message_admins("[key_name_admin(src)] has started answering [key_name(M.key, 0, 0)]'s prayer.")
+ var/msg = input("Message:", text("Subtle PM to [M.key]")) as text
+
+ if (!msg)
+ message_admins("[key_name_admin(src)] decided not to answer [key_name(M.key, 0, 0)]'s prayer")
+ return
+ if(usr)
+ if (usr.client)
+ if(usr.client.holder)
+ to_chat(M, "You hear a voice in your head... [msg]")
+
+ log_admin("SubtlePM: [key_name(usr)] -> [key_name(M)] : [msg]")
+ msg = " SubtleMessage: [key_name_admin(usr)] -> [key_name_admin(M)] : [msg]"
+ message_admins(msg)
+ admin_ticket_log(M, msg)
+ SSblackbox.add_details("admin_verb","Subtle Message") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_world_narrate()
+ set category = "Special Verbs"
+ set name = "Global Narrate"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ var/msg = input("Message:", text("Enter the text you wish to appear to everyone:")) as text
+
+ if (!msg)
+ return
+ to_chat(world, "[msg]")
+ log_admin("GlobalNarrate: [key_name(usr)] : [msg]")
+ message_admins("[key_name_admin(usr)] Sent a global narrate")
+ SSblackbox.add_details("admin_verb","Global Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_direct_narrate(mob/M)
+ set category = "Special Verbs"
+ set name = "Direct Narrate"
+
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ if(!M)
+ M = input("Direct narrate to whom?", "Active Players") as null|anything in GLOB.player_list
+
+ if(!M)
+ return
+
+ var/msg = input("Message:", text("Enter the text you wish to appear to your target:")) as text
+
+ if( !msg )
+ return
+
+ to_chat(M, msg)
+ log_admin("DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]")
+ msg = " DirectNarrate: [key_name(usr)] to ([M.name]/[M.key]): [msg]
"
+ message_admins(msg)
+ admin_ticket_log(M, msg)
+ SSblackbox.add_details("admin_verb","Direct Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_local_narrate(atom/A)
+ set category = "Special Verbs"
+ set name = "Local Narrate"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ if(!A)
+ return
+ var/range = input("Range:", "Narrate to mobs within how many tiles:", 7) as num
+ if(!range)
+ return
+ var/msg = input("Message:", text("Enter the text you wish to appear to everyone within view:")) as text
+ if (!msg)
+ return
+ for(var/mob/M in view(range,A))
+ to_chat(M, msg)
+
+ log_admin("LocalNarrate: [key_name(usr)] at [get_area(A)][COORD(A)]: [msg]")
+ message_admins(" LocalNarrate: [key_name_admin(usr)] at [get_area(A)][ADMIN_JMP(A)]: [msg]
")
+ SSblackbox.add_details("admin_verb","Local Narrate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list)
+ set category = "Special Verbs"
+ set name = "Godmode"
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ M.status_flags ^= GODMODE
+ to_chat(usr, "Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]")
+
+ log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]")
+ var/msg = "[key_name_admin(usr)] has toggled [key_name_admin(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]"
+ message_admins(msg)
+ admin_ticket_log(M, msg)
+ SSblackbox.add_details("admin_toggle","Godmode|[M.status_flags & GODMODE]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+
+/proc/cmd_admin_mute(whom, mute_type, automute = 0)
+ if(!whom)
+ return
+
+ var/muteunmute
+ var/mute_string
+ var/feedback_string
+ switch(mute_type)
+ if(MUTE_IC)
+ mute_string = "IC (say and emote)"
+ feedback_string = "IC"
+ if(MUTE_OOC)
+ mute_string = "OOC"
+ feedback_string = "OOC"
+ if(MUTE_PRAY)
+ mute_string = "pray"
+ feedback_string = "Pray"
+ if(MUTE_ADMINHELP)
+ mute_string = "adminhelp, admin PM and ASAY"
+ feedback_string = "Adminhelp"
+ if(MUTE_DEADCHAT)
+ mute_string = "deadchat and DSAY"
+ feedback_string = "Deadchat"
+ if(MUTE_ALL)
+ mute_string = "everything"
+ feedback_string = "Everything"
+ else
+ return
+
+ var/client/C
+ if(istype(whom, /client))
+ C = whom
+ else if(istext(whom))
+ C = GLOB.directory[whom]
+ else
+ return
+
+ var/datum/preferences/P
+ if(C)
+ P = C.prefs
+ else
+ P = GLOB.preferences_datums[whom]
+ if(!P)
+ return
+
+ if(automute)
+ if(!config.automute_on)
+ return
+ else
+ if(!check_rights())
+ return
+
+ if(automute)
+ muteunmute = "auto-muted"
+ P.muted |= mute_type
+ log_admin("SPAM AUTOMUTE: [muteunmute] [key_name(whom)] from [mute_string]")
+ message_admins("SPAM AUTOMUTE: [muteunmute] [key_name_admin(whom)] from [mute_string].")
+ if(C)
+ to_chat(C, "You have been [muteunmute] from [mute_string] by the SPAM AUTOMUTE system. Contact an admin.")
+ SSblackbox.add_details("admin_toggle","Auto Mute [feedback_string]|1") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ return
+
+ if(P.muted & mute_type)
+ muteunmute = "unmuted"
+ P.muted &= ~mute_type
+ else
+ muteunmute = "muted"
+ P.muted |= mute_type
+
+ log_admin("[key_name(usr)] has [muteunmute] [key_name(whom)] from [mute_string]")
+ message_admins("[key_name_admin(usr)] has [muteunmute] [key_name_admin(whom)] from [mute_string].")
+ if(C)
+ to_chat(C, "You have been [muteunmute] from [mute_string] by [key_name(usr, include_name = FALSE)].")
+ SSblackbox.add_details("admin_toggle","Mute [feedback_string]|[P.muted & mute_type]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+
+//I use this proc for respawn character too. /N
+/proc/create_xeno(ckey)
+ if(!ckey)
+ var/list/candidates = list()
+ for(var/mob/M in GLOB.player_list)
+ if(M.stat != DEAD)
+ continue //we are not dead!
+ if(!(ROLE_ALIEN in M.client.prefs.be_special))
+ continue //we don't want to be an alium
+ if(M.client.is_afk())
+ continue //we are afk
+ if(M.mind && M.mind.current && M.mind.current.stat != DEAD)
+ continue //we have a live body we are tied to
+ candidates += M.ckey
+ if(candidates.len)
+ ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in candidates
+ else
+ to_chat(usr, "Error: create_xeno(): no suitable candidates.")
+ if(!istext(ckey))
+ return 0
+
+ var/alien_caste = input(usr, "Please choose which caste to spawn.","Pick a caste",null) as null|anything in list("Queen","Praetorian","Hunter","Sentinel","Drone","Larva")
+ var/obj/effect/landmark/spawn_here = GLOB.xeno_spawn.len ? pick(GLOB.xeno_spawn) : null
+ var/mob/living/carbon/alien/new_xeno
+ switch(alien_caste)
+ if("Queen")
+ new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(spawn_here)
+ if("Praetorian")
+ new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(spawn_here)
+ if("Hunter")
+ new_xeno = new /mob/living/carbon/alien/humanoid/hunter(spawn_here)
+ if("Sentinel")
+ new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(spawn_here)
+ if("Drone")
+ new_xeno = new /mob/living/carbon/alien/humanoid/drone(spawn_here)
+ if("Larva")
+ new_xeno = new /mob/living/carbon/alien/larva(spawn_here)
+ else
+ return 0
+ if(!spawn_here)
+ SSjob.SendToLateJoin(new_xeno, FALSE)
+
+ new_xeno.ckey = ckey
+ var/msg = "[key_name_admin(usr)] has spawned [ckey] as a filthy xeno [alien_caste]."
+ message_admins(msg)
+ admin_ticket_log(new_xeno, msg)
+ return 1
+
+/*
+If a guy was gibbed and you want to revive him, this is a good way to do so.
+Works kind of like entering the game with a new character. Character receives a new mind if they didn't have one.
+Traitors and the like can also be revived with the previous role mostly intact.
+/N */
+/client/proc/respawn_character()
+ set category = "Special Verbs"
+ set name = "Respawn Character"
+ set desc = "Respawn a person that has been gibbed/dusted/killed. They must be a ghost for this to work and preferably should not have a body to go back into."
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ var/input = ckey(input(src, "Please specify which key will be respawned.", "Key", ""))
+ if(!input)
+ return
+
+ var/mob/dead/observer/G_found
+ for(var/mob/dead/observer/G in GLOB.player_list)
+ if(G.ckey == input)
+ G_found = G
+ break
+
+ if(!G_found)//If a ghost was not found.
+ to_chat(usr, "There is no active key like that in the game or the person is not currently a ghost.")
+ return
+
+ if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something
+ //Check if they were an alien
+ if(G_found.mind.assigned_role=="Alien")
+ if(alert("This character appears to have been an alien. Would you like to respawn them as such?",,"Yes","No")=="Yes")
+ var/turf/T
+ if(GLOB.xeno_spawn.len)
+ T = pick(GLOB.xeno_spawn)
+
+ var/mob/living/carbon/alien/new_xeno
+ switch(G_found.mind.special_role)//If they have a mind, we can determine which caste they were.
+ if("Hunter")
+ new_xeno = new /mob/living/carbon/alien/humanoid/hunter(T)
+ if("Sentinel")
+ new_xeno = new /mob/living/carbon/alien/humanoid/sentinel(T)
+ if("Drone")
+ new_xeno = new /mob/living/carbon/alien/humanoid/drone(T)
+ if("Praetorian")
+ new_xeno = new /mob/living/carbon/alien/humanoid/royal/praetorian(T)
+ if("Queen")
+ new_xeno = new /mob/living/carbon/alien/humanoid/royal/queen(T)
+ else//If we don't know what special role they have, for whatever reason, or they're a larva.
+ create_xeno(G_found.ckey)
+ return
+
+ if(!T)
+ SSjob.SendToLateJoin(new_xeno, FALSE)
+
+ //Now to give them their mind back.
+ G_found.mind.transfer_to(new_xeno) //be careful when doing stuff like this! I've already checked the mind isn't in use
+ new_xeno.key = G_found.key
+ to_chat(new_xeno, "You have been fully respawned. Enjoy the game.")
+ var/msg = "[key_name_admin(usr)] has respawned [new_xeno.key] as a filthy xeno."
+ message_admins(msg)
+ admin_ticket_log(new_xeno, msg)
+ return //all done. The ghost is auto-deleted
+
+ //check if they were a monkey
+ else if(findtext(G_found.real_name,"monkey"))
+ if(alert("This character appears to have been a monkey. Would you like to respawn them as such?",,"Yes","No")=="Yes")
+ var/mob/living/carbon/monkey/new_monkey = new
+ SSjob.SendToLateJoin(new_monkey)
+ G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use
+ new_monkey.key = G_found.key
+ to_chat(new_monkey, "You have been fully respawned. Enjoy the game.")
+ var/msg = "[key_name_admin(usr)] has respawned [new_monkey.key] as a filthy xeno."
+ message_admins(msg)
+ admin_ticket_log(new_monkey, msg)
+ return //all done. The ghost is auto-deleted
+
+
+ //Ok, it's not a xeno or a monkey. So, spawn a human.
+ var/mob/living/carbon/human/new_character = new//The mob being spawned.
+ SSjob.SendToLateJoin(new_character)
+
+ var/datum/data/record/record_found //Referenced to later to either randomize or not randomize the character.
+ if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something
+ /*Try and locate a record for the person being respawned through GLOB.data_core.
+ This isn't an exact science but it does the trick more often than not.*/
+ var/id = md5("[G_found.real_name][G_found.mind.assigned_role]")
+
+ record_found = find_record("id", id, GLOB.data_core.locked)
+
+ if(record_found)//If they have a record we can determine a few things.
+ new_character.real_name = record_found.fields["name"]
+ new_character.gender = record_found.fields["sex"]
+ new_character.age = record_found.fields["age"]
+ new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], record_found.fields["species"], record_found.fields["features"])
+ else
+ var/datum/preferences/A = new()
+ A.copy_to(new_character)
+ A.real_name = G_found.real_name
+ new_character.dna.update_dna_identity()
+
+ new_character.name = new_character.real_name
+
+ if(G_found.mind && !G_found.mind.active)
+ G_found.mind.transfer_to(new_character) //be careful when doing stuff like this! I've already checked the mind isn't in use
+ else
+ new_character.mind_initialize()
+ if(!new_character.mind.assigned_role)
+ new_character.mind.assigned_role = "Assistant"//If they somehow got a null assigned role.
+
+ new_character.key = G_found.key
+
+ /*
+ The code below functions with the assumption that the mob is already a traitor if they have a special role.
+ So all it does is re-equip the mob with powers and/or items. Or not, if they have no special role.
+ If they don't have a mind, they obviously don't have a special role.
+ */
+
+ //Two variables to properly announce later on.
+ var/admin = key_name_admin(src)
+ var/player_key = G_found.key
+
+ //Now for special roles and equipment.
+ var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(ANTAG_DATUM_TRAITOR)
+ if(traitordatum)
+ SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)
+ traitordatum.equip()
+
+
+ switch(new_character.mind.special_role)
+ if("Wizard")
+ new_character.loc = pick(GLOB.wizardstart)
+ //SSticker.mode.learn_basic_spells(new_character)
+ SSticker.mode.equip_wizard(new_character)
+ if("Syndicate")
+ var/obj/effect/landmark/synd_spawn = locate("landmark*Syndicate-Spawn")
+ if(synd_spawn)
+ new_character.loc = get_turf(synd_spawn)
+ call(/datum/game_mode/proc/equip_syndicate)(new_character)
+ if("Space Ninja")
+ var/list/ninja_spawn = list()
+ for(var/obj/effect/landmark/L in GLOB.landmarks_list)
+ if(L.name=="carpspawn")
+ ninja_spawn += L
+ var/datum/antagonist/ninja/ninjadatum = new_character.mind.has_antag_datum(ANTAG_DATUM_NINJA)
+ ninjadatum.equip_space_ninja()
+ if(ninja_spawn.len)
+ var/obj/effect/landmark/ninja_spawn_here = pick(ninja_spawn)
+ new_character.loc = ninja_spawn_here.loc
+
+ else//They may also be a cyborg or AI.
+ switch(new_character.mind.assigned_role)
+ if("Cyborg")//More rigging to make em' work and check if they're traitor.
+ new_character = new_character.Robotize()
+ if("AI")
+ new_character = new_character.AIize()
+ else
+ SSjob.EquipRank(new_character, new_character.mind.assigned_role, 1)//Or we simply equip them.
+
+ //Announces the character on all the systems, based on the record.
+ if(!issilicon(new_character))//If they are not a cyborg/AI.
+ if(!record_found&&new_character.mind.assigned_role!=new_character.mind.special_role)//If there are no records for them. If they have a record, this info is already in there. MODE people are not announced anyway.
+ //Power to the user!
+ if(alert(new_character,"Warning: No data core entry detected. Would you like to announce the arrival of this character by adding them to various databases, such as medical records?",,"No","Yes")=="Yes")
+ GLOB.data_core.manifest_inject(new_character)
+
+ if(alert(new_character,"Would you like an active AI to announce this character?",,"No","Yes")=="Yes")
+ AnnounceArrival(new_character, new_character.mind.assigned_role)
+
+ var/msg = "[admin] has respawned [player_key] as [new_character.real_name]."
+ message_admins(msg)
+ admin_ticket_log(new_character, msg)
+
+ to_chat(new_character, "You have been fully respawned. Enjoy the game.")
+
+ SSblackbox.add_details("admin_verb","Respawn Character") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ return new_character
+
+/client/proc/cmd_admin_add_freeform_ai_law()
+ set category = "Fun"
+ set name = "Add Custom AI law"
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ var/input = input(usr, "Please enter anything you want the AI to do. Anything. Serious.", "What?", "") as text|null
+ if(!input)
+ return
+
+ log_admin("Admin [key_name(usr)] has added a new AI law - [input]")
+ message_admins("Admin [key_name_admin(usr)] has added a new AI law - [input]")
+
+ var/show_log = alert(src, "Show ion message?", "Message", "Yes", "No")
+ var/announce_ion_laws = (show_log == "Yes" ? 1 : -1)
+
+ var/datum/round_event/ion_storm/add_law_only/ion = new()
+ ion.announceEvent = announce_ion_laws
+ ion.ionMessage = input
+
+ SSblackbox.add_details("admin_verb","Add Custom AI Law") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_rejuvenate(mob/living/M in GLOB.mob_list)
+ set category = "Special Verbs"
+ set name = "Rejuvenate"
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ if(!mob)
+ return
+ if(!istype(M))
+ alert("Cannot revive a ghost")
+ return
+ M.revive(full_heal = 1, admin_revive = 1)
+
+ log_admin("[key_name(usr)] healed / revived [key_name(M)]")
+ var/msg = "Admin [key_name_admin(usr)] healed / revived [key_name_admin(M)]!"
+ message_admins(msg)
+ admin_ticket_log(M, msg)
+ SSblackbox.add_details("admin_verb","Rejuvinate") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_create_centcom_report()
+ set category = "Special Verbs"
+ set name = "Create Command Report"
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ var/input = input(usr, "Please enter anything you want. Anything. Serious.", "What?", "") as message|null
+ if(!input)
+ return
+
+ var/confirm = alert(src, "Do you want to announce the contents of the report to the crew?", "Announce", "Yes", "No", "Cancel")
+ var/announce_command_report = TRUE
+ switch(confirm)
+ if("Yes")
+ priority_announce(input, null, 'sound/ai/commandreport.ogg')
+ announce_command_report = FALSE
+ if("Cancel")
+ return
+
+ print_command_report(input, "[announce_command_report ? "Classified " : ""][command_name()] Update", announce_command_report)
+
+ log_admin("[key_name(src)] has created a command report: [input]")
+ message_admins("[key_name_admin(src)] has created a command report")
+ SSblackbox.add_details("admin_verb","Create Command Report") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_change_command_name()
+ set category = "Special Verbs"
+ set name = "Change Command Name"
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ var/input = input(usr, "Please input a new name for Central Command.", "What?", "") as text|null
+ if(!input)
+ return
+ change_command_name(input)
+ message_admins("[key_name_admin(src)] has changed Central Command's name to [input]")
+ log_admin("[key_name(src)] has changed the Central Command name to: [input]")
+
+/client/proc/cmd_admin_delete(atom/A as obj|mob|turf in world)
+ set category = "Admin"
+ set name = "Delete"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ admin_delete(A)
+
+/client/proc/admin_delete(datum/D)
+ var/atom/A = D
+ var/coords = istype(A) ? " at ([A.x], [A.y], [A.z])" : ""
+ if (alert(src, "Are you sure you want to delete:\n[D]\nat[coords]?", "Confirmation", "Yes", "No") == "Yes")
+ log_admin("[key_name(usr)] deleted [D][coords]")
+ message_admins("[key_name_admin(usr)] deleted [D][coords]")
+ SSblackbox.add_details("admin_verb","Delete") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ if(isturf(D))
+ var/turf/T = D
+ T.ChangeTurf(T.baseturf)
+ else
+ qdel(D)
+
+/client/proc/cmd_admin_list_open_jobs()
+ set category = "Admin"
+ set name = "Manage Job Slots"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ holder.manage_free_slots()
+ SSblackbox.add_details("admin_verb","Manage Job Slots") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_explosion(atom/O as obj|mob|turf in world)
+ set category = "Special Verbs"
+ set name = "Explosion"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ var/devastation = input("Range of total devastation. -1 to none", text("Input")) as num|null
+ if(devastation == null) return
+ var/heavy = input("Range of heavy impact. -1 to none", text("Input")) as num|null
+ if(heavy == null) return
+ var/light = input("Range of light impact. -1 to none", text("Input")) as num|null
+ if(light == null) return
+ var/flash = input("Range of flash. -1 to none", text("Input")) as num|null
+ if(flash == null) return
+ var/flames = input("Range of flames. -1 to none", text("Input")) as num|null
+ if(flames == null) return
+
+ if ((devastation != -1) || (heavy != -1) || (light != -1) || (flash != -1) || (flames != -1))
+ if ((devastation > 20) || (heavy > 20) || (light > 20) || (flames > 20))
+ if (alert(src, "Are you sure you want to do this? It will laaag.", "Confirmation", "Yes", "No") == "No")
+ return
+
+ explosion(O, devastation, heavy, light, flash, null, null,flames)
+ log_admin("[key_name(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at ([O.x],[O.y],[O.z])")
+ message_admins("[key_name_admin(usr)] created an explosion ([devastation],[heavy],[light],[flames]) at ([O.x],[O.y],[O.z])")
+ SSblackbox.add_details("admin_verb","Explosion") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ return
+ else
+ return
+
+/client/proc/cmd_admin_emp(atom/O as obj|mob|turf in world)
+ set category = "Special Verbs"
+ set name = "EM Pulse"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ var/heavy = input("Range of heavy pulse.", text("Input")) as num|null
+ if(heavy == null) return
+ var/light = input("Range of light pulse.", text("Input")) as num|null
+ if(light == null) return
+
+ if (heavy || light)
+
+ empulse(O, heavy, light)
+ log_admin("[key_name(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
+ message_admins("[key_name_admin(usr)] created an EM Pulse ([heavy],[light]) at ([O.x],[O.y],[O.z])")
+ SSblackbox.add_details("admin_verb","EM Pulse") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+ return
+ else
+ return
+
+/client/proc/cmd_admin_gib(mob/M in GLOB.mob_list)
+ set category = "Special Verbs"
+ set name = "Gib"
+
+ if (!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+
+ var/confirm = alert(src, "Drop a brain?", "Confirm", "Yes", "No","Cancel")
+ if(confirm == "Cancel")
+ return
+ //Due to the delay here its easy for something to have happened to the mob
+ if(!M)
+ return
+
+ log_admin("[key_name(usr)] has gibbed [key_name(M)]")
+ message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]")
+
+ if(isobserver(M))
new /obj/effect/gibspawner/generic(get_turf(M))
- return
- if(confirm == "Yes")
- M.gib()
- else
- M.gib(1)
- SSblackbox.add_details("admin_verb","Gib") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/cmd_admin_gib_self()
- set name = "Gibself"
- set category = "Fun"
-
- var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No")
- if(confirm == "Yes")
- log_admin("[key_name(usr)] used gibself.")
- message_admins("[key_name_admin(usr)] used gibself.")
- SSblackbox.add_details("admin_verb","Gib Self") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- mob.gib(1, 1, 1)
-
-/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list)
- set category = "Special Verbs"
- set name = "Check Contents"
-
- var/list/L = M.get_contents()
- for(var/t in L)
- to_chat(usr, "[t]")
- SSblackbox.add_details("admin_verb","Check Contents") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/toggle_view_range()
- set category = "Special Verbs"
- set name = "Change View Range"
- set desc = "switches between 1x and custom views"
-
- if(view == world.view)
+ return
+ if(confirm == "Yes")
+ M.gib()
+ else
+ M.gib(1)
+ SSblackbox.add_details("admin_verb","Gib") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/cmd_admin_gib_self()
+ set name = "Gibself"
+ set category = "Fun"
+
+ var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No")
+ if(confirm == "Yes")
+ log_admin("[key_name(usr)] used gibself.")
+ message_admins("[key_name_admin(usr)] used gibself.")
+ SSblackbox.add_details("admin_verb","Gib Self") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+ mob.gib(1, 1, 1)
+
+/client/proc/cmd_admin_check_contents(mob/living/M in GLOB.mob_list)
+ set category = "Special Verbs"
+ set name = "Check Contents"
+
+ var/list/L = M.get_contents()
+ for(var/t in L)
+ to_chat(usr, "[t]")
+ SSblackbox.add_details("admin_verb","Check Contents") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
+
+/client/proc/toggle_view_range()
+ set category = "Special Verbs"
+ set name = "Change View Range"
+ set desc = "switches between 1x and custom views"
+
+ if(view == world.view)
change_view(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128))
- else
+ else
change_view(world.view)
-
- log_admin("[key_name(usr)] changed their view range to [view].")
- //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI
-
- SSblackbox.add_details("admin_toggle","Change View Range|[view]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/admin_call_shuttle()
-
- set category = "Admin"
- set name = "Call Shuttle"
-
- if(EMERGENCY_AT_LEAST_DOCKED)
- return
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/confirm = alert(src, "You sure?", "Confirm", "Yes", "No")
- if(confirm != "Yes")
- return
-
- SSshuttle.emergency.request()
- SSblackbox.add_details("admin_verb","Call Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- log_admin("[key_name(usr)] admin-called the emergency shuttle.")
- message_admins("[key_name_admin(usr)] admin-called the emergency shuttle.")
- return
-
-/client/proc/admin_cancel_shuttle()
- set category = "Admin"
- set name = "Cancel Shuttle"
- if(!check_rights(0))
- return
- if(alert(src, "You sure?", "Confirm", "Yes", "No") != "Yes")
- return
-
- if(EMERGENCY_AT_LEAST_DOCKED)
- return
-
- SSshuttle.emergency.cancel()
- SSblackbox.add_details("admin_verb","Cancel Shuttle") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- log_admin("[key_name(usr)] admin-recalled the emergency shuttle.")
- message_admins("[key_name_admin(usr)] admin-recalled the emergency shuttle.")
-
- return
-
-/client/proc/everyone_random()
- set category = "Fun"
- set name = "Make Everyone Random"
- set desc = "Make everyone have a random appearance. You can only use this before rounds!"
-
- if(SSticker.HasRoundStarted())
- to_chat(usr, "Nope you can't do this, the game's already started. This only works before rounds!")
- return
-
- if(config.force_random_names)
- config.force_random_names = 0
- message_admins("Admin [key_name_admin(usr)] has disabled \"Everyone is Special\" mode.")
- to_chat(usr, "Disabled.")
- return
-
-
- var/notifyplayers = alert(src, "Do you want to notify the players?", "Options", "Yes", "No", "Cancel")
- if(notifyplayers == "Cancel")
- return
-
- log_admin("Admin [key_name(src)] has forced the players to have random appearances.")
- message_admins("Admin [key_name_admin(usr)] has forced the players to have random appearances.")
-
- if(notifyplayers == "Yes")
- to_chat(world, "Admin [usr.key] has forced the players to have completely random identities!")
-
- to_chat(usr, "Remember: you can always disable the randomness by using the verb again, assuming the round hasn't started yet.")
-
- config.force_random_names = 1
- SSblackbox.add_details("admin_verb","Make Everyone Random") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-
-/client/proc/toggle_random_events()
- set category = "Server"
- set name = "Toggle random events on/off"
- set desc = "Toggles random events such as meteors, black holes, blob (but not space dust) on/off"
- if(!config.allow_random_events)
- config.allow_random_events = 1
- to_chat(usr, "Random events enabled")
- message_admins("Admin [key_name_admin(usr)] has enabled random events.")
- else
- config.allow_random_events = 0
- to_chat(usr, "Random events disabled")
- message_admins("Admin [key_name_admin(usr)] has disabled random events.")
- SSblackbox.add_details("admin_toggle","Toggle Random Events|[config.allow_random_events]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-
-/client/proc/admin_change_sec_level()
- set category = "Special Verbs"
- set name = "Set Security Level"
- set desc = "Changes the security level. Announcement only, i.e. setting to Delta won't activate nuke"
-
- if (!holder)
- to_chat(src, "Only administrators may use this command.")
- return
-
- var/level = input("Select security level to change to","Set Security Level") as null|anything in list("green","blue","red","delta")
- if(level)
- set_security_level(level)
-
- log_admin("[key_name(usr)] changed the security level to [level]")
- message_admins("[key_name_admin(usr)] changed the security level to [level]")
- SSblackbox.add_details("admin_verb","Set Security Level [capitalize(level)]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-/client/proc/toggle_nuke(obj/machinery/nuclearbomb/N in GLOB.nuke_list)
- set name = "Toggle Nuke"
- set category = "Fun"
- set popup_menu = 0
- if(!check_rights(R_DEBUG))
- return
-
- if(!N.timing)
- var/newtime = input(usr, "Set activation timer.", "Activate Nuke", "[N.timer_set]") as num
- if(!newtime)
- return
- N.timer_set = newtime
- N.set_safety()
- N.set_active()
-
- log_admin("[key_name(usr)] [N.timing ? "activated" : "deactivated"] a nuke at ([N.x],[N.y],[N.z]).")
- message_admins("[ADMIN_LOOKUPFLW(usr)] [N.timing ? "activated" : "deactivated"] a nuke at [ADMIN_COORDJMP(N)].")
- SSblackbox.add_details("admin_toggle","Toggle Nuke|[N.timing]") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-
-GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
-
-/client/proc/create_outfits()
- set category = "Debug"
- set name = "Create Custom Outfit"
-
- if(!check_rights(R_DEBUG))
- return
-
- holder.create_outfit()
-
-/datum/admins/proc/create_outfit()
- var/list/uniforms = typesof(/obj/item/clothing/under)
- var/list/suits = typesof(/obj/item/clothing/suit)
- var/list/gloves = typesof(/obj/item/clothing/gloves)
- var/list/shoes = typesof(/obj/item/clothing/shoes)
- var/list/headwear = typesof(/obj/item/clothing/head)
- var/list/glasses = typesof(/obj/item/clothing/glasses)
- var/list/masks = typesof(/obj/item/clothing/mask)
- var/list/ids = typesof(/obj/item/card/id)
-
- var/uniform_select = ""
-
- var/suit_select = ""
-
- var/gloves_select = ""
-
- var/shoes_select = ""
-
- var/head_select = ""
-
- var/glasses_select = ""
-
- var/mask_select = ""
-
- var/id_select = ""
-
- var/dat = {"
-
| "
- if(jobban_isbanned(user, "appearance"))
- dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game. " - dat += "Random Name " - dat += "Always Random Name: [be_random_name ? "Yes" : "No"] " - - dat += "Name: " - dat += "[real_name] " - - dat += "Gender: [gender == MALE ? "Male" : "Female"] " - dat += "Age: [age] " - dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"] " - dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"] " - dat += "Special Names: " - dat += "Clown: [custom_names["clown"]] " - dat += "Mime:[custom_names["mime"]] " - dat += "AI: [custom_names["ai"]] " - dat += "Cyborg: [custom_names["cyborg"]] " - dat += "Chaplain religion: [custom_names["religion"]] " - dat += "Chaplain deity: [custom_names["deity"]] " - - dat += "Custom job preferences: " - dat += "Prefered security department: [prefered_security_department] | "
-
- dat += ""
-
- dat += " |
"
- dat += "General Settings" - dat += "UI Style: [UI_style]" - dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Default"] " - dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"] " - dat += "tgui Style: [(tgui_fancy) ? "Fancy" : "No Frills"] " - dat += "tgui Monitors: [(tgui_lock) ? "Primary" : "All"] " - dat += "Window Flashing: [(windowflashing) ? "Yes" : "No"] " - dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"] " - dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"] " - dat += "Ghost ears: [(chat_toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"] " - dat += "Ghost sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"] " - dat += "Ghost whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "All Speech" : "Nearest Creatures"] " - dat += "Ghost radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "Yes" : "No"] " - dat += "Ghost pda: [(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"] " - dat += "Pull requests: [(chat_toggles & CHAT_PULLR) ? "Yes" : "No"] " - dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Yes" : "No"] " - if(config.allow_Metadata) - dat += "OOC Notes: Edit " - - if(user.client) - if(user.client.holder) - dat += "Adminhelp Sound: [(toggles & SOUND_ADMINHELP)?"On":"Off"] " - dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"On":"Off"] " - - if(unlock_content || check_rights_for(user.client, R_ADMIN)) - dat += "OOC: Change " - - if(unlock_content) - dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"] " - dat += "Ghost Form: [ghost_form] " - dat += "Ghost Orbit: [ghost_orbit] " - - var/button_name = "If you see this something went wrong." - switch(ghost_accs) - if(GHOST_ACCS_FULL) - button_name = GHOST_ACCS_FULL_NAME - if(GHOST_ACCS_DIR) - button_name = GHOST_ACCS_DIR_NAME - if(GHOST_ACCS_NONE) - button_name = GHOST_ACCS_NONE_NAME - - dat += "Ghost Accessories: [button_name] " - - switch(ghost_others) - if(GHOST_OTHERS_THEIR_SETTING) - button_name = GHOST_OTHERS_THEIR_SETTING_NAME - if(GHOST_OTHERS_DEFAULT_SPRITE) - button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME - if(GHOST_OTHERS_SIMPLE) - button_name = GHOST_OTHERS_SIMPLE_NAME - - dat += "Ghosts of Others: [button_name] " - - if (config.maprotation) - var/p_map = preferred_map - if (!p_map) - p_map = "Default" - if (config.defaultmap) - p_map += " ([config.defaultmap.map_name])" - else - if (p_map in config.maplist) - var/datum/map_config/VM = config.maplist[p_map] - if (!VM) - p_map += " (No longer exists)" - else - p_map = VM.map_name - else - p_map += " (No longer exists)" - if(config.allow_map_voting) - dat += "Preferred Map: [p_map] " - - dat += "FPS: [clientfps] " - - dat += "Parallax (Fancy Space): " - switch (parallax) - if (PARALLAX_LOW) - dat += "Low" - if (PARALLAX_MED) - dat += "Medium" - if (PARALLAX_INSANE) - dat += "Insane" - if (PARALLAX_DISABLE) - dat += "Disabled" - else - dat += "High" - dat += " " - - dat += " | "
-
- dat += "Special Role Settings" - - if(jobban_isbanned(user, "Syndicate")) - dat += "You are banned from antagonist roles." - src.be_special = list() - - - for (var/i in GLOB.special_roles) - if(jobban_isbanned(user, i)) - dat += "Be [capitalize(i)]: BANNED" - else - var/days_remaining = null - if(config.use_age_restriction_for_jobs && ispath(GLOB.special_roles[i])) //If it's a game mode antag, check if the player meets the minimum age - var/mode_path = GLOB.special_roles[i] - var/datum/game_mode/temp_mode = new mode_path - days_remaining = temp_mode.get_remaining_days(user.client) - - if(days_remaining) - dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS] " - else - dat += "Be [capitalize(i)]: [(i in be_special) ? "Yes" : "No"] " - - dat += " |
| "
- dat += " " - dat += "Set Flavor Text " - if(lentext(features["flavor_text"]) <= 40) - if(!lentext(features["flavor_text"])) - dat += "\[...\]" - else - dat += "[features["flavor_text"]]" - else - dat += "[TextPreview(features["flavor_text"])]... " - if(config.mutant_races)//really don't need this check, but fuck un-tabbing all those lines - dat += " Body" - dat += "Gender: [gender == MALE ? "Male" : "Female"]" - dat += "Species:[pref_species.id] " - dat += "Random Body " - dat += "Always Random Body: [be_random_body ? "Yes" : "No"] " - if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits)) - dat += "Primary Color: Change " - dat += "Secondary Color: Change " - dat += "Tertiary Color: Change " - if(pref_species.use_skintones) - dat += "Skin Tone: [skin_tone] " - dat += "Genitals Use Skintone:[features["genitals_use_skintone"] == TRUE ? "Enabled" : "Disabled"] " - - if(HAIR in pref_species.species_traits) - dat += "Hair Style: [hair_style] " - dat += "Hair Color: Change " - dat += "Facial Hair Style: [facial_hair_style] " - dat += "Facial Hair Color: Change " - if(EYECOLOR in pref_species.species_traits) - dat += "Eye Color: Change " - if("tail_lizard" in pref_species.mutant_bodyparts) - dat += "Tail: [features["tail_lizard"]] " - else if("mam_tail" in pref_species.mutant_bodyparts) - dat += "Tail: [features["mam_tail"]] " - else if("tail_human" in pref_species.mutant_bodyparts) - dat += "Tail: [features["tail_human"]] " - if("snout" in pref_species.mutant_bodyparts) - dat += "Snout: [features["snout"]] " - if("horns" in pref_species.mutant_bodyparts) - dat += "Horns: [features["horns"]] " - if("frills" in pref_species.mutant_bodyparts) - dat += "Frills: [features["frills"]] " - if("spines" in pref_species.mutant_bodyparts) - dat += "Spines: [features["spines"]] " - if("body_markings" in pref_species.mutant_bodyparts) - dat += "Body Markings: [features["body_markings"]] " - else if("mam_body_markings" in pref_species.mutant_bodyparts) - dat += "Body Markings: [features["mam_body_markings"]] " - if("mam_ears" in pref_species.mutant_bodyparts) - dat += "Ears: [features["mam_ears"]] " - else if("ears" in pref_species.mutant_bodyparts) - dat += "Ears: [features["ears"]] " - if("legs" in pref_species.mutant_bodyparts) - dat += "Legs: [features["legs"]] " - if("taur" in pref_species.mutant_bodyparts) - dat += "Taur: [features["taur"]] " - if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1) - dat += "Wings: [features["wings"]] " - if("xenohead" in pref_species.mutant_bodyparts) - dat += "Caste: [features["xenohead"]] " - if("xenotail" in pref_species.mutant_bodyparts) - dat += "Tail: [features["xenotail"]] " - if("xenodorsal" in pref_species.mutant_bodyparts) - dat += "Dorsal Tubes: [features["xenodorsal"]] " - - dat += " | "
-
-
- dat += "Clothing & Equipment" -//underwear will be refactored later so it fits in with other wearable equipment and isn't just an overlay -// dat += "Underwear:[underwear]" -// dat += "Undershirt:[undershirt] " -// dat += "Socks:[socks] " - dat += "Backpack:[backbag] " - dat += "Uplink Location:[uplink_spawn_loc] " - - dat += " Genitals" - if(NOGENITALS in pref_species.species_traits) - dat += "Your species ([pref_species.name]) does not support genitals!" - else - dat += "Has Penis:[features["has_cock"] == TRUE ? "Yes" : "No"] " - if(features["has_cock"] == TRUE) - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Penis Color: (Skin tone overriding) " - else - dat += "Penis Color: Change " -// dat += " " - dat += "Penis Shape: [features["cock_shape"]] " - dat += "Penis Length: [features["cock_length"]] inch(es) " - dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"] " - if(features["has_balls"] == TRUE) - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Testicles Color: (Skin tone overriding) " - else - dat += "Testicles Color: Change " - dat += "Has Vagina:[features["has_vag"] == TRUE ? "Yes" : "No"] " - if(features["has_vag"]) - dat += "Vagina Type: [features["vag_shape"]] " - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Vagina Color: (Skin tone overriding) " - else - dat += "Vagina Color: Change " - dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"] " - dat += "Has Breasts:[features["has_breasts"] == TRUE ? "Yes" : "No"] " - if(features["has_breasts"]) - if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) - dat += "Color: (Skin tone overriding) " - else - dat += "Color: Change " - dat += "Cup Size:[features["breasts_size"]] " - dat += "Breast Shape:[features["breasts_shape"]] " - /* - dat += " Ovipositor" - dat += "Has Ovipositor:[features["has_ovi"] == TRUE ? "Yes" : "No"]" - if(features["has_ovi"]) - dat += "Ovi Color: Change" - dat += "Eggsack" - dat += "Has Eggsack:[features["has_eggsack"] == TRUE ? "Yes" : "No"]" - if(features["has_eggsack"] == TRUE) - dat += "Color: Change" - dat += "Egg Color: Change" - dat += "Egg Size:[features["eggsack_egg_size"]]\" Diameter" - - dat += " | "
- */
-
-
- dat += "
" // Table within a table for alignment, also allows you to easily add more colomns.
- HTML += "
|
|
| "
+ if(jobban_isbanned(user, "appearance"))
+ dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game. " + dat += "Random Name " + dat += "Always Random Name: [be_random_name ? "Yes" : "No"] " + + dat += "Name: " + dat += "[real_name] " + + dat += "Gender: [gender == MALE ? "Male" : "Female"] " + dat += "Age: [age] " + dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"] " + dat += "Exhibitionist:[features["exhibitionist"] == TRUE ? "Yes" : "No"] " + dat += "Special Names: " + dat += "Clown: [custom_names["clown"]] " + dat += "Mime:[custom_names["mime"]] " + dat += "AI: [custom_names["ai"]] " + dat += "Cyborg: [custom_names["cyborg"]] " + dat += "Chaplain religion: [custom_names["religion"]] " + dat += "Chaplain deity: [custom_names["deity"]] " + + dat += "Custom job preferences: " + dat += "Prefered security department: [prefered_security_department] | "
+
+ dat += ""
+
+ dat += " |
"
+ dat += "General Settings" + dat += "UI Style: [UI_style]" + dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Default"] " + dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"] " + dat += "tgui Style: [(tgui_fancy) ? "Fancy" : "No Frills"] " + dat += "tgui Monitors: [(tgui_lock) ? "Primary" : "All"] " + dat += "Window Flashing: [(windowflashing) ? "Yes" : "No"] " + dat += "Play admin midis: [(toggles & SOUND_MIDI) ? "Yes" : "No"] " + dat += "Play lobby music: [(toggles & SOUND_LOBBY) ? "Yes" : "No"] " + dat += "Ghost ears: [(chat_toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"] " + dat += "Ghost sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"] " + dat += "Ghost whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "All Speech" : "Nearest Creatures"] " + dat += "Ghost radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "Yes" : "No"] " + dat += "Ghost pda: [(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"] " + dat += "Pull requests: [(chat_toggles & CHAT_PULLR) ? "Yes" : "No"] " + dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Yes" : "No"] " + if(config.allow_Metadata) + dat += "OOC Notes: Edit " + + if(user.client) + if(user.client.holder) + dat += "Adminhelp Sound: [(toggles & SOUND_ADMINHELP)?"On":"Off"] " + dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"On":"Off"] " + + if(unlock_content || check_rights_for(user.client, R_ADMIN)) + dat += "OOC: Change " + + if(unlock_content) + dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"] " + dat += "Ghost Form: [ghost_form] " + dat += "Ghost Orbit: [ghost_orbit] " + + var/button_name = "If you see this something went wrong." + switch(ghost_accs) + if(GHOST_ACCS_FULL) + button_name = GHOST_ACCS_FULL_NAME + if(GHOST_ACCS_DIR) + button_name = GHOST_ACCS_DIR_NAME + if(GHOST_ACCS_NONE) + button_name = GHOST_ACCS_NONE_NAME + + dat += "Ghost Accessories: [button_name] " + + switch(ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + button_name = GHOST_OTHERS_THEIR_SETTING_NAME + if(GHOST_OTHERS_DEFAULT_SPRITE) + button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME + if(GHOST_OTHERS_SIMPLE) + button_name = GHOST_OTHERS_SIMPLE_NAME + + dat += "Ghosts of Others: [button_name] " + + if (config.maprotation) + var/p_map = preferred_map + if (!p_map) + p_map = "Default" + if (config.defaultmap) + p_map += " ([config.defaultmap.map_name])" + else + if (p_map in config.maplist) + var/datum/map_config/VM = config.maplist[p_map] + if (!VM) + p_map += " (No longer exists)" + else + p_map = VM.map_name + else + p_map += " (No longer exists)" + if(config.allow_map_voting) + dat += "Preferred Map: [p_map] " + + dat += "FPS: [clientfps] " + + dat += "Parallax (Fancy Space): " + switch (parallax) + if (PARALLAX_LOW) + dat += "Low" + if (PARALLAX_MED) + dat += "Medium" + if (PARALLAX_INSANE) + dat += "Insane" + if (PARALLAX_DISABLE) + dat += "Disabled" + else + dat += "High" + dat += " " + + dat += " | "
+
+ dat += "Special Role Settings" + + if(jobban_isbanned(user, "Syndicate")) + dat += "You are banned from antagonist roles." + src.be_special = list() + + + for (var/i in GLOB.special_roles) + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: BANNED" + else + var/days_remaining = null + if(config.use_age_restriction_for_jobs && ispath(GLOB.special_roles[i])) //If it's a game mode antag, check if the player meets the minimum age + var/mode_path = GLOB.special_roles[i] + var/datum/game_mode/temp_mode = new mode_path + days_remaining = temp_mode.get_remaining_days(user.client) + + if(days_remaining) + dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS] " + else + dat += "Be [capitalize(i)]: [(i in be_special) ? "Yes" : "No"] " + + dat += " |
| "
+ dat += " " + dat += "Set Flavor Text " + if(lentext(features["flavor_text"]) <= 40) + if(!lentext(features["flavor_text"])) + dat += "\[...\]" + else + dat += "[features["flavor_text"]]" + else + dat += "[TextPreview(features["flavor_text"])]... " + if(config.mutant_races)//really don't need this check, but fuck un-tabbing all those lines + dat += " Body" + dat += "Gender: [gender == MALE ? "Male" : "Female"]" + dat += "Species:[pref_species.id] " + dat += "Random Body " + dat += "Always Random Body: [be_random_body ? "Yes" : "No"] " + if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits)) + dat += "Primary Color: Change " + dat += "Secondary Color: Change " + dat += "Tertiary Color: Change " + if(pref_species.use_skintones) + dat += "Skin Tone: [skin_tone] " + dat += "Genitals Use Skintone:[features["genitals_use_skintone"] == TRUE ? "Enabled" : "Disabled"] " + + if(HAIR in pref_species.species_traits) + dat += "Hair Style: [hair_style] " + dat += "Hair Color: Change " + dat += "Facial Hair Style: [facial_hair_style] " + dat += "Facial Hair Color: Change " + if(EYECOLOR in pref_species.species_traits) + dat += "Eye Color: Change " + if("tail_lizard" in pref_species.mutant_bodyparts) + dat += "Tail: [features["tail_lizard"]] " + else if("mam_tail" in pref_species.mutant_bodyparts) + dat += "Tail: [features["mam_tail"]] " + else if("tail_human" in pref_species.mutant_bodyparts) + dat += "Tail: [features["tail_human"]] " + if("snout" in pref_species.mutant_bodyparts) + dat += "Snout: [features["snout"]] " + if("horns" in pref_species.mutant_bodyparts) + dat += "Snout: [features["horns"]] " + if("frills" in pref_species.mutant_bodyparts) + dat += "Frills: [features["frills"]] " + if("spines" in pref_species.mutant_bodyparts) + dat += "Spines: [features["spines"]] " + if("body_markings" in pref_species.mutant_bodyparts) + dat += "Body Markings: [features["body_markings"]] " + else if("mam_body_markings" in pref_species.mutant_bodyparts) + dat += "Body Markings: [features["mam_body_markings"]] " + if("mam_ears" in pref_species.mutant_bodyparts) + dat += "Ears: [features["mam_ears"]] " + else if("ears" in pref_species.mutant_bodyparts) + dat += "Ears: [features["ears"]] " + if("legs" in pref_species.mutant_bodyparts) + dat += "Legs: [features["legs"]] " + if("taur" in pref_species.mutant_bodyparts) + dat += "Taur: [features["taur"]] " + if("wings" in pref_species.mutant_bodyparts && GLOB.r_wings_list.len >1) + dat += "Wings: [features["wings"]] " + if("xenohead" in pref_species.mutant_bodyparts) + dat += "Caste: [features["xenohead"]] " + if("xenotail" in pref_species.mutant_bodyparts) + dat += "Tail: [features["xenotail"]] " + if("xenodorsal" in pref_species.mutant_bodyparts) + dat += "Dorsal Tubes: [features["xenodorsal"]] " + + dat += " | "
+
+
+ dat += "Clothing & Equipment" +//underwear will be refactored later so it fits in with other wearable equipment and isn't just an overlay +// dat += "Underwear:[underwear]" +// dat += "Undershirt:[undershirt] " +// dat += "Socks:[socks] " + dat += "Backpack:[backbag] " + dat += "Uplink Location:[uplink_spawn_loc] " + + dat += " Genitals" + if(NOGENITALS in pref_species.species_traits) + dat += "Your species ([pref_species.name]) does not support genitals!" + else + dat += "Has Penis:[features["has_cock"] == TRUE ? "Yes" : "No"] " + if(features["has_cock"] == TRUE) + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Penis Color: (Skin tone overriding) " + else + dat += "Penis Color: Change " +// dat += " " + dat += "Penis Shape: [features["cock_shape"]] " + dat += "Penis Length: [features["cock_length"]] inch(es) " + dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"] " + if(features["has_balls"] == TRUE) + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Testicles Color: (Skin tone overriding) " + else + dat += "Testicles Color: Change " + dat += "Has Vagina:[features["has_vag"] == TRUE ? "Yes" : "No"] " + if(features["has_vag"]) + dat += "Vagina Type: [features["vag_shape"]] " + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Vagina Color: (Skin tone overriding) " + else + dat += "Vagina Color: Change " + dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"] " + dat += "Has Breasts:[features["has_breasts"] == TRUE ? "Yes" : "No"] " + if(features["has_breasts"]) + if(pref_species.use_skintones && features["genitals_use_skintone"] == TRUE) + dat += "Color: (Skin tone overriding) " + else + dat += "Color: Change " + dat += "Cup Size:[features["breasts_size"]] " + dat += "Breast Shape:[features["breasts_shape"]] " + /* + dat += " Ovipositor" + dat += "Has Ovipositor:[features["has_ovi"] == TRUE ? "Yes" : "No"]" + if(features["has_ovi"]) + dat += "Ovi Color: Change" + dat += "Eggsack" + dat += "Has Eggsack:[features["has_eggsack"] == TRUE ? "Yes" : "No"]" + if(features["has_eggsack"] == TRUE) + dat += "Color: Change" + dat += "Egg Color: Change" + dat += "Egg Size:[features["eggsack_egg_size"]]\" Diameter" + + dat += " | "
+ */
+
+
+ dat += "
" // Table within a table for alignment, also allows you to easily add more colomns.
+ HTML += "
|
|