diff --git a/SQL/README.md b/SQL/README.md new file mode 100644 index 00000000000..e11e0706a32 --- /dev/null +++ b/SQL/README.md @@ -0,0 +1,81 @@ +### Prerequisites + +The server connects to a mysql-compatible server (mysql, mariadb, percona), so you'll need one of those with a database and user/password pair ready. + +We use [flyway](https://flywaydb.org/) to manage database migrations. To set up the database, you'll need to [download flyway](https://flywaydb.org/getstarted/download.html). + +You'll also need some proficiency with the command line. + +---- + +### Attribution + +Credit to Mloc from Baystation12 for the initial readme. + +--- + +### Creating migrations + +As a coder, creating migrations is relatively easy. And they're a lot more flexible than just updating the initial schema would be. + +First, figure out the changes you need to make. From table alteration and creation commands, to simply update and insert statements. + +Write them into a .sql file in the SQL/migrate folder, in a valid order of execution. Name the file in the following format: + + Vxxx__Description_goes_here.sql + +Where `xxx` is the next version number from the last existing file (include the 0s), and the descrption is a short description for the migration, with spaces replaced by underscores. + +Push this to your branch, and you're done! + +--- + +### Initial setup + +In the root project directory, run: + + path/to/flyway migrate -user=USER -password=PASSWORD -url=jdbc:mysql://HOST/DATABASE + +Where USER is your mysql username, PASSWORD is your mysql password, HOST is the hostname of the mysql server and DATABASE is the database to use. + +--- + +### Migrating + +Use the same command as above. Handy, isn't it? + +--- + +### Using a pre-flyway database + +**Note that this is not recommended!** +You may run into issues with some migrations, due to improper versioning. The best way to utilize this system is to set everything up on an empty schema. +The next alternative is to make sure your database structure matches the V001 file within the migrate folder by manually modifying the structure to avoid dataloss, and then doing the steps described below. + +If you're using a database since before we moved to flyway, it's a bit more involved to get migrations working. + +In the root project directory, run: + + path/to/flyway baseline -user=USER -password=PASSWORD -url=jdbc:mysql://HOST/DATABASE -baselineVersion=001 -baselineDescription="Initial schema" + +From there, you can run migrations as normal. + +--- + +### Configuration file + +Instead of putting -user, -password and -url in the command line every time you execute flyway, you can use a config file. Create it somewhere in the root of your project (we're calling it 'db.conf'): + + flyway.url=jdbc:mysql://HOST/DATABASE + flyway.user=USER + flyway.password=PASSWORD + +Now you can just run `flyway migrate -configFile=db.conf`, and the settings will be loaded from config. + +--- + +### Misc tables + +We included a set of miscellanious tables in the misc folder. These are primarily used for debugging and are not meant to be pushed into production. As such, they're not included in the migration folder. + +Ignoring or implementing them should not cause issues with the system. diff --git a/SQL/Aurora_SQL_Schema.sql b/SQL/migrate/V001__Initial_schema.sql similarity index 57% rename from SQL/Aurora_SQL_Schema.sql rename to SQL/migrate/V001__Initial_schema.sql index 0e968a2c521..74fce0b0a63 100644 --- a/SQL/Aurora_SQL_Schema.sql +++ b/SQL/migrate/V001__Initial_schema.sql @@ -1,15 +1,92 @@ -CREATE DATABASE `spacestation13` /*!40100 DEFAULT CHARACTER SET utf8 */; +-- ------------------------------------------------------------ +-- These are BOREALIS' tables. Some are actively used ingame, +-- hence why they're bundled in here. +-- ------------------------------------------------------------ -CREATE TABLE `ss13_admin` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) CHARACTER SET latin1 NOT NULL, - `rank` varchar(32) CHARACTER SET latin1 NOT NULL DEFAULT 'Administrator', - `level` int(2) NOT NULL DEFAULT '0', - `flags` int(16) NOT NULL DEFAULT '0', - `discord_id` varchar(45) NOT NULL DEFAULT '', +-- +-- BOREALIS' table for bans +-- + +CREATE TABLE `discord_bans` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` varchar(45) NOT NULL, + `user_name` varchar(45) NOT NULL, + `server_id` varchar(45) NOT NULL, + `ban_type` varchar(45) NOT NULL, + `ban_duration` int(11) NOT NULL DEFAULT '-1', + `ban_reason` longtext, + `ban_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expiration_time` datetime NOT NULL, + `admin_id` varchar(45) DEFAULT NULL, + `admin_name` varchar(45) DEFAULT 'BOREALIS', + `ban_lifted` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- BOREALIS' table for channels +-- + +CREATE TABLE `discord_channels` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `channel_group` varchar(32) NOT NULL, + `channel_id` text NOT NULL, + `pin_flag` int(11) NOT NULL DEFAULT '0', + `server_id` varchar(45) NOT NULL DEFAULT '', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- BOREALIS' table for logs +-- + +CREATE TABLE `discord_log` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `action_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `action` text NOT NULL, + `admin_id` varchar(45) DEFAULT NULL, + `user_id` varchar(45) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- BOREALIS' table for strikes +-- + +CREATE TABLE `discord_strikes` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` varchar(45) NOT NULL, + `user_name` varchar(45) NOT NULL, + `action_type` varchar(45) NOT NULL DEFAULT 'WARNING', + `strike_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `admin_id` varchar(45) NOT NULL, + `admin_name` varchar(45) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- BOREALIS' table for subscriptions +-- + +CREATE TABLE `discord_subscribers` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` varchar(45) NOT NULL, + `once` tinyint(1) NOT NULL DEFAULT '0', + `subscribed_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `expired_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- ------------------------------------------------------------ +-- SS13 tables begin here. All of these are actively used. +-- Note that some are used by the WebInterface, but if so, +-- it's done in support of ingame systems. +-- ------------------------------------------------------------ + +-- +-- Table for admin rank alterations +-- + CREATE TABLE `ss13_admin_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -19,43 +96,50 @@ CREATE TABLE `ss13_admin_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `ss13_api_commands` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `command` VARCHAR(50) NOT NULL COLLATE 'utf8_bin', - `description` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_bin', - PRIMARY KEY (`id`), - UNIQUE INDEX `UNIQUE command` (`command`) -) -COLLATE='utf8_bin' -ENGINE=InnoDB; +-- +-- Table for the server-supported API/world.Topic commands +-- +CREATE TABLE `ss13_api_commands` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `command` varchar(50) COLLATE utf8_bin NOT NULL, + `description` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UNIQUE command` (`command`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- +-- Table for auth tokens for world.Topic +-- CREATE TABLE `ss13_api_tokens` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `token` VARCHAR(100) NOT NULL COLLATE 'utf8_bin', - `ip` VARCHAR(16) NULL DEFAULT NULL COLLATE 'utf8_bin', - `creator` VARCHAR(50) NOT NULL COLLATE 'utf8_bin', - `description` VARCHAR(100) NOT NULL COLLATE 'utf8_bin', - `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `deleted_at` DATETIME NULL DEFAULT NULL, - PRIMARY KEY (`id`) -) -COLLATE='utf8_bin' -ENGINE=InnoDB; + `id` int(11) NOT NULL AUTO_INCREMENT, + `token` varchar(100) COLLATE utf8_bin NOT NULL, + `ip` varchar(16) COLLATE utf8_bin DEFAULT NULL, + `creator` varchar(50) COLLATE utf8_bin NOT NULL, + `description` varchar(100) COLLATE utf8_bin NOT NULL, + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- +-- Table to describe which tokens can access what commands for world.Topic +-- CREATE TABLE `ss13_api_token_command` ( - `command_id` INT(11) NOT NULL, - `token_id` INT(11) NOT NULL, - PRIMARY KEY (`command_id`, `token_id`), - INDEX `token_id` (`token_id`), - CONSTRAINT `function_id` FOREIGN KEY (`command_id`) REFERENCES `ss13_api_commands` (`id`) ON UPDATE CASCADE ON DELETE CASCADE, - CONSTRAINT `token_id` FOREIGN KEY (`token_id`) REFERENCES `ss13_api_tokens` (`id`) ON UPDATE CASCADE ON DELETE CASCADE -) -COLLATE='utf8_bin' -ENGINE=InnoDB; - + `command_id` int(11) NOT NULL, + `token_id` int(11) NOT NULL, + PRIMARY KEY (`command_id`,`token_id`), + KEY `token_id` (`token_id`), + CONSTRAINT `function_id` FOREIGN KEY (`command_id`) REFERENCES `ss13_api_commands` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `token_id` FOREIGN KEY (`token_id`) REFERENCES `ss13_api_tokens` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +-- +-- Table for bans issued +-- CREATE TABLE `ss13_ban` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -78,13 +162,17 @@ CREATE TABLE `ss13_ban` ( `edits` text CHARACTER SET latin1, `unbanned` tinyint(1) DEFAULT NULL, `unbanned_datetime` datetime DEFAULT NULL, - `unbanned_reason` text CHARACTER SET latin1 DEFAULT NULL, + `unbanned_reason` text, `unbanned_ckey` varchar(32) CHARACTER SET latin1 DEFAULT NULL, `unbanned_computerid` varchar(32) CHARACTER SET latin1 DEFAULT NULL, `unbanned_ip` varchar(32) CHARACTER SET latin1 DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for ban-mirroring, used to catch ban dodgers +-- + CREATE TABLE `ss13_ban_mirrors` ( `ban_mirror_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `ban_id` int(10) unsigned NOT NULL, @@ -95,6 +183,24 @@ CREATE TABLE `ss13_ban_mirrors` ( PRIMARY KEY (`ban_mirror_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for housing CCIA notices to be sent mid-round +-- + +CREATE TABLE `ss13_ccia_general_notice_list` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `message` text COLLATE utf8_unicode_ci NOT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table for player information +-- + CREATE TABLE `ss13_player` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ckey` varchar(32) CHARACTER SET latin1 NOT NULL, @@ -109,95 +215,237 @@ CREATE TABLE `ss13_player` ( UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for linking requests between the Web-Interface and game server +-- + +CREATE TABLE `ss13_player_linking` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `forum_id` int(11) NOT NULL, + `forum_username_short` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `forum_username` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `player_ckey` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `status` enum('new','confirmed','rejected','linked') COLLATE utf8_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table for player personal-AI preferences +-- + +CREATE TABLE `ss13_player_pai` ( + `ckey` varchar(32) NOT NULL, + `name` varchar(50) DEFAULT NULL, + `description` text, + `role` text, + `comments` text, + PRIMARY KEY (`ckey`), + CONSTRAINT `player_pai_fk_ckey` FOREIGN KEY (`ckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Table for general player preferences +-- + +CREATE TABLE `ss13_player_preferences` ( + `ckey` varchar(32) NOT NULL, + `ooccolor` text, + `lastchangelog` text, + `UI_style` text, + `current_character` int(11) DEFAULT '0', + `toggles` int(11) DEFAULT '0', + `UI_style_color` text, + `UI_style_alpha` int(11) DEFAULT '255', + `asfx_togs` int(11) DEFAULT '0', + `lastmotd` text, + `lastmemo` text, + `language_prefixes` text, + PRIMARY KEY (`ckey`), + CONSTRAINT `player_preferences_fk_ckey` FOREIGN KEY (`ckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Table for holding admin ranks +-- + +CREATE TABLE `ss13_admin` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `ckey` varchar(32) CHARACTER SET latin1 NOT NULL, + `rank` varchar(32) CHARACTER SET latin1 NOT NULL DEFAULT 'Administrator', + `level` int(2) NOT NULL DEFAULT '0', + `flags` int(16) NOT NULL DEFAULT '0', + `discord_id` varchar(45) NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `UNIQUE` (`ckey`), + CONSTRAINT `ckey` FOREIGN KEY (`ckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table for initial character data +-- + CREATE TABLE `ss13_characters` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ckey` varchar(32) NOT NULL, - `name` varchar(128) NULL DEFAULT NULL, - `metadata` varchar(512) NULL DEFAULT NULL, - `be_special_role` text NULL DEFAULT NULL, - `gender` varchar(32) NULL DEFAULT NULL, - `age` int(11) NULL DEFAULT NULL, - `species` varchar(32) NULL DEFAULT NULL, - `language` text NULL DEFAULT NULL, - `hair_colour` varchar(7) NULL DEFAULT NULL, - `facial_colour` varchar(7) NULL DEFAULT NULL, - `skin_tone` int(11) NULL DEFAULT NULL, - `skin_colour` varchar(7) NULL DEFAULT NULL, - `hair_style` varchar(32) NULL DEFAULT NULL, - `facial_style` varchar(32) NULL DEFAULT NULL, - `eyes_colour` varchar(7) NULL DEFAULT NULL, - `underwear` varchar(32) NULL DEFAULT NULL, - `undershirt` varchar(32) NULL DEFAULT NULL, - `socks` varchar(32) NULL DEFAULT NULL, - `backbag` int(11) NULL DEFAULT NULL, - `b_type` varchar(32) NULL DEFAULT NULL, - `spawnpoint` varchar(32) NULL DEFAULT NULL, - `jobs` text NULL DEFAULT NULL, + `name` varchar(128) DEFAULT NULL, + `metadata` varchar(512) DEFAULT NULL, + `be_special_role` text, + `gender` varchar(32) DEFAULT NULL, + `age` int(11) DEFAULT NULL, + `species` varchar(32) DEFAULT NULL, + `language` varchar(50) DEFAULT NULL, + `hair_colour` varchar(7) DEFAULT NULL, + `facial_colour` varchar(7) DEFAULT NULL, + `skin_tone` int(11) DEFAULT NULL, + `skin_colour` varchar(7) DEFAULT NULL, + `hair_style` varchar(32) DEFAULT NULL, + `facial_style` varchar(32) DEFAULT NULL, + `eyes_colour` varchar(7) DEFAULT NULL, + `underwear` varchar(32) DEFAULT NULL, + `undershirt` varchar(32) DEFAULT NULL, + `socks` varchar(32) DEFAULT NULL, + `backbag` int(11) DEFAULT NULL, + `b_type` varchar(32) DEFAULT NULL, + `spawnpoint` varchar(32) DEFAULT NULL, + `jobs` text, `alternate_option` tinyint(1) DEFAULT NULL, - `alternate_titles` text NULL DEFAULT NULL, + `alternate_titles` text, `disabilities` int(11) DEFAULT '0', - `skills` text NULL DEFAULT NULL, - `skill_specialization` text NULL DEFAULT NULL, - `home_system` text NULL DEFAULT NULL, - `citizenship` text NULL DEFAULT NULL, - `faction` text NULL DEFAULT NULL, - `religion` text NULL DEFAULT NULL, - `nt_relation` text NULL DEFAULT NULL, - `uplink_location` text NULL DEFAULT NULL, - `organs_data` text NULL DEFAULT NULL, - `organs_robotic` text NULL DEFAULT NULL, - `gear` text NULL DEFAULT NULL, + `skills` text, + `skill_specialization` text, + `home_system` text, + `citizenship` text, + `faction` text, + `religion` text, + `nt_relation` text, + `uplink_location` text, + `organs_data` text, + `organs_robotic` text, + `gear` text, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `deleted_at` datetime NULL DEFAULT NULL, + `deleted_at` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `ss13_characters_ckey` (`ckey`), KEY `ss13_characteres_name` (`name`), CONSTRAINT `ss13_characters_fk_ckey` FOREIGN KEY (`ckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +-- +-- Table for character flavour text +-- + CREATE TABLE `ss13_characters_flavour` ( `char_id` int(11) NOT NULL, - `records_employment` text NULL DEFAULT NULL, - `records_medical` text NULL DEFAULT NULL, - `records_security` text NULL DEFAULT NULL, - `records_exploit` text NULL DEFAULT NULL, - `records_ccia` text NULL DEFAULT NULL, - `flavour_general` text NULL DEFAULT NULL, - `flavour_head` text NULL DEFAULT NULL, - `flavour_face` text NULL DEFAULT NULL, - `flavour_eyes` text NULL DEFAULT NULL, - `flavour_torso` text NULL DEFAULT NULL, - `flavour_arms` text NULL DEFAULT NULL, - `flavour_hands` text NULL DEFAULT NULL, - `flavour_legs` text NULL DEFAULT NULL, - `flavour_feet` text NULL DEFAULT NULL, - `robot_default` text NULL DEFAULT NULL, - `robot_standard` text NULL DEFAULT NULL, - `robot_engineering` text NULL DEFAULT NULL, - `robot_construction` text NULL DEFAULT NULL, - `robot_medical` text NULL DEFAULT NULL, - `robot_rescue` text NULL DEFAULT NULL, - `robot_miner` text NULL DEFAULT NULL, - `robot_custodial` text NULL DEFAULT NULL, - `robot_service` text NULL DEFAULT NULL, - `robot_clerical` text NULL DEFAULT NULL, - `robot_security` text NULL DEFAULT NULL, - `robot_research` text NULL DEFAULT NULL, + `records_employment` text, + `records_medical` text, + `records_security` text, + `records_exploit` text, + `records_ccia` text, + `flavour_general` text, + `flavour_head` text, + `flavour_face` text, + `flavour_eyes` text, + `flavour_torso` text, + `flavour_arms` text, + `flavour_hands` text, + `flavour_legs` text, + `flavour_feet` text, + `robot_default` text, + `robot_standard` text, + `robot_engineering` text, + `robot_construction` text, + `robot_medical` text, + `robot_rescue` text, + `robot_miner` text, + `robot_custodial` text, + `robot_service` text, + `robot_clerical` text, + `robot_security` text, + `robot_research` text, PRIMARY KEY (`char_id`), CONSTRAINT `ss13_flavour_fk_char_id` FOREIGN KEY (`char_id`) REFERENCES `ss13_characters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +-- +-- Table for housing IC criminal records +-- + +CREATE TABLE `ss13_character_incidents` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `char_id` int(11) NOT NULL, + `UID` varchar(32) COLLATE utf8_bin NOT NULL, + `datetime` varchar(50) COLLATE utf8_bin NOT NULL, + `notes` text COLLATE utf8_bin NOT NULL, + `charges` text COLLATE utf8_bin NOT NULL, + `evidence` text COLLATE utf8_bin NOT NULL, + `arbiters` text COLLATE utf8_bin NOT NULL, + `brig_sentence` int(11) NOT NULL DEFAULT '0', + `fine` int(11) NOT NULL DEFAULT '0', + `felony` int(11) NOT NULL DEFAULT '0', + `created_by` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `deleted_by` varchar(50) COLLATE utf8_bin DEFAULT NULL, + `game_id` varchar(50) COLLATE utf8_bin NOT NULL, + `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `deleted_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UID_char_id` (`char_id`,`UID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- +-- Table for logging which characters have joined rounds when +-- + CREATE TABLE `ss13_characters_log` ( - `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, - `char_id` INT(11) NOT NULL, - `game_id` VARCHAR(50) NOT NULL, - `datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `job_name` VARCHAR(32) NOT NULL, - `special_role` VARCHAR(32) NULL DEFAULT NULL, - PRIMARY KEY (`id`), - CONSTRAINT `ss13_charlog_fk_char_id` FOREIGN KEY (`char_id`) REFERENCES `ss13_characters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `char_id` int(11) NOT NULL, + `game_id` varchar(50) NOT NULL, + `datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + `job_name` varchar(32) DEFAULT NULL, + `special_role` varchar(32) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `ss13_charlog_fk_char_id` (`char_id`), + CONSTRAINT `ss13_charlog_fk_char_id` FOREIGN KEY (`char_id`) REFERENCES `ss13_characters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for CCIA actions taken against characters +-- + +CREATE TABLE `ss13_ccia_actions` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `title` text COLLATE utf8_unicode_ci NOT NULL, + `type` enum('injunction','suspension','warning','other') COLLATE utf8_unicode_ci NOT NULL, + `issuedby` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `details` text COLLATE utf8_unicode_ci NOT NULL, + `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `expires_at` date DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Bridge table between `ss13_ccia_actions` and `ss13_characters` +-- + +CREATE TABLE `ss13_ccia_action_char` ( + `action_id` int(10) unsigned NOT NULL, + `char_id` int(11) NOT NULL, + PRIMARY KEY (`action_id`,`char_id`), + KEY `ccia_action_char_char_id_foreign` (`char_id`), + CONSTRAINT `ccia_action_char_action_id_foreign` FOREIGN KEY (`action_id`) REFERENCES `ss13_ccia_actions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `ccia_action_char_char_id_foreign` FOREIGN KEY (`char_id`) REFERENCES `ss13_characters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table for logging player connections +-- + CREATE TABLE `ss13_connection_log` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `ckey` varchar(32) NOT NULL, @@ -208,12 +456,20 @@ CREATE TABLE `ss13_connection_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for antag contest participants +-- + CREATE TABLE `ss13_contest_participants` ( `player_ckey` varchar(32) NOT NULL, `character_id` int(10) unsigned NOT NULL, `contest_faction` enum('INDEP','SLF','BIS','ASI','PSIS','HSH','TCD') NOT NULL DEFAULT 'INDEP' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for antag contenst reports +-- + CREATE TABLE `ss13_contest_reports` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `player_ckey` varchar(32) NOT NULL, @@ -223,17 +479,13 @@ CREATE TABLE `ss13_contest_reports` ( `objective_side` enum('pro_synth','anti_synth') NOT NULL, `objective_outcome` tinyint(1) DEFAULT '0', `objective_datetime` datetime NOT NULL, + `duplicate` int(1) unsigned DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `ss13_customitems` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) CHARACTER SET latin1 NOT NULL, - `real_name` varchar(32) CHARACTER SET latin1 NOT NULL, - `item` varchar(124) CHARACTER SET latin1 NOT NULL, - `job` text CHARACTER SET latin1, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for death statistics +-- CREATE TABLE `ss13_death` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -254,6 +506,10 @@ CREATE TABLE `ss13_death` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for housing station directives +-- + CREATE TABLE `ss13_directives` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(64) CHARACTER SET latin1 NOT NULL, @@ -261,6 +517,10 @@ CREATE TABLE `ss13_directives` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for round statistics +-- + CREATE TABLE `ss13_feedback` ( `id` int(11) NOT NULL AUTO_INCREMENT, `time` datetime NOT NULL, @@ -271,6 +531,10 @@ CREATE TABLE `ss13_feedback` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for ingame forms +-- + CREATE TABLE `ss13_forms` ( `form_id` int(11) NOT NULL AUTO_INCREMENT, `id` varchar(4) CHARACTER SET latin1 NOT NULL, @@ -281,6 +545,22 @@ CREATE TABLE `ss13_forms` ( PRIMARY KEY (`form_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for tracking IPC implants +-- + +CREATE TABLE `ss13_ipc_tracking` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `player_ckey` varchar(32) NOT NULL, + `character_name` varchar(255) NOT NULL, + `tag_status` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Table for the ingame library +-- + CREATE TABLE `ss13_library` ( `id` int(11) NOT NULL AUTO_INCREMENT, `author` text CHARACTER SET latin1 NOT NULL, @@ -292,21 +572,9 @@ CREATE TABLE `ss13_library` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `ss13_news` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `publishtime` int(11) NOT NULL, - `channel` varchar(64) CHARACTER SET latin1 NOT NULL, - `author` varchar(64) CHARACTER SET latin1 NOT NULL, - `title` varchar(64) CHARACTER SET latin1 DEFAULT NULL, - `body` text CHARACTER SET latin1 NOT NULL, - `notpublishing` tinyint(1) DEFAULT '0', - `approved` tinyint(1) DEFAULT '0', - `status` tinyint(1) NOT NULL DEFAULT '1', - `uploadip` varchar(18) CHARACTER SET latin1 NOT NULL, - `uploadtime` datetime NOT NULL, - `approvetime` datetime DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for player notes +-- CREATE TABLE `ss13_notes` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -323,35 +591,9 @@ CREATE TABLE `ss13_notes` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE `ss13_player_linking` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `forum_id` int(11) NOT NULL, - `forum_username_short` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `forum_username` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `player_ckey` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `status` enum('new','confirmed','rejected','linked') COLLATE utf8_unicode_ci NOT NULL, - `created_at` timestamp NULL DEFAULT NULL, - `updated_at` timestamp NULL DEFAULT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -CREATE TABLE `ss13_player_preferences` ( - `ckey` varchar(32) NOT NULL, - `ooccolor` text NULL DEFAULT NULL, - `lastchangelog` text NULL DEFAULT NULL, - `UI_style` text NULL DEFAULT NULL, - `current_character` int(11) NULL DEFAULT NULL, - `toggles` int(11) DEFAULT '0', - `UI_style_color` text NULL DEFAULT NULL, - `UI_style_alpha` int(11) NULL DEFAULT '255', - `asfx_togs` int(11) DEFAULT '0', - `lastmotd` text NULL DEFAULT NULL, - `lastmemo` text NULL DEFAULT NULL, - `language_prefixes` text NULL DEFAULT NULL, - PRIMARY KEY (`ckey`), - CONSTRAINT `player_preferences_fk_ckey` FOREIGN KEY (`ckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +-- +-- Table for ingame poll options +-- CREATE TABLE `ss13_poll_option` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -366,6 +608,10 @@ CREATE TABLE `ss13_poll_option` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for ingame poll questions +-- + CREATE TABLE `ss13_poll_question` ( `id` int(11) NOT NULL AUTO_INCREMENT, `polltype` varchar(16) CHARACTER SET latin1 NOT NULL DEFAULT 'OPTION', @@ -377,6 +623,10 @@ CREATE TABLE `ss13_poll_question` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for ingame poll text/freeform replies +-- + CREATE TABLE `ss13_poll_textreply` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -388,6 +638,10 @@ CREATE TABLE `ss13_poll_textreply` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for ingame poll votes +-- + CREATE TABLE `ss13_poll_vote` ( `id` int(11) NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -400,13 +654,21 @@ CREATE TABLE `ss13_poll_vote` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for tracking ingame population counts +-- + CREATE TABLE `ss13_population` ( `id` int(11) NOT NULL AUTO_INCREMENT, `playercount` int(11) DEFAULT NULL, `admincount` int(11) DEFAULT NULL, `time` datetime NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=69279 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table for player privacy preferences +-- CREATE TABLE `ss13_privacy` ( `id` int(11) NOT NULL AUTO_INCREMENT, @@ -416,6 +678,27 @@ CREATE TABLE `ss13_privacy` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for ingame santa clause event +-- + +CREATE TABLE `ss13_santa` ( + `character_name` varchar(32) NOT NULL, + `participation_status` tinyint(1) NOT NULL DEFAULT '1', + `is_assigned` tinyint(1) NOT NULL DEFAULT '0', + `mark_name` varchar(32) DEFAULT NULL, + `character_gender` varchar(32) NOT NULL, + `character_species` varchar(32) NOT NULL, + `character_job` varchar(32) NOT NULL, + `character_like` mediumtext NOT NULL, + `gift_assigned` varchar(255) DEFAULT NULL, + PRIMARY KEY (`character_name`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +-- +-- Table for syndicate contracts +-- + CREATE TABLE `ss13_syndie_contracts` ( `contract_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `contractee_id` int(11) NOT NULL, @@ -433,10 +716,14 @@ CREATE TABLE `ss13_syndie_contracts` ( PRIMARY KEY (`contract_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- +-- Table for comments to syndicate contracts +-- + CREATE TABLE `ss13_syndie_contracts_comments` ( `comment_id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `contract_id` int(11) NOT NULL, - `commentor_id` int(11) NOT NULL, + `contract_id` int(11) unsigned NOT NULL, + `commentor_id` int(11) unsigned NOT NULL, `commentor_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `comment` text COLLATE utf8_unicode_ci NOT NULL, @@ -445,9 +732,62 @@ CREATE TABLE `ss13_syndie_contracts_comments` ( `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL, `deleted_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`comment_id`) + `report_status` enum('waiting-approval','accepted','rejected') COLLATE utf8_unicode_ci DEFAULT NULL, + PRIMARY KEY (`comment_id`), + KEY `contract_id` (`contract_id`), + CONSTRAINT `contract_id` FOREIGN KEY (`contract_id`) REFERENCES `ss13_syndie_contracts` (`contract_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- +-- Bridge table between contract comment data and player table +-- + +CREATE TABLE `ss13_syndie_contracts_comments_completers` ( + `user_id` int(11) NOT NULL, + `comment_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`user_id`,`comment_id`), + KEY `comment_id` (`comment_id`), + CONSTRAINT `comment_id` FOREIGN KEY (`comment_id`) REFERENCES `ss13_syndie_contracts_comments` (`comment_id`) ON DELETE CASCADE, + CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `ss13_player` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table for individual contract objectives +-- + +CREATE TABLE `ss13_syndie_contracts_objectives` ( + `objective_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `contract_id` int(11) NOT NULL, + `status` enum('open','closed','deleted') COLLATE utf8_unicode_ci NOT NULL, + `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `description` text COLLATE utf8_unicode_ci NOT NULL, + `reward_credits` int(11) DEFAULT NULL, + `reward_credits_update` int(11) DEFAULT NULL, + `reward_other` text COLLATE utf8_unicode_ci, + `reward_other_update` text COLLATE utf8_unicode_ci, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + PRIMARY KEY (`objective_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Bridge table between contract objectives and comments +-- + +CREATE TABLE `ss13_syndie_contracts_comments_objectives` ( + `objective_id` int(10) unsigned NOT NULL, + `comment_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`objective_id`,`comment_id`), + KEY `comments_comment_id` (`comment_id`), + CONSTRAINT `comments_comment_id` FOREIGN KEY (`comment_id`) REFERENCES `ss13_syndie_contracts_comments` (`comment_id`) ON DELETE CASCADE, + CONSTRAINT `objectives_objective_id` FOREIGN KEY (`objective_id`) REFERENCES `ss13_syndie_contracts_objectives` (`objective_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- +-- Table for contract subscribers +-- + CREATE TABLE `ss13_syndie_contracts_subscribers` ( `contract_id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned NOT NULL, @@ -455,6 +795,10 @@ CREATE TABLE `ss13_syndie_contracts_subscribers` ( CONSTRAINT `syndie_contracts_subscribers_contract_id_foreign` FOREIGN KEY (`contract_id`) REFERENCES `ss13_syndie_contracts` (`contract_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- +-- Table for player warnings +-- + CREATE TABLE `ss13_warnings` ( `id` int(11) NOT NULL AUTO_INCREMENT, `time` datetime NOT NULL, @@ -476,6 +820,10 @@ CREATE TABLE `ss13_warnings` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- +-- Table for housing tokens for the WebInterface SSO from within the game +-- + CREATE TABLE `ss13_web_sso` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `ckey` varchar(255) COLLATE utf8_unicode_ci NOT NULL, @@ -485,6 +833,10 @@ CREATE TABLE `ss13_web_sso` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +-- +-- Table for logging whitelist alterations +-- + CREATE TABLE `ss13_whitelist_log` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `datetime` datetime NOT NULL, @@ -494,93 +846,13 @@ CREATE TABLE `ss13_whitelist_log` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +-- +-- Table for storing whitelist bitkeys +-- + CREATE TABLE `ss13_whitelist_statuses` ( `flag` int(10) unsigned NOT NULL, `status_name` varchar(32) NOT NULL, `subspecies` tinyint(4) NOT NULL DEFAULT '1', PRIMARY KEY (`status_name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -CREATE TABLE `ss13_stats_ie` ( - `ckey` varchar(32) NOT NULL, - `IsIE` tinyint(4) NOT NULL, - `IsEdge` tinyint(4) NOT NULL, - `EdgeHtmlVersion` int(11) NOT NULL, - `TrueVersion` tinyint(4) NOT NULL, - `ActingVersion` tinyint(4) NOT NULL, - `CompatibilityMode` tinyint(4) NOT NULL, - `DateUpdated` datetime DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`ckey`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `ss13_character_incidents` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `char_id` INT(11) NOT NULL, - `UID` VARCHAR(32) NOT NULL COLLATE 'utf8_bin', - `datetime` VARCHAR(50) NOT NULL COLLATE 'utf8_bin', - `notes` TEXT NOT NULL COLLATE 'utf8_bin', - `charges` TEXT NOT NULL COLLATE 'utf8_bin', - `evidence` TEXT NOT NULL COLLATE 'utf8_bin', - `arbiters` TEXT NOT NULL COLLATE 'utf8_bin', - `brig_sentence` INT(11) NOT NULL DEFAULT '0', - `fine` INT(11) NOT NULL DEFAULT '0', - `felony` INT(11) NOT NULL DEFAULT '0', - `created_by` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin', - `deleted_by` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8_bin', - `game_id` VARCHAR(50) NOT NULL COLLATE 'utf8_bin', - `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `deleted_at` DATETIME NULL DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE INDEX `UID_char_id` (`char_id`, `UID`) -) COLLATE='utf8_bin' ENGINE=InnoDB; - -CREATE TABLE `discord_channels` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `channel_group` varchar(32) NOT NULL, - `channel_id` text NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `ss13_ccia_actions` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` text COLLATE utf8_unicode_ci NOT NULL, - `type` enum('injunction','suspension','warning','other') COLLATE utf8_unicode_ci NOT NULL, - `issuedby` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `details` text COLLATE utf8_unicode_ci NOT NULL, - `url` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `expires_at` date DEFAULT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - `created_at` timestamp NULL DEFAULT NULL, - `updated_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -CREATE TABLE `ss13_ccia_action_char` ( - `action_id` int(10) unsigned NOT NULL, - `char_id` int(11) NOT NULL, - PRIMARY KEY (`action_id`,`char_id`), - KEY `ccia_action_char_char_id_foreign` (`char_id`), - CONSTRAINT `ccia_action_char_action_id_foreign` FOREIGN KEY (`action_id`) REFERENCES `ss13_ccia_actions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `ccia_action_char_char_id_foreign` FOREIGN KEY (`char_id`) REFERENCES `ss13_characters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -CREATE TABLE `ss13_ccia_general_notice_list` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `message` text COLLATE utf8_unicode_ci NOT NULL, - `deleted_at` timestamp NULL DEFAULT NULL, - `created_at` timestamp NULL DEFAULT NULL, - `updated_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - -CREATE TABLE `ss13_player_pai` ( - `ckey` VARCHAR(32) NOT NULL, - `name` VARCHAR(50) NULL DEFAULT NULL, - `description` TEXT NULL DEFAULT NULL, - `role` TEXT NULL DEFAULT NULL, - `comments` TEXT NULL DEFAULT NULL, - PRIMARY KEY (`ckey`), - CONSTRAINT `player_pai_fk_ckey` FOREIGN KEY (`ckey`) REFERENCES `ss13_player` (`ckey`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/SQL/migrate/V002__Parallax_preferences.sql b/SQL/migrate/V002__Parallax_preferences.sql new file mode 100644 index 00000000000..3f1cec7c87f --- /dev/null +++ b/SQL/migrate/V002__Parallax_preferences.sql @@ -0,0 +1,7 @@ +-- +-- Adds parallax related preferences toggles for the player preferences table. +-- + +ALTER TABLE `ss13_player_preferences` + ADD `parallax_toggles` INT(11) NULL DEFAULT NULL, + ADD `parallax_speed` INT(11) NULL DEFAULT NULL; diff --git a/SQL/misc/Debug_tables.sql b/SQL/misc/Debug_tables.sql new file mode 100644 index 00000000000..f2222464266 --- /dev/null +++ b/SQL/misc/Debug_tables.sql @@ -0,0 +1,17 @@ +-- These are tables used only for debugging/profiling. +-- They are not needed for normal server operation. + +CREATE TABLE `ss13dbg_lighting` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `time` INT(11) NULL DEFAULT NULL COMMENT 'World time (in ticks)', + `type` VARCHAR(32) NULL DEFAULT NULL COMMENT 'The type of the update.', + `name` VARCHAR(50) NULL DEFAULT NULL COMMENT 'The callee\'s name.', + `loc_name` VARCHAR(50) NULL DEFAULT NULL COMMENT 'The callee\'s location.', + `x` SMALLINT(6) NULL DEFAULT NULL, + `y` SMALLINT(6) NULL DEFAULT NULL, + `z` SMALLINT(6) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) +COLLATE='utf8_general_ci' +ENGINE=MEMORY +ROW_FORMAT=FIXED; diff --git a/baystation12.dme b/baystation12.dme index d9e075b4cec..02beb727569 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -23,6 +23,7 @@ #include "code\__defines\chemistry.dm" #include "code\__defines\damage_organs.dm" #include "code\__defines\dna.dm" +#include "code\__defines\dview.dm" #include "code\__defines\gamemode.dm" #include "code\__defines\items_clothing.dm" #include "code\__defines\lighting.dm" @@ -78,6 +79,7 @@ #include "code\_onclick\hud\human.dm" #include "code\_onclick\hud\movable_screen_objects.dm" #include "code\_onclick\hud\other_mobs.dm" +#include "code\_onclick\hud\parallax.dm" #include "code\_onclick\hud\robot.dm" #include "code\_onclick\hud\screen_objects.dm" #include "code\_onclick\hud\spell_screen_objects.dm" @@ -136,6 +138,7 @@ #include "code\controllers\Processes\garbage.dm" #include "code\controllers\Processes\inactivity.dm" #include "code\controllers\Processes\law.dm" +#include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\machinery.dm" #include "code\controllers\Processes\mob.dm" #include "code\controllers\Processes\modifier.dm" @@ -632,6 +635,7 @@ #include "code\game\objects\items\devices\floor_painter.dm" #include "code\game\objects\items\devices\hacktool.dm" #include "code\game\objects\items\devices\holowarrant.dm" +#include "code\game\objects\items\devices\lightmeter.dm" #include "code\game\objects\items\devices\lightreplacer.dm" #include "code\game\objects\items\devices\magnetic_lock.dm" #include "code\game\objects\items\devices\megaphone.dm" @@ -1022,7 +1026,6 @@ #include "code\modules\client\preferences.dm" #include "code\modules\client\preferences_ambience.dm" #include "code\modules\client\preferences_factions.dm" -#include "code\modules\client\preferences_gear.dm" #include "code\modules\client\preferences_notification.dm" #include "code\modules\client\preferences_savefile.dm" #include "code\modules\client\preferences_spawnpoints.dm" @@ -1042,6 +1045,22 @@ #include "code\modules\client\preference_setup\global\02_settings.dm" #include "code\modules\client\preference_setup\global\03_language.dm" #include "code\modules\client\preference_setup\global\04_pai.dm" +#include "code\modules\client\preference_setup\loadout\gear_tweaks.dm" +#include "code\modules\client\preference_setup\loadout\loadout.dm" +#include "code\modules\client\preference_setup\loadout\loadout_accessories.dm" +#include "code\modules\client\preference_setup\loadout\loadout_cosmetics.dm" +#include "code\modules\client\preference_setup\loadout\loadout_ears.dm" +#include "code\modules\client\preference_setup\loadout\loadout_eyes.dm" +#include "code\modules\client\preference_setup\loadout\loadout_general.dm" +#include "code\modules\client\preference_setup\loadout\loadout_gloves.dm" +#include "code\modules\client\preference_setup\loadout\loadout_head.dm" +#include "code\modules\client\preference_setup\loadout\loadout_mask.dm" +#include "code\modules\client\preference_setup\loadout\loadout_shoes.dm" +#include "code\modules\client\preference_setup\loadout\loadout_smoking.dm" +#include "code\modules\client\preference_setup\loadout\loadout_suit.dm" +#include "code\modules\client\preference_setup\loadout\loadout_uniform.dm" +#include "code\modules\client\preference_setup\loadout\loadout_utility.dm" +#include "code\modules\client\preference_setup\loadout\loadout_xeno.dm" #include "code\modules\client\preference_setup\occupation\occupation.dm" #include "code\modules\client\preference_setup\other\01_incidents.dm" #include "code\modules\client\preference_setup\skills\skills.dm" @@ -1245,12 +1264,13 @@ #include "code\modules\library\lib_items.dm" #include "code\modules\library\lib_machines.dm" #include "code\modules\library\lib_readme.dm" -#include "code\modules\lighting\_lighting_defs.dm" -#include "code\modules\lighting\light_source.dm" +#include "code\modules\lighting\lighting_area.dm" #include "code\modules\lighting\lighting_atom.dm" +#include "code\modules\lighting\lighting_corner.dm" #include "code\modules\lighting\lighting_overlay.dm" -#include "code\modules\lighting\lighting_process.dm" -#include "code\modules\lighting\lighting_system.dm" +#include "code\modules\lighting\lighting_profiler.dm" +#include "code\modules\lighting\lighting_setup.dm" +#include "code\modules\lighting\lighting_source.dm" #include "code\modules\lighting\lighting_turf.dm" #include "code\modules\lighting\~lighting_undefs.dm" #include "code\modules\liquid\splash_simulation.dm" @@ -1281,6 +1301,7 @@ #include "code\modules\mining\drilling\scanner.dm" #include "code\modules\mob\animations.dm" #include "code\modules\mob\death.dm" +#include "code\modules\mob\dview.dm" #include "code\modules\mob\emote.dm" #include "code\modules\mob\gender.dm" #include "code\modules\mob\hear_say.dm" @@ -1610,9 +1631,6 @@ #include "code\modules\multiz\pipes.dm" #include "code\modules\multiz\structures.dm" #include "code\modules\multiz\turf.dm" -#include "code\modules\nano\_JSON.dm" -#include "code\modules\nano\JSON Reader.dm" -#include "code\modules\nano\JSON Writer.dm" #include "code\modules\nano\nanoexternal.dm" #include "code\modules\nano\nanomanager.dm" #include "code\modules\nano\nanomapgen.dm" @@ -1818,6 +1836,7 @@ #include "code\modules\reagents\reagent_containers\food\cans.dm" #include "code\modules\reagents\reagent_containers\food\condiment.dm" #include "code\modules\reagents\reagent_containers\food\drinks.dm" +#include "code\modules\reagents\reagent_containers\food\lunch.dm" #include "code\modules\reagents\reagent_containers\food\sandwich.dm" #include "code\modules\reagents\reagent_containers\food\snacks.dm" #include "code\modules\reagents\reagent_containers\food\drinks\bottle.dm" diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index b515c1225f1..ff12697c9db 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -137,13 +137,13 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0) if(firelevel > 6) icon_state = "3" - set_light(7, FIRE_LIGHT_3) + set_light(7, FIRE_LIGHT_3, update_type = UPDATE_NONE) // We set color later in the proc, that should trigger an update. else if(firelevel > 2.5) icon_state = "2" - set_light(5, FIRE_LIGHT_2) + set_light(5, FIRE_LIGHT_2, update_type = UPDATE_NONE) else icon_state = "1" - set_light(3, FIRE_LIGHT_1) + set_light(3, FIRE_LIGHT_1, update_type = UPDATE_NONE) for(var/mob/living/L in loc) L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs! @@ -439,4 +439,4 @@ datum/gas_mixture/proc/check_recombustability(list/fuel_objs) #undef FIRE_LIGHT_1 #undef FIRE_LIGHT_2 -#undef FIRE_LIGHT_3 \ No newline at end of file +#undef FIRE_LIGHT_3 diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm deleted file mode 100644 index 94668321c60..00000000000 --- a/code/__HELPERS/matrices.dm +++ /dev/null @@ -1,26 +0,0 @@ -/matrix/proc/TurnTo(old_angle, new_angle) - . = new_angle - old_angle - Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT - - -/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3) - if(!segments) - return - var/segment = 360/segments - if(!clockwise) - segment = -segment - var/list/matrices = list() - for(var/i in 1 to segments-1) - var/matrix/M = matrix(transform) - M.Turn(segment*i) - matrices += M - var/matrix/last = matrix(transform) - matrices += last - - speed /= segments - - animate(src, transform = matrices[1], time = speed, loops) - for(var/i in 2 to segments) //2 because 1 is covered above - animate(transform = matrices[i], time = speed) - //doesn't have an object argument because this is "Stacking" with the animate call above - //3 billion% intentional diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm index ac5f7120fd6..1799800c338 100644 --- a/code/__defines/_compile_options.dm +++ b/code/__defines/_compile_options.dm @@ -1,2 +1,2 @@ #define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary. - // 1 will enable set background. 0 will disable set background. \ No newline at end of file + // 1 will enable set background. 0 will disable set background. diff --git a/code/__defines/dview.dm b/code/__defines/dview.dm new file mode 100644 index 00000000000..55764fb9a37 --- /dev/null +++ b/code/__defines/dview.dm @@ -0,0 +1,14 @@ +//DVIEW defines + +#define FOR_DVIEW(type, range, center, invis_flags) \ + dview_mob.loc = center; \ + dview_mob.see_invisible = invis_flags; \ + for(type in view(range, dview_mob)) + +#define END_FOR_DVIEW dview_mob.loc = null + +#define DVIEW(output, range, center, invis_flags) \ + dview_mob.loc = center; \ + dview_mob.see_invisible = invis_flags; \ + output = view(range, dview_mob); \ + dview_mob.loc = null; diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm index 73ca556c4c7..f7a7e278c0e 100644 --- a/code/__defines/lighting.dm +++ b/code/__defines/lighting.dm @@ -1,34 +1,83 @@ -//DVIEW defines -//DVIEW is a hack that uses a mob with darksight in order to find lists of viewable stuff while ignoring darkness +#define LIGHTING_INTERVAL 1 // Frequency, in 1/10ths of a second, of the lighting process. -var/mob/dview/dview_mob = new +#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone +#define LIGHTING_ROUND_VALUE 1 / 128 //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY. -/mob/dview - invisibility = 101 - density = 0 +#define LIGHTING_ICON 'icons/effects/lighting_overlay.png' // icon used for lighting shading effects +#define DARKNESS_ICON 'icons/effects/darkness.png' - anchored = 1 - simulated = 0 +#define LIGHTING_SOFT_THRESHOLD 0.001 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays. - see_in_dark = 1e6 +// If I were you I'd leave this alone. +#define LIGHTING_BASE_MATRIX \ + list \ + ( \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, LIGHTING_SOFT_THRESHOLD, 0, \ + 0, 0, 0, 1 \ + ) \ -#define FOR_DVIEW(type, range, center, invis_flags) \ - dview_mob.loc = center; \ - dview_mob.see_invisible = invis_flags; \ - for(type in view(range, dview_mob)) +// Helpers so we can (more easily) control the colour matrices. +#define CL_MATRIX_RR 1 +#define CL_MATRIX_RG 2 +#define CL_MATRIX_RB 3 +#define CL_MATRIX_RA 4 +#define CL_MATRIX_GR 5 +#define CL_MATRIX_GG 6 +#define CL_MATRIX_GB 7 +#define CL_MATRIX_GA 8 +#define CL_MATRIX_BR 9 +#define CL_MATRIX_BG 10 +#define CL_MATRIX_BB 11 +#define CL_MATRIX_BA 12 +#define CL_MATRIX_AR 13 +#define CL_MATRIX_AG 14 +#define CL_MATRIX_AB 15 +#define CL_MATRIX_AA 16 +#define CL_MATRIX_CR 17 +#define CL_MATRIX_CG 18 +#define CL_MATRIX_CB 19 +#define CL_MATRIX_CA 20 -#define END_FOR_DVIEW dview_mob.loc = null - -#define DVIEW(output, range, center, invis_flags) \ - dview_mob.loc = center; \ - dview_mob.see_invisible = invis_flags; \ - output = view(range, dview_mob); \ - dview_mob.loc = null ; +//Some defines to generalise colours used in lighting. +//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated +#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130) +#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100) +#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250) +#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225) +#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225) +#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125) +#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50) +#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50) +//These ones aren't a direct colour like the ones above, because nothing would fit +#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25) +#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75) +#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75) +#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175) +#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250) +//Defines for lighting status, see power/lighting.dm +#define LIGHT_OK 0 +#define LIGHT_EMPTY 1 +#define LIGHT_BROKEN 2 +#define LIGHT_BURNED 3 // Night lighting controller times // The time (in ticks based on worldtime2ticks()) that various actions trigger #define MORNING_LIGHT_RESET 252000 // 7am or 07:00 - lighting restores to normal in morning #define NIGHT_LIGHT_ACTIVE 648000 // 6pm or 18:00 - night lighting mode activates + +// Update type flags. +#define UPDATE_SCHEDULE 0 // Default behavior. Schedule an update with lighting process. +#define UPDATE_NOW 1 // Update right now, fuck the scheduler. May cause lag. +#define UPDATE_NONE 2 // Don't trigger an update at all. Useful if you're triggering the update manually. + +// Some brightness/range defines for objects. +#define L_WALLMOUNT_POWER 0.4 +#define L_WALLMOUNT_RANGE 2 +#define L_WALLMOUNT_HI_POWER 2 // For red/delta alert on fire alarms. +#define L_WALLMOUNT_HI_RANGE 4 diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 006beadd16c..b4f7b502bb5 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -48,6 +48,9 @@ #define SHOW_TYPING 0x4000 #define CHAT_NOICONS 0x8000 +#define PARALLAX_SPACE 0x1 +#define PARALLAX_DUST 0x2 + #define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|CHAT_OOC|CHAT_DEAD|CHAT_GHOSTEARS|CHAT_GHOSTSIGHT|CHAT_PRAYER|CHAT_RADIO|CHAT_ATTACKLOGS|CHAT_LOOC) //Sound effects toggles @@ -260,4 +263,9 @@ #define LAYER_TABLE 2.8 #define LAYER_UNDER_TABLE 2.79 -#define LAYER_ABOVE_TABLE 2.81 \ No newline at end of file +#define LAYER_ABOVE_TABLE 2.81 + +// Stoplag. +#define TICK_LIMIT 80 +#define TICK_CHECK ( world.tick_usage > TICK_LIMIT ? stoplag() : 0 ) +#define CHECK_TICK if (world.tick_usage > TICK_LIMIT) stoplag() diff --git a/code/__defines/process_scheduler.dm b/code/__defines/process_scheduler.dm index 34b6be033b8..3db5980b7c1 100644 --- a/code/__defines/process_scheduler.dm +++ b/code/__defines/process_scheduler.dm @@ -16,3 +16,17 @@ // SCHECK macros // This references src directly to work around a weird bug with try/catch #define SCHECK sleepCheck() + +#define F_SCHECK \ + calls_since_last_scheck = 0; \ + if (killed) CRASH("A killed process is still running somehow..."); \ + if (hung) { \ + handleHung(); \ + CRASH("Process [name] hung and was restarted."); \ + } \ + if (world.tick_usage > 100 || (world.tick_usage - tick_start) > tick_allowance) { \ + sleep(world.tick_lag); \ + cpu_defer_count++; \ + last_slept = TimeOfHour; \ + tick_start = world.tick_usage; \ + } diff --git a/code/_helpers/datum_pool.dm b/code/_helpers/datum_pool.dm index 2706fcef83d..1462744b904 100644 --- a/code/_helpers/datum_pool.dm +++ b/code/_helpers/datum_pool.dm @@ -1,125 +1,152 @@ +//This was made pretty explicity for atmospherics devices which could not delete their datums properly +//Make sure you go around and null out those references to the datum +//It was also pretty explicitly and shamelessly stolen from regular object pooling, thanks esword + +//#define DEBUG_DATUM_POOL + +#define MAINTAINING_OBJECT_POOL_COUNT 500 + +// Read-only or compile-time vars and special exceptions. +/var/list/exclude = list("inhand_states", "loc", "locs", "parent_type", "vars", "verbs", "type", "x", "y", "z","group", "animate_movement") + +/var/global/list/masterdatumPool = new +/var/global/list/pooledvariables = new /* -/tg/station13 /atom/movable Pool: ---------------------------------- -By RemieRichards + * @args : datum type, normal arguments + * Example call: getFromPool(/datum/pipeline, args) + */ +/proc/getFromPool(var/type, ...) + var/list/B = (args - type) -Creation/Deletion is laggy, so let's reduce reuse and recycle! + if(length(masterdatumPool[type]) <= 0) -*/ -#define ATOM_POOL_COUNT 100 -// "define DEBUG_ATOM_POOL 1 -var/global/list/GlobalPool = list() - -//You'll be using this proc 90% of the time. -//It grabs a type from the pool if it can -//And if it can't, it creates one -//The pool is flexible and will expand to fit -//The new created atom when it eventually -//Goes into the pool - -//Second argument can be a new location, if the type is /atom/movable -//Or a list of arguments -//Either way it gets passed to new - -/proc/PoolOrNew(var/get_type,var/second_arg) - var/datum/D - D = GetFromPool(get_type,second_arg) - - if(!D) - // So the GC knows we're pooling this type. - if(!GlobalPool[get_type]) - GlobalPool[get_type] = list() - if(islist(second_arg)) - return new get_type (arglist(second_arg)) - else - return new get_type (second_arg) - return D - -/proc/GetFromPool(var/get_type,var/second_arg) - if(isnull(GlobalPool[get_type])) - return 0 - - if(length(GlobalPool[get_type]) == 0) - return 0 - - var/datum/D = pick_n_take(GlobalPool[get_type]) - if(D) - D.ResetVars() - D.Prepare(second_arg) - return D - return 0 - -/proc/PlaceInPool(var/datum/D) - if(!istype(D)) - return - - if(length(GlobalPool[D.type]) > ATOM_POOL_COUNT) - #ifdef DEBUG_ATOM_POOL - world << text("DEBUG_DATUM_POOL: PlaceInPool([]) exceeds []. Discarding.", D.type, ATOM_POOL_COUNT) + #ifdef DEBUG_DATUM_POOL + if(ticker) + to_chat(world, text("DEBUG_DATUM_POOL: new proc has been called ([] | []).", type, list2params(B))) #endif - if(garbage_collector) - garbage_collector.AddTrash(D) + + //so the GC knows we're pooling this type. + if(isnull(masterdatumPool[type])) + masterdatumPool[type] = list() + + if(B && B.len) + return new type(arglist(B)) else - del(D) + return new type() + + var/datum/O = masterdatumPool[type][1] + masterdatumPool[type] -= O + + #ifdef DEBUG_DATUM_POOL + to_chat(world, text("DEBUG_DATUM_POOL: getFromPool([]) [] left arglist([]).", type, length(masterdatumPool[type]), list2params(B))) + #endif + + if(!O || !istype(O)) + O = new type(arglist(B)) + else + if(istype(O, /atom/movable) && B.len) // B.len check so we don't OoB. + var/atom/movable/AM = O + AM.forceMove(B[1], FALSE, TRUE) + + if(B && B.len) + O.New(arglist(B)) + else + O.New() + + return O + +/* + * @args + * D, datum instance + * + * Example call: returnToPool(src) + */ + +/proc/returnToPool(const/datum/D) + ASSERT(D) + + if(istype(D, /atom/movable) && length(masterdatumPool[D.type]) > MAINTAINING_OBJECT_POOL_COUNT) + #ifdef DEBUG_DATUM_POOL + to_chat(world, text("DEBUG_DATUM_POOL: returnToPool([]) exceeds [] discarding...", D.type, MAINTAINING_OBJECT_POOL_COUNT)) + #endif + + qdel(D) return - if(D in GlobalPool[D.type]) - return - - if(!GlobalPool[D.type]) - GlobalPool[D.type] = list() - - GlobalPool[D.type] += D + if(isnull(masterdatumPool[D.type])) + masterdatumPool[D.type] = list() D.Destroy() - D.ResetVars() + D.resetVariables() -/proc/IsPooled(var/datum/D) - if(isnull(GlobalPool[D.type])) - return 0 - return 1 + #ifdef DEBUG_DATUM_POOL + if(D in masterdatumPool[D.type]) + to_chat(world, text("returnToPool has been called twice for the same datum of type [] time to panic.", D.type)) + #endif -/datum/proc/Prepare(args) - if(islist(args)) - New(arglist(args)) - else - New(args) + masterdatumPool[D.type] |= D -/atom/movable/Prepare(args) - var/list/args_list = args - if(istype(args_list) && args_list.len) - loc = args[1] - else - loc = args - ..() + #ifdef DEBUG_DATUM_POOL + to_chat(world, text("DEBUG_DATUM_POOL: returnToPool([]) [] left.", D.type, length(masterdatumPool[D.type]))) + #endif -var/list/excluded_vars = list("animate_movement", "contents", "loc", "locs", "parent_type", "vars", "verbs", "type") -var/list/pooledvariables = list() -//thanks to clusterfack @ /vg/station for these two procs -/datum/proc/createVariables(var/list/excluded) +#undef MAINTAINING_DATUM_POOL_COUNT + +#ifdef DEBUG_DATUM_POOL +#undef DEBUG_DATUM_POOL +#endif + +/datum/proc/createVariables() pooledvariables[type] = new/list() - var/list/all_excluded = excluded_vars + excluded + var/list/exclude = global.exclude + args for(var/key in vars) - if(key in all_excluded) + if(key in exclude) continue pooledvariables[type][key] = initial(vars[key]) -/datum/proc/ResetVars(var/list/excluded = list()) +//RETURNS NULL WHEN INITIALIZED AS A LIST() AND POSSIBLY OTHER DISCRIMINATORS +//IF YOU ARE USING SPECIAL VARIABLES SUCH A LIST() INITIALIZE THEM USING RESET VARIABLES +//SEE http://www.byond.com/forum/?post=76850 AS A REFERENCE ON THIS + +/datum/proc/resetVariables() if(!pooledvariables[type]) - createVariables(excluded) + createVariables(args) for(var/key in pooledvariables[type]) vars[key] = pooledvariables[type][key] -/atom/movable/ResetVars() - ..() - loc = null - contents = initial(contents) //something is really wrong if this object still has stuff in it by this point +/proc/isInTypes(atom/Object, types) + if(!Object) + return 0 + var/prototype = Object.type + Object = null -/image/ResetVars() - ..() - loc = null + for (var/type in params2list(types)) + if (ispath(prototype, text2path(type))) + return 1 -#undef ATOM_POOL_COUNT + return 0 + +/client/proc/debug_pooling() + set name = "Debug Pooling Type" + set category = "Debug" + + var/type = input("What is the typepath for the pooled object variables you wish to view?", "Pooled Variables") in pooledvariables|null + + if(!type) + return + + var/list/L = list() + L += "Stored Variables for Pooling for this type
" + for(var/key in pooledvariables[type]) + if(pooledvariables[type][key]) + L += "
[key] = [pooledvariables[type][key]]" + else + L += "
[key] = null" + usr << browse(jointext(L,""),"window=poolingvariablelogs") + +// Shim - this method doesn't natively exist in this implementation. +/proc/IsPooled(var/datum/D) + return "[D.type]" in masterdatumPool \ No newline at end of file diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 6a722bf7e30..5d26075034c 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -794,6 +794,8 @@ proc/GaussRandRound(var/sigma,var/roundto) var/old_icon1 = T.icon var/old_overlays = T.overlays.Copy() var/old_underlays = T.underlays.Copy() + if (T.dynamic_lighting && T.lighting_overlay) + T.lighting_overlay.forceMove(B, harderforce = TRUE) var/turf/X = B.ChangeTurf(T.type) X.set_dir(old_dir1) @@ -1364,15 +1366,6 @@ var/list/WALLITEMS = list( /atom/movable/proc/stop_orbit() orbiting = null -/mob/dview/New() - ..() - // We don't want to be in any mob lists; we're a dummy not a mob. - mob_list -= src - if(stat == DEAD) - dead_mob_list -= src - else - living_mob_list -= src - // call to generate a stack trace and print to runtime logs /proc/crash_with(msg) CRASH(msg) @@ -1396,3 +1389,18 @@ var/list/WALLITEMS = list( a = a.loc return 0//If we get here, we must be buried many layers deep in nested containers. Shouldn't happen + +//Increases delay as the server gets more overloaded, +//as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful +#define DELTA_CALC max((max(world.tick_usage,world.cpu)/100),1) + +/proc/stoplag() + . = 0 + var/i = 1 + do + . += round(i*DELTA_CALC) + sleep(i*world.tick_lag*DELTA_CALC) + i *= 2 + while (world.tick_usage > TICK_LIMIT) + +#undef DELTA_CALC diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 36fcab5cd2c..af6b86e3a66 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -255,6 +255,8 @@ datum/hud/New(mob/owner) mymob.instantiate_hud(src, ui_style, ui_color, ui_alpha) + update_parallax_existence() + /mob/proc/instantiate_hud(var/datum/hud/HUD, var/ui_style, var/ui_color, var/ui_alpha) return diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm new file mode 100644 index 00000000000..ced3f8681ff --- /dev/null +++ b/code/_onclick/hud/parallax.dm @@ -0,0 +1,267 @@ +// Until we convert to planes. +#define PLANE_SPACE_BACKGROUND -98 +#define PLANE_SPACE_PARALLAX (PLANE_SPACE_BACKGROUND + 1) // -97 +#define PLANE_SPACE_DUST (PLANE_SPACE_PARALLAX + 1) // -96 +#define PLANE_ABOVE_PARALLAX (PLANE_SPACE_BACKGROUND + 3) // -95 + +/* + * This file handles all parallax-related business once the parallax itself is initialized with the rest of the HUD + */ +#define PARALLAX_IMAGE_WIDTH 8 +#define PARALLAX_IMAGE_TILES (PARALLAX_IMAGE_WIDTH**2) +#define GRID_WIDTH 3 + +var/list/parallax_on_clients = list() +var/parallax_initialized = 0 +var/space_color = "#050505" +var/list/parallax_icon[(GRID_WIDTH**2)*3] + +/obj/screen/parallax + var/base_offset_x = 0 + var/base_offset_y = 0 + mouse_opacity = 0 + icon = 'icons/turf/space.dmi' + icon_state = "blank" + name = "space parallax" + screen_loc = "CENTER,CENTER" + blend_mode = BLEND_ADD + layer = AREA_LAYER + plane = PLANE_SPACE_PARALLAX + globalscreen = 1 + var/parallax_speed = 0 + +/obj/screen/plane_master + appearance_flags = PLANE_MASTER + screen_loc = "CENTER,CENTER" + globalscreen = 1 + +/obj/screen/plane_master/parallax_master + plane = PLANE_SPACE_PARALLAX + blend_mode = BLEND_MULTIPLY + color = list( + 1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,0, + 0,0,0,1) + +/obj/screen/plane_master/parallax_spacemaster //Turns space white, causing the parallax to only show in areas with opacity. Somehow + plane = PLANE_SPACE_BACKGROUND + color = list( + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 1,1,1,1) + +/obj/screen/plane_master/parallax_spacemaster/New() + ..() + overlays += image(icon = 'icons/mob/screen1.dmi', icon_state = "blank") + if(universe) + universe.convert_parallax(src) + +/obj/screen/plane_master/parallax_dustmaster + plane = PLANE_SPACE_DUST + color = list(0,0,0,0) + +/datum/hud/proc/update_parallax_existence() + if(!parallax_initialized) + return + initialize_parallax() + update_parallax() + update_parallax_values() + +/datum/hud/proc/initialize_parallax() + var/client/C = mymob.client + + if(!C.parallax_master) + C.parallax_master = getFromPool(/obj/screen/plane_master/parallax_master) + if(!C.parallax_spacemaster) + C.parallax_spacemaster = getFromPool(/obj/screen/plane_master/parallax_spacemaster) + if(!C.parallax_dustmaster) + C.parallax_dustmaster = getFromPool(/obj/screen/plane_master/parallax_dustmaster) + + if(!C.parallax.len) + for(var/obj/screen/parallax/bgobj in parallax_icon) + var/obj/screen/parallax/parallax_layer = getFromPool(/obj/screen/parallax) + parallax_layer.appearance = bgobj.appearance + parallax_layer.base_offset_x = bgobj.base_offset_x + parallax_layer.base_offset_y = bgobj.base_offset_y + parallax_layer.parallax_speed = bgobj.parallax_speed + parallax_layer.screen_loc = bgobj.screen_loc + C.parallax += parallax_layer + if(bgobj.parallax_speed) + C.parallax_movable += parallax_layer + + if(!C.parallax_offset.len) + C.parallax_offset["horizontal"] = 0 + C.parallax_offset["vertical"] = 0 + + C.screen |= C.parallax_dustmaster + +/datum/hud/proc/update_parallax() + var/client/C = mymob.client + if(C.prefs.parallax_togs & PARALLAX_SPACE) + parallax_on_clients |= C + for(var/obj/screen/parallax/bgobj in C.parallax) + C.screen |= bgobj + C.screen |= C.parallax_master + C.screen |= C.parallax_spacemaster + if(C.prefs.parallax_togs & PARALLAX_DUST) + C.parallax_dustmaster.color = list( + 1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1) + else + C.parallax_dustmaster.color = list(0,0,0,0) + else + for(var/obj/screen/parallax/bgobj in C.parallax) + C.screen -= bgobj + parallax_on_clients -= C + C.screen -= C.parallax_master + C.screen -= C.parallax_spacemaster + C.parallax_dustmaster.color = list(0,0,0,0) + +/datum/hud/proc/update_parallax_values() + var/client/C = mymob.client + if(!parallax_initialized) + return + + if(!(locate(/turf/space) in trange(C.view,get_turf(C.eye)))) + return + + //ACTUALLY MOVING THE PARALLAX + var/turf/posobj = get_turf(C.eye) + + if(!C.previous_turf || (C.previous_turf.z != posobj.z)) + C.previous_turf = posobj + + //Doing it this way prevents parallax layers from "jumping" when you change Z-Levels. + var/offsetx = C.parallax_offset["horizontal"] + posobj.x - C.previous_turf.x + var/offsety = C.parallax_offset["vertical"] + posobj.y - C.previous_turf.y + C.parallax_offset["horizontal"] = offsetx + C.parallax_offset["vertical"] = offsety + + C.previous_turf = posobj + + for(var/obj/screen/parallax/bgobj in C.parallax_movable) + var/accumulated_offset_x = bgobj.base_offset_x - round(offsetx * bgobj.parallax_speed * C.prefs.parallax_speed) + var/accumulated_offset_y = bgobj.base_offset_y - round(offsety * bgobj.parallax_speed * C.prefs.parallax_speed) + + if(accumulated_offset_x > PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE) + accumulated_offset_x -= PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE*GRID_WIDTH //3x3 grid, 15 tiles * 64 icon_size * 3 grid size + if(accumulated_offset_x < -(PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE*2)) + accumulated_offset_x += PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE*GRID_WIDTH + + if(accumulated_offset_y > PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE) + accumulated_offset_y -= PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE*GRID_WIDTH + if(accumulated_offset_y < -(PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE*2)) + accumulated_offset_y += PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE*GRID_WIDTH + + bgobj.screen_loc = "CENTER:[accumulated_offset_x],CENTER:[accumulated_offset_y]" + +//Parallax generation code below + +#define PARALLAX4_ICON_NUMBER 20 +#define PARALLAX3_ICON_NUMBER 14 +#define PARALLAX2_ICON_NUMBER 10 + +/proc/create_global_parallax_icons() + var/list/plane1 = list() + var/list/plane2 = list() + var/list/plane3 = list() + var/list/pixel_x = list() + var/list/pixel_y = list() + var/index = 1 + for(var/i = 0 to (PARALLAX_IMAGE_TILES-1)) + for(var/j = 1 to GRID_WIDTH**2) + plane1 += rand(1,26) + plane2 += rand(1,26) + plane3 += rand(1,26) + pixel_x += WORLD_ICON_SIZE * (i%PARALLAX_IMAGE_WIDTH) + pixel_y += WORLD_ICON_SIZE * round(i/PARALLAX_IMAGE_WIDTH) + + for(var/i in 0 to ((GRID_WIDTH**2)-1)) + var/obj/screen/parallax/parallax_layer = getFromPool(/obj/screen/parallax) + + var/list/L = list() + for(var/j in 1 to PARALLAX_IMAGE_TILES) + if(plane1[j+i*PARALLAX_IMAGE_TILES] <= PARALLAX4_ICON_NUMBER) + var/image/I = image('icons/turf/space_parallax4.dmi',"[plane1[j+i*PARALLAX_IMAGE_TILES]]") + I.pixel_x = pixel_x[j] + I.pixel_y = pixel_y[j] + L += I + + parallax_layer.overlays = L + parallax_layer.parallax_speed = 0 + parallax_layer.calibrate_parallax(i+1) + parallax_icon[index] = parallax_layer + index++ + + for(var/i in 0 to ((GRID_WIDTH**2)-1)) + var/obj/screen/parallax/parallax_layer = getFromPool(/obj/screen/parallax) + + var/list/L = list() + for(var/j in 1 to PARALLAX_IMAGE_TILES) + if(plane2[j+i*PARALLAX_IMAGE_TILES] <= PARALLAX3_ICON_NUMBER) + var/image/I = image('icons/turf/space_parallax3.dmi',"[plane2[j+i*PARALLAX_IMAGE_TILES]]") + I.pixel_x = pixel_x[j] + I.pixel_y = pixel_y[j] + L += I + + parallax_layer.overlays = L + parallax_layer.parallax_speed = 0.5 + parallax_layer.calibrate_parallax(i+1) + parallax_icon[index] = parallax_layer + index++ + + for(var/i in 0 to ((GRID_WIDTH**2)-1)) + var/obj/screen/parallax/parallax_layer = getFromPool(/obj/screen/parallax) + var/list/L = list() + for(var/j in 1 to PARALLAX_IMAGE_TILES) + if(plane3[j+i*PARALLAX_IMAGE_TILES] <= PARALLAX2_ICON_NUMBER) + var/image/I = image('icons/turf/space_parallax2.dmi',"[plane3[j+i*PARALLAX_IMAGE_TILES]]") + I.pixel_x = pixel_x[j] + I.pixel_y = pixel_y[j] + L += I + + parallax_layer.overlays = L + parallax_layer.parallax_speed = 1 + parallax_layer.calibrate_parallax(i+1) + parallax_icon[index] = parallax_layer + index++ + + parallax_initialized = 1 + +/obj/screen/parallax/proc/calibrate_parallax(var/i) + if(!i) + return + + /* Placement of screen objects + 1 2 3 + 4 5 6 + 7 8 9 + */ + + base_offset_x = -PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE/2 + base_offset_y = -PARALLAX_IMAGE_WIDTH*WORLD_ICON_SIZE/2 + +//TODO: switch to grid size defines... somehow + switch(i) + if(1,4,7) //1 mod grid_size + base_offset_x -= WORLD_ICON_SIZE*PARALLAX_IMAGE_WIDTH + if(3,6,9) //0 mod grid_size + base_offset_x += WORLD_ICON_SIZE*PARALLAX_IMAGE_WIDTH + switch(i) + if(1,2,3) //round(i/grid_size) = 0 + base_offset_y += WORLD_ICON_SIZE*PARALLAX_IMAGE_WIDTH + if(7,8,9) //round(i/grid_size) = 2 + base_offset_y -= WORLD_ICON_SIZE*PARALLAX_IMAGE_WIDTH + + screen_loc = "CENTER:[base_offset_x],CENTER:[base_offset_y]" + +#undef PARALLAX4_ICON_NUMBER +#undef PARALLAX3_ICON_NUMBER +#undef PARALLAX2_ICON_NUMBER +#undef PARALLAX_IMAGE_WIDTH +#undef PARALLAX_IMAGE_TILES diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index a0e60d0deb7..a9fc180e2a1 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -12,6 +12,7 @@ layer = 20.0 unacidable = 1 var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. + var/globalscreen = 0 // TODO: Screen pooling. /obj/screen/Destroy() master = null diff --git a/code/_onclick/hud/spell_screen_objects.dm b/code/_onclick/hud/spell_screen_objects.dm index 213a4ed16aa..98118b93d1d 100644 --- a/code/_onclick/hud/spell_screen_objects.dm +++ b/code/_onclick/hud/spell_screen_objects.dm @@ -23,7 +23,7 @@ spell_holder.client.screen -= src spell_holder = null -/obj/screen/movable/spell_master/ResetVars(var/list/exclude = list()) +/obj/screen/movable/spell_master/resetVariables(var/list/exclude = list()) exclude += "spell_objects" ..(exclude) @@ -93,7 +93,7 @@ if(spell.spell_flags & NO_BUTTON) //no button to add if we don't get one return - var/obj/screen/spell/newscreen = PoolOrNew(/obj/screen/spell) + var/obj/screen/spell/newscreen = getFromPool(/obj/screen/spell) newscreen.spellmaster = src newscreen.spell = spell diff --git a/code/_onclick/oldcode.dm b/code/_onclick/oldcode.dm deleted file mode 100644 index e3f417d59ac..00000000000 --- a/code/_onclick/oldcode.dm +++ /dev/null @@ -1,376 +0,0 @@ -/atom/DblClick(location, control, params) //TODO: DEFERRED: REWRITE - if(!usr) return - - // ------- TIME SINCE LAST CLICK ------- - if (world.time <= usr:lastDblClick+1) - return - else - usr:lastDblClick = world.time - - //Putting it here for now. It diverts stuff to the mech clicking procs. Putting it here stops us drilling items in our inventory Carn - if(istype(usr.loc,/obj/mecha)) - if(usr.client && (src in usr.client.screen)) - return - var/obj/mecha/Mech = usr.loc - Mech.click_action(src,usr) - return - - // ------- DIR CHANGING WHEN CLICKING ------ - if( iscarbon(usr) && !usr.buckled ) - if( src.x && src.y && usr.x && usr.y ) - var/dx = src.x - usr.x - var/dy = src.y - usr.y - - if(dy || dx) - if(abs(dx) < abs(dy)) - if(dy > 0) usr.set_dir(NORTH) - else usr.set_dir(SOUTH) - else - if(dx > 0) usr.set_dir(EAST) - else usr.set_dir(WEST) - else - if(pixel_y > 16) usr.set_dir(NORTH) - else if(pixel_y < -16) usr.set_dir(SOUTH) - else if(pixel_x > 16) usr.set_dir(EAST) - else if(pixel_x < -16) usr.set_dir(WEST) - - - - - // ------- AI ------- - else if (istype(usr, /mob/living/silicon/ai)) - var/mob/living/silicon/ai/ai = usr - if (ai.control_disabled) - return - - // ------- CYBORG ------- - else if (istype(usr, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/bot = usr - if (bot.lockcharge) return - ..() - - - // ------- SHIFT-CLICK ------- - - if(params) - var/parameters = params2list(params) - - if(parameters["shift"]){ - if(!isAI(usr)) - ShiftClick(usr) - else - AIShiftClick(usr) - return - } - - // ------- ALT-CLICK ------- - - if(parameters["alt"]){ - if(!isAI(usr)) - AltClick(usr) - else - AIAltClick(usr) - return - } - - // ------- CTRL-CLICK ------- - - if(parameters["ctrl"]){ - if(!isAI(usr)) - CtrlClick(usr) - else - AICtrlClick(usr) - return - } - - // ------- MIDDLE-CLICK ------- - - if(parameters["middle"]){ - if(!isAI(usr)) - MiddleClick(usr) - return - } - - // ------- THROW ------- - if(usr.in_throw_mode) - return usr:throw_item(src) - - // ------- ITEM IN HAND DEFINED ------- - var/obj/item/W = usr.get_active_hand() -/* Now handled by get_active_hand() - // ------- ROBOT ------- - if(istype(usr, /mob/living/silicon/robot)) - if(!isnull(usr:module_active)) - W = usr:module_active - else - W = null -*/ - // ------- ATTACK SELF ------- - if (W == src && usr.stat == 0) - W.attack_self(usr) - if(usr.hand) - usr.update_inv_l_hand(0) //update in-hand overlays - else - usr.update_inv_r_hand(0) - return - - // ------- PARALYSIS, STUN, WEAKENED, DEAD, (And not AI) ------- - if (((usr.paralysis || usr.stunned || usr.weakened) && !istype(usr, /mob/living/silicon/ai)) || usr.stat != 0) - return - - // ------- CLICKING STUFF IN CONTAINERS ------- - if ((!( src in usr.contents ) && (((!( isturf(src) ) && (!( isturf(src.loc) ) && (src.loc && !( isturf(src.loc.loc) )))) || !( isturf(usr.loc) )) && (src.loc != usr.loc && (!( istype(src, /obj/screen) ) && !( usr.contents.Find(src.loc) )))))) - if (istype(usr, /mob/living/silicon/ai)) - var/mob/living/silicon/ai/ai = usr - if (ai.control_disabled) - return - else - return - - // ------- 1 TILE AWAY ------- - var/t5 - // ------- AI CAN CLICK ANYTHING ------- - if(istype(usr, /mob/living/silicon/ai)) - t5 = 1 - // ------- CYBORG CAN CLICK ANYTHING WHEN NOT HOLDING STUFF ------- - else if(istype(usr, /mob/living/silicon/robot) && !W) - t5 = 1 - else - t5 = in_range(src, usr) || src.loc == usr - -// world << "according to dblclick(), t5 is [t5]" - - // ------- ACTUALLY DETERMINING STUFF ------- - if (((t5 || (W && (W.flags & USEDELAY))) && !( istype(src, /obj/screen) ))) - - // ------- ( CAN USE ITEM OR HAS 1 SECOND USE DELAY ) AND NOT CLICKING ON SCREEN ------- - - if (usr.next_move < world.time) - usr.prev_move = usr.next_move - usr.next_move = world.time + 10 - else - // ------- ALREADY USED ONE ITEM WITH USE DELAY IN THE PREVIOUS SECOND ------- - return - - // ------- DELAY CHECK PASSED ------- - - if ((src.loc && (get_dist(src, usr) < 2 || src.loc == usr.loc))) - - // ------- CLICKED OBJECT EXISTS IN GAME WORLD, DISTANCE FROM PERSON TO OBJECT IS 1 SQUARE OR THEY'RE ON THE SAME SQUARE ------- - - var/direct = get_dir(usr, src) - var/obj/item/weapon/dummy/D = new /obj/item/weapon/dummy( usr.loc ) - var/ok = 0 - if ( (direct - 1) & direct) - - // ------- CLICKED OBJECT IS LOCATED IN A DIAGONAL POSITION FROM THE PERSON ------- - - var/turf/Step_1 - var/turf/Step_2 - switch(direct) - if(5.0) - Step_1 = get_step(usr, NORTH) - Step_2 = get_step(usr, EAST) - - if(6.0) - Step_1 = get_step(usr, SOUTH) - Step_2 = get_step(usr, EAST) - - if(9.0) - Step_1 = get_step(usr, NORTH) - Step_2 = get_step(usr, WEST) - - if(10.0) - Step_1 = get_step(usr, SOUTH) - Step_2 = get_step(usr, WEST) - - else - if(Step_1 && Step_2) - - // ------- BOTH CARDINAL DIRECTIONS OF THE DIAGONAL EXIST IN THE GAME WORLD ------- - - var/check_1 = 0 - var/check_2 = 0 - if(step_to(D, Step_1)) - check_1 = 1 - for(var/obj/border_obstacle in Step_1) - if(border_obstacle.flags & ON_BORDER) - if(!border_obstacle.CheckExit(D, src)) - check_1 = 0 - // ------- YOU TRIED TO CLICK ON AN ITEM THROUGH A WINDOW (OR SIMILAR THING THAT LIMITS ON BORDERS) ON ONE OF THE DIRECITON TILES ------- - for(var/obj/border_obstacle in get_turf(src)) - if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle)) - if(!border_obstacle.CanPass(D, D.loc, 1, 0)) - // ------- YOU TRIED TO CLICK ON AN ITEM THROUGH A WINDOW (OR SIMILAR THING THAT LIMITS ON BORDERS) ON THE TILE YOU'RE ON ------- - check_1 = 0 - - D.loc = usr.loc - if(step_to(D, Step_2)) - check_2 = 1 - - for(var/obj/border_obstacle in Step_2) - if(border_obstacle.flags & ON_BORDER) - if(!border_obstacle.CheckExit(D, src)) - check_2 = 0 - for(var/obj/border_obstacle in get_turf(src)) - if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle)) - if(!border_obstacle.CanPass(D, D.loc, 1, 0)) - check_2 = 0 - - - if(check_1 || check_2) - ok = 1 - // ------- YOU CAN REACH THE ITEM THROUGH AT LEAST ONE OF THE TWO DIRECTIONS. GOOD. ------- - - /* - More info: - If you're trying to click an item in the north-east of your mob, the above section of code will first check if tehre's a tile to the north or you and to the east of you - These two tiles are Step_1 and Step_2. After this, a new dummy object is created on your location. It then tries to move to Step_1, If it succeeds, objects on the turf you're on and - the turf that Step_1 is are checked for items which have the ON_BORDER flag set. These are itmes which limit you on only one tile border. Windows, for the most part. - CheckExit() and CanPass() are use to determine this. The dummy object is then moved back to your location and it tries to move to Step_2. Same checks are performed here. - If at least one of the two checks succeeds, it means you can reach the item and ok is set to 1. - */ - else - // ------- OBJECT IS ON A CARDINAL TILE (NORTH, SOUTH, EAST OR WEST OR THE TILE YOU'RE ON) ------- - if(loc == usr.loc) - ok = 1 - // ------- OBJECT IS ON THE SAME TILE AS YOU ------- - else - ok = 1 - - //Now, check objects to block exit that are on the border - for(var/obj/border_obstacle in usr.loc) - if(border_obstacle.flags & ON_BORDER) - if(!border_obstacle.CheckExit(D, src)) - ok = 0 - - //Next, check objects to block entry that are on the border - for(var/obj/border_obstacle in get_turf(src)) - if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle)) - if(!border_obstacle.CanPass(D, D.loc, 1, 0)) - ok = 0 - /* - See the previous More info, for... more info... - */ - - //qdel(D) - // Garbage Collect Dummy - D.loc = null - D = null - - // ------- DUMMY OBJECT'S SERVED IT'S PURPOSE, IT'S REWARDED WITH A SWIFT DELETE ------- - if (!( ok )) - // ------- TESTS ABOVE DETERMINED YOU CANNOT REACH THE TILE ------- - return 0 - - if (!( usr.restrained() || (usr.lying && usr.buckled!=src) )) - // ------- YOU ARE NOT REASTRAINED ------- - - if (W) - // ------- YOU HAVE AN ITEM IN YOUR HAND - HANDLE ATTACKBY AND AFTERATTACK ------- - var/ignoreAA = 0 //Ignore afterattack(). Surgery uses this. - if (t5) - ignoreAA = src.attackby(W, usr) - if (W && !ignoreAA) - W.afterattack(src, usr, (t5 ? 1 : 0), params) - - else - // ------- YOU DO NOT HAVE AN ITEM IN YOUR HAND ------- - if (istype(usr, /mob/living/carbon/human)) - // ------- YOU ARE HUMAN ------- - src.attack_hand(usr, usr.hand) - else - // ------- YOU ARE NOT HUMAN. WHAT ARE YOU - DETERMINED HERE AND PROPER ATTACK_MOBTYPE CALLED ------- - if (istype(usr, /mob/living/carbon/monkey)) - src.attack_paw(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/alien/humanoid)) - if(usr.m_intent == "walk" && istype(usr, /mob/living/carbon/alien/humanoid/hunter)) - usr.m_intent = "run" - usr.hud_used.move_intent.icon_state = "running" - usr.update_icons() - src.attack_alien(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/alien/larva)) - src.attack_larva(usr) - else if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) - src.attack_ai(usr, usr.hand) - else if(istype(usr, /mob/living/carbon/slime)) - src.attack_slime(usr) - else if(istype(usr, /mob/living/simple_animal)) - src.attack_animal(usr) - else - // ------- YOU ARE RESTRAINED. DETERMINE WHAT YOU ARE AND ATTACK WITH THE PROPER HAND_X PROC ------- - if (istype(usr, /mob/living/carbon/human)) - src.hand_h(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/monkey)) - src.hand_p(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/alien/humanoid)) - src.hand_al(usr, usr.hand) - else if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot)) - src.hand_a(usr, usr.hand) - - else - // ------- ITEM INACESSIBLE OR CLICKING ON SCREEN ------- - if (istype(src, /obj/screen)) - // ------- IT'S THE HUD YOU'RE CLICKING ON ------- - usr.prev_move = usr.next_move - usr:lastDblClick = world.time + 2 - if (usr.next_move < world.time) - usr.next_move = world.time + 2 - else - return - - // ------- 2 DECISECOND DELAY FOR CLICKING PASSED ------- - - if (!( usr.restrained() )) - - // ------- YOU ARE NOT RESTRAINED ------- - if ((W && !( istype(src, /obj/screen) ))) - // ------- IT SHOULD NEVER GET TO HERE, DUE TO THE ISTYPE(SRC, /OBJ/SCREEN) FROM PREVIOUS IF-S - I TESTED IT WITH A DEBUG OUTPUT AND I COULDN'T GET THIST TO SHOW UP. ------- - src.attackby(W, usr) - if (W) - W.afterattack(src, usr,, params) - else - // ------- YOU ARE NOT RESTRAINED, AND ARE CLICKING A HUD OBJECT ------- - if (istype(usr, /mob/living/carbon/human)) - src.attack_hand(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/monkey)) - src.attack_paw(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/alien/humanoid)) - src.attack_alien(usr, usr.hand) - else - // ------- YOU ARE RESTRAINED CLICKING ON A HUD OBJECT ------- - if (istype(usr, /mob/living/carbon/human)) - src.hand_h(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/monkey)) - src.hand_p(usr, usr.hand) - else if (istype(usr, /mob/living/carbon/alien/humanoid)) - src.hand_al(usr, usr.hand) - else - // ------- YOU ARE CLICKING ON AN OBJECT THAT'S INACCESSIBLE TO YOU AND IS NOT YOUR HUD ------- - if((LASER in usr:mutations) && usr:a_intent == I_HURT && world.time >= usr.next_move) - // ------- YOU HAVE THE LASER MUTATION, YOUR INTENT SET TO HURT AND IT'S BEEN MORE THAN A DECISECOND SINCE YOU LAS TATTACKED ------- - - var/turf/T = get_turf(usr) - var/turf/U = get_turf(src) - - - if(istype(usr, /mob/living/carbon/human)) - usr:nutrition -= rand(1,5) - usr:handle_regular_hud_updates() - - var/obj/item/projectile/beam/A = new /obj/item/projectile/beam( usr.loc ) - A.icon = 'icons/effects/genetics.dmi' - A.icon_state = "eyelasers" - playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1) - - A.firer = usr - A.def_zone = usr:get_organ_target() - A.original = src - A.current = T - A.yo = U.y - T.y - A.xo = U.x - T.x - spawn( 1 ) - A.process() - - usr.next_move = world.time + 6 - return diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index e91643019e8..7344eed309a 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -157,7 +157,7 @@ var/const/tk_maxrange = 15 /obj/item/tk_grab/proc/apply_focus_overlay() if(!focus) return - var/obj/effect/overlay/O = PoolOrNew(/obj/effect/overlay, locate(focus.x,focus.y,focus.z)) + var/obj/effect/overlay/O = getFromPool(/obj/effect/overlay, locate(focus.x,focus.y,focus.z)) O.name = "sparkles" O.anchored = 1 O.density = 0 diff --git a/code/controllers/Processes/alarm.dm b/code/controllers/Processes/alarm.dm index ce2dab54c0e..707c5756418 100644 --- a/code/controllers/Processes/alarm.dm +++ b/code/controllers/Processes/alarm.dm @@ -22,7 +22,7 @@ var/datum/controller/process/alarm/alarm_manager for(last_object in all_handlers) var/datum/alarm_handler/AH = last_object AH.process() - SCHECK + F_SCHECK /datum/controller/process/alarm/proc/active_alarms() var/list/all_alarms = new diff --git a/code/controllers/Processes/chemistry.dm b/code/controllers/Processes/chemistry.dm index 084de83e28c..508bdba37fd 100644 --- a/code/controllers/Processes/chemistry.dm +++ b/code/controllers/Processes/chemistry.dm @@ -22,7 +22,7 @@ var/datum/controller/process/chemistry/chemistryProcess var/datum/reagents/holder = last_object if(!holder.process_reactions()) active_holders -= holder - SCHECK + F_SCHECK /datum/controller/process/chemistry/proc/mark_for_update(var/datum/reagents/holder) if(holder in active_holders) diff --git a/code/controllers/Processes/disease.dm b/code/controllers/Processes/disease.dm index 2cf0f5ea44b..2a1c2c9eb60 100644 --- a/code/controllers/Processes/disease.dm +++ b/code/controllers/Processes/disease.dm @@ -9,7 +9,7 @@ for(last_object in active_diseases) var/datum/disease/D = last_object D.process() - SCHECK + F_SCHECK /datum/controller/process/disease/statProcess() ..() diff --git a/code/controllers/Processes/event.dm b/code/controllers/Processes/event.dm index d05aa455d13..404c71f0aee 100644 --- a/code/controllers/Processes/event.dm +++ b/code/controllers/Processes/event.dm @@ -6,10 +6,10 @@ for(last_object in event_manager.active_events) var/datum/event/E = last_object E.process() - SCHECK + F_SCHECK for(var/i = EVENT_LEVEL_MUNDANE to EVENT_LEVEL_MAJOR) last_object = event_manager.event_containers[i] var/list/datum/event_container/EC = last_object EC.process() - SCHECK + F_SCHECK diff --git a/code/controllers/Processes/explosives.dm b/code/controllers/Processes/explosives.dm index 7009084dea3..81e70577bf4 100644 --- a/code/controllers/Processes/explosives.dm +++ b/code/controllers/Processes/explosives.dm @@ -46,7 +46,7 @@ var/datum/controller/process/explosives/bomb_processor else explosion(data) - SCHECK + F_SCHECK work_queue -= data lighting_process.enable() @@ -110,7 +110,7 @@ var/datum/controller/process/explosives/bomb_processor if (vibration) for(var/mob/M in player_list) - SCHECK + F_SCHECK // Double check for client var/reception = 2//Whether the person can be shaken or hear sound //2 = BOTH @@ -176,12 +176,12 @@ var/datum/controller/process/explosives/bomb_processor else continue T.ex_act(dist) - SCHECK + F_SCHECK if(T) for(var/atom_movable in T.contents) //bypass type checking since only atom/movable can be contained by turfs anyway var/atom/movable/AM = atom_movable if(AM && AM.simulated) AM.ex_act(dist) - SCHECK + F_SCHECK var/took = (world.timeofday-start)/10 //You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare @@ -214,7 +214,7 @@ var/datum/controller/process/explosives/bomb_processor for(var/direction in cardinal) var/turf/T = get_step(epicenter, direction) explosion_spread(T, power - epicenter.explosion_resistance, direction) - SCHECK + F_SCHECK //This step applies the ex_act effects for the explosion, as planned in the previous step. for(var/turf/T in explosion_turfs) @@ -233,13 +233,13 @@ var/datum/controller/process/explosives/bomb_processor T = locate(x,y,z) for(var/atom/A in T) A.ex_act(severity) - SCHECK + F_SCHECK explosion_in_progress = 0 // A proc used by recursive explosions. (The actually recursive bit.) /datum/controller/process/explosives/proc/explosion_spread(turf/s, power, direction) - SCHECK + F_SCHECK if (istype(s, /turf/unsimulated)) return if(power <= 0) diff --git a/code/controllers/Processes/garbage.dm b/code/controllers/Processes/garbage.dm index 44de0d0216c..5322e07be5d 100644 --- a/code/controllers/Processes/garbage.dm +++ b/code/controllers/Processes/garbage.dm @@ -80,7 +80,7 @@ world/loop_checks = 0 tick_dels++ total_dels++ destroyed.Cut(1, 2) - SCHECK + F_SCHECK #undef GC_FORCE_DEL_PER_TICK #undef GC_COLLECTION_TIMEOUT @@ -151,13 +151,13 @@ world/loop_checks = 0 /datum/proc/finalize_qdel() if(IsPooled(src)) - PlaceInPool(src) + returnToPool(src) else del(src) /atom/finalize_qdel() - if(IsPooled(src)) - PlaceInPool(src) + if (IsPooled(src)) + returnToPool(src) else if(garbage_collector) garbage_collector.AddTrash(src) diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm index 1480943f390..137bcb6e0b2 100644 --- a/code/controllers/Processes/inactivity.dm +++ b/code/controllers/Processes/inactivity.dm @@ -11,4 +11,4 @@ log_access("AFK: [key_name(C)]") C << "You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected." del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients. - SCHECK + F_SCHECK diff --git a/code/controllers/Processes/law.dm b/code/controllers/Processes/law.dm index a17572e8bee..a4589e1ec21 100644 --- a/code/controllers/Processes/law.dm +++ b/code/controllers/Processes/law.dm @@ -7,6 +7,8 @@ var/list/med_severity = list() var/list/high_severity = list() + disabled = 1 + /datum/controller/process/law/New() corp_regs = src @@ -25,4 +27,4 @@ for( var/L in subtypesof( /datum/law/high_severity )) high_severity += new L - laws = low_severity + med_severity + high_severity \ No newline at end of file + laws = low_severity + med_severity + high_severity diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm new file mode 100644 index 00000000000..5b849a612dd --- /dev/null +++ b/code/controllers/Processes/lighting.dm @@ -0,0 +1,97 @@ +#define STAGE_NONE 0 +#define STAGE_SOURCE 1 +#define STAGE_CORNER 2 +#define STAGE_OVERLAY 3 + +/var/list/lighting_update_lights = list() // List of lighting sources queued for update. +/var/list/lighting_update_corners = list() // List of lighting corners queued for update. +/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. + +// Probably slow. +/var/lighting_profiling = FALSE + +/var/datum/controller/process/lighting/lighting_process + +/datum/controller/process/lighting + schedule_interval = LIGHTING_INTERVAL + var/list/curr_lights = list() + var/list/curr_corners = list() + var/list/curr_overlays = list() + var/list/resume_pos = 0 + +/datum/controller/process/lighting/setup() + name = "lighting" + + lighting_process = src + +/datum/controller/process/lighting/statProcess() + ..() + stat(null, "[all_lighting_overlays.len] overlays ([all_lighting_corners.len] corners)") + stat(null, "Lights: [lighting_update_lights.len] queued, [curr_lights.len] processing") + stat(null, "Corners: [lighting_update_corners.len] queued, [curr_corners.len] processing") + stat(null, "Overlays: [lighting_update_overlays.len] queued, [curr_overlays.len] processing") + +/datum/controller/process/lighting/doWork() + // -- SOURCES -- + if (resume_pos == STAGE_NONE) + curr_lights = lighting_update_lights + lighting_update_lights = list() + + resume_pos = STAGE_SOURCE + + while (curr_lights.len) + var/datum/light_source/L = curr_lights[curr_lights.len] + curr_lights.len-- + + if(L.check() || L.destroyed || L.force_update) + L.remove_lum() + if(!L.destroyed) + L.apply_lum() + + else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. + L.smart_vis_update() + + L.vis_update = FALSE + L.force_update = FALSE + L.needs_update = FALSE + + F_SCHECK + + // -- CORNERS -- + if (resume_pos == STAGE_SOURCE) + curr_corners = lighting_update_corners + lighting_update_corners = list() + + resume_pos = STAGE_CORNER + + while (curr_corners.len) + var/datum/lighting_corner/C = curr_corners[curr_corners.len] + curr_corners.len-- + + C.update_overlays() + + C.needs_update = FALSE + + F_SCHECK + + if (resume_pos == STAGE_CORNER) + curr_overlays = lighting_update_overlays + lighting_update_overlays = list() + + resume_pos = STAGE_OVERLAY + + while (curr_overlays.len) + var/atom/movable/lighting_overlay/O = curr_overlays[curr_overlays.len] + curr_overlays.len-- + + O.update_overlay() + O.needs_update = FALSE + + F_SCHECK + + resume_pos = 0 + +#undef STAGE_NONE +#undef STAGE_SOURCE +#undef STAGE_CORNER +#undef STAGE_OVERLAY diff --git a/code/controllers/Processes/machinery.dm b/code/controllers/Processes/machinery.dm index 75015fc94cc..2270fae7459 100644 --- a/code/controllers/Processes/machinery.dm +++ b/code/controllers/Processes/machinery.dm @@ -1,67 +1,105 @@ /var/global/machinery_sort_required = 0 +#define STAGE_NONE 0 +#define STAGE_MACHINERY 1 +#define STAGE_POWERNET 2 +#define STAGE_POWERSINK 3 +#define STAGE_PIPENET 4 + +/datum/controller/process/machinery + var/tmp/list/processing_machinery = list() + var/tmp/list/processing_powernets = list() + var/tmp/list/processing_powersinks = list() + var/tmp/list/processing_pipenets = list() + var/stage = STAGE_NONE + /datum/controller/process/machinery/setup() name = "machinery" - schedule_interval = 20 // every 2 seconds + schedule_interval = 2 SECONDS start_delay = 12 /datum/controller/process/machinery/doWork() - internal_sort() - internal_process_pipenets() - internal_process_machinery() - internal_process_power() - internal_process_power_drain() + // If we're starting a new tick, setup. + if (stage == STAGE_NONE) + processing_machinery = machines.Copy() + stage = STAGE_MACHINERY + + // Process machinery. + while (processing_machinery.len) + var/obj/machinery/M = processing_machinery[processing_machinery.len] + processing_machinery.len-- + + if (!M || M.gcDestroyed) + machines -= M + continue + + if (M.process() == PROCESS_KILL) + machines -= M + continue + + if (M.use_power) + M.auto_use_power() + + F_SCHECK + + if (stage == STAGE_MACHINERY) + processing_powernets = powernets.Copy() + stage = STAGE_POWERNET + + while (processing_powernets.len) + var/datum/powernet/PN = processing_powernets[processing_powernets.len] + processing_powernets.len-- + + if (!PN || PN.gcDestroyed) + powernets -= PN + continue + + PN.reset() + F_SCHECK + + if (stage == STAGE_POWERNET) + processing_powersinks = processing_power_items.Copy() + stage = STAGE_POWERSINK + + while (processing_powersinks.len) + var/obj/item/I = processing_powersinks[processing_powersinks.len] + processing_powersinks.len-- + + if (!I || !I.pwr_drain()) + processing_power_items -= I + + F_SCHECK + + if (stage == STAGE_POWERSINK) + processing_pipenets = pipe_networks.Copy() + stage = STAGE_PIPENET + + while (processing_pipenets.len) + var/datum/pipe_network/PN = processing_pipenets[processing_pipenets.len] + processing_pipenets.len-- + + if (!PN || PN.gcDestroyed) + continue + + PN.process() + F_SCHECK + + stage = STAGE_NONE /datum/controller/process/machinery/proc/internal_sort() if(machinery_sort_required) machinery_sort_required = 0 machines = dd_sortedObjectList(machines) -/datum/controller/process/machinery/proc/internal_process_machinery() - for(last_object in machines) - var/obj/machinery/M = last_object - if(M && !M.gcDestroyed) - if(M.process() == PROCESS_KILL) - //M.inMachineList = 0 We don't use this debugging function - machines.Remove(M) - continue - - if(M && M.use_power) - M.auto_use_power() - - SCHECK - -/datum/controller/process/machinery/proc/internal_process_power() - for(last_object in powernets) - var/datum/powernet/powerNetwork = last_object - if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed)) - powerNetwork.reset() - SCHECK - continue - - powernets.Remove(powerNetwork) - -/datum/controller/process/machinery/proc/internal_process_power_drain() - // Currently only used by powersinks. These items get priority processed before machinery - for(last_object in processing_power_items) - var/obj/item/I = last_object - if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list. - processing_power_items.Remove(I) - SCHECK - -/datum/controller/process/machinery/proc/internal_process_pipenets() - for(last_object in pipe_networks) - var/datum/pipe_network/pipeNetwork = last_object - if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed)) - pipeNetwork.process() - SCHECK - continue - - pipe_networks.Remove(pipeNetwork) - /datum/controller/process/machinery/statProcess() ..() - stat(null, "[machines.len] machines") - stat(null, "[powernets.len] powernets") - stat(null, "[pipe_networks.len] pipenets") - stat(null, "[processing_power_items.len] power item\s") + stat(null, "[machines.len] machines, [processing_machinery.len] queued") + stat(null, "[powernets.len] powernets, [processing_powernets.len] queued") + stat(null, "[processing_power_items.len] power items, [processing_powersinks.len] queued") + stat(null, "[pipe_networks.len] pipenets, [processing_pipenets.len] queued") + +#undef STAGE_NONE +#undef STAGE_MACHINERY +#undef STAGE_POWERNET +#undef STAGE_POWERSINK +#undef STAGE_PIPENET diff --git a/code/controllers/Processes/mob.dm b/code/controllers/Processes/mob.dm index 8681803ac44..ead2791dd69 100644 --- a/code/controllers/Processes/mob.dm +++ b/code/controllers/Processes/mob.dm @@ -1,9 +1,11 @@ /datum/controller/process/mob var/tmp/datum/updateQueue/updateQueueInstance + var/tmp/list/queue = list() + var/normal_exit = TRUE /datum/controller/process/mob/setup() name = "mob" - schedule_interval = 20 // every 2 seconds + schedule_interval = 2 SECONDS // every 2 seconds start_delay = 16 /datum/controller/process/mob/started() @@ -12,18 +14,24 @@ mob_list = list() /datum/controller/process/mob/doWork() - for(last_object in mob_list) - var/mob/M = last_object - if(M && isnull(M.gcDestroyed)) - try - M.Life() - catch(var/exception/e) - catchException(e, M) - SCHECK - else - catchBadType(M) + if (normal_exit) + queue = mob_list.Copy() + + normal_exit = FALSE + + while (queue.len) + var/mob/M = queue[queue.len] + queue.len-- + + if (!M || M.gcDestroyed) mob_list -= M + continue + + M.Life() + F_SCHECK + + normal_exit = TRUE /datum/controller/process/mob/statProcess() ..() - stat(null, "[mob_list.len] mobs") \ No newline at end of file + stat(null, "[mob_list.len] mobs, [queue.len] queued") diff --git a/code/controllers/Processes/nanoui.dm b/code/controllers/Processes/nanoui.dm index 1667af943da..fb43970709d 100644 --- a/code/controllers/Processes/nanoui.dm +++ b/code/controllers/Processes/nanoui.dm @@ -1,12 +1,35 @@ +/datum/controller/process/nanoui + var/is_idle = TRUE + var/list/queued_uis = list() + /datum/controller/process/nanoui/setup() name = "nanoui" - schedule_interval = 20 // every 2 seconds + schedule_interval = 2 SECONDS /datum/controller/process/nanoui/statProcess() ..() - stat(null, "[nanomanager.processing_uis.len] UIs") + stat(null, "[nanomanager.processing_uis.len] UIs, [queued_uis.len] processing") /datum/controller/process/nanoui/doWork() + if (is_idle) + queued_uis = nanomanager.processing_uis.Copy() + is_idle = FALSE + + while (queued_uis.len) + var/datum/nanoui/UI = queued_uis[queued_uis.len] + queued_uis.len-- + + if (!UI || UI.gcDestroyed) + catchBadType(UI) + nanomanager.processing_uis -= UI + continue + + UI.process() + F_SCHECK + + is_idle = TRUE + +/*datum/controller/process/nanoui/doWork() for(last_object in nanomanager.processing_uis) var/datum/nanoui/NUI = last_object if(istype(NUI) && isnull(NUI.gcDestroyed)) @@ -17,3 +40,4 @@ else catchBadType(NUI) nanomanager.processing_uis -= NUI +*/ diff --git a/code/controllers/Processes/night_lighting.dm b/code/controllers/Processes/night_lighting.dm index fc463f8a53d..94fa9fd939b 100644 --- a/code/controllers/Processes/night_lighting.dm +++ b/code/controllers/Processes/night_lighting.dm @@ -54,14 +54,14 @@ var/datum/controller/process/night_lighting/nl_ctrl for (var/obj/machinery/power/apc/APC in get_apc_list(whitelisted_only)) APC.toggle_nightlight("on") - SCHECK + F_SCHECK /datum/controller/process/night_lighting/proc/deactivate(var/whitelisted_only = 1) isactive = 0 for (var/obj/machinery/power/apc/APC in get_apc_list(whitelisted_only)) APC.toggle_nightlight("off") - SCHECK + F_SCHECK /datum/controller/process/night_lighting/proc/get_apc_list(var/whitelisted_only = 1) var/list/obj/machinery/power/apc/lighting_apcs = list() @@ -73,6 +73,6 @@ var/datum/controller/process/night_lighting/nl_ctrl if (B.apc && !B.apc.aidisabled) lighting_apcs += B.apc - SCHECK + F_SCHECK return lighting_apcs diff --git a/code/controllers/Processes/obj.dm b/code/controllers/Processes/obj.dm index b3f52a9bcfc..b0cea9c2ed0 100644 --- a/code/controllers/Processes/obj.dm +++ b/code/controllers/Processes/obj.dm @@ -1,6 +1,10 @@ +/datum/controller/process/obj + var/normal_exit = TRUE + var/list/queue = list() + /datum/controller/process/obj/setup() name = "obj" - schedule_interval = 20 // every 2 seconds + schedule_interval = 2 SECONDS start_delay = 8 /datum/controller/process/obj/started() @@ -9,18 +13,23 @@ processing_objects = list() /datum/controller/process/obj/doWork() - for(last_object in processing_objects) - var/datum/O = last_object - if(isnull(O.gcDestroyed)) - try - O:process() - catch(var/exception/e) - catchException(e, O) - SCHECK - else - catchBadType(O) + if (normal_exit) + queue = processing_objects.Copy() + normal_exit = FALSE + + while (queue.len) + var/datum/O = queue[queue.len] + queue.len-- + + if (!O || O.gcDestroyed) processing_objects -= O + continue + + O:process() + F_SCHECK + + normal_exit = TRUE /datum/controller/process/obj/statProcess() ..() - stat(null, "[processing_objects.len] objects") + stat(null, "[processing_objects.len] objects, [queue.len] queued") diff --git a/code/controllers/Processes/scheduler.dm b/code/controllers/Processes/scheduler.dm index 970b8b71ad3..1eb09f16dd6 100644 --- a/code/controllers/Processes/scheduler.dm +++ b/code/controllers/Processes/scheduler.dm @@ -5,6 +5,8 @@ ************/ /datum/controller/process/scheduler var/list/scheduled_tasks + var/tick_completed = TRUE + var/list/queued_tasks /datum/controller/process/scheduler/setup() name = "scheduler" @@ -13,21 +15,29 @@ scheduler = src /datum/controller/process/scheduler/doWork() - for(last_object in scheduled_tasks) - var/datum/scheduled_task/scheduled_task = last_object - try - if(world.time > scheduled_task.trigger_time) - unschedule(scheduled_task) - scheduled_task.pre_process() - scheduled_task.process() - scheduled_task.post_process() - catch(var/exception/e) - catchException(e, last_object) - SCHECK + if (tick_completed) + queued_tasks = scheduled_tasks.Copy() + tick_completed = FALSE + + while (queued_tasks.len) + var/datum/scheduled_task/task = queued_tasks[queued_tasks.len] + queued_tasks.len-- + + if (world.time > task.trigger_time) + unschedule(task) + // why are these separated. + task.pre_process() + F_SCHECK // fuck it, it's a cheap call. + task.process() + F_SCHECK + task.post_process() + F_SCHECK + + tick_completed = TRUE /datum/controller/process/scheduler/statProcess() ..() - stat(null, "[scheduled_tasks.len] task\s") + stat(null, "[scheduled_tasks.len] tasks, [queued_tasks.len] queued") /datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st) scheduled_tasks += st diff --git a/code/controllers/Processes/turf.dm b/code/controllers/Processes/turf.dm index 83e4789de1d..57ed82ca648 100644 --- a/code/controllers/Processes/turf.dm +++ b/code/controllers/Processes/turf.dm @@ -9,7 +9,7 @@ var/global/list/turf/processing_turfs = list() var/turf/T = last_object if(T.process() == PROCESS_KILL) processing_turfs.Remove(T) - SCHECK + F_SCHECK /datum/controller/process/turf/statProcess() ..() diff --git a/code/controllers/Processes/wireless.dm b/code/controllers/Processes/wireless.dm index 4affc4a74de..9c997d70947 100644 --- a/code/controllers/Processes/wireless.dm +++ b/code/controllers/Processes/wireless.dm @@ -69,4 +69,4 @@ var/datum/controller/process/wireless/wirelessProcess process_conections -= C if(!target_found) unsuccesful_connections += C - SCHECK + F_SCHECK diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index cca7c5e9b36..5b5c58c9e9a 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -76,6 +76,14 @@ datum/controller/game_controller/proc/setup_objects() T.broadcast_status() + admin_notice(span("danger", "Caching space parallax.")) + create_global_parallax_icons() + admin_notice(span("danger", "Done.")) + + admin_notice(span("danger", "Setting up lighting.")) + initialize_lighting() + admin_notice(span("danger", "Lighting Setup Completed.")) + //Spawn the contents of the cargo warehouse sleep(-1) spawn_cargo_stock() diff --git a/code/controllers/news_controller.dm b/code/controllers/news_controller.dm deleted file mode 100644 index f8d9ce3c808..00000000000 --- a/code/controllers/news_controller.dm +++ /dev/null @@ -1,94 +0,0 @@ -var/global/datum/news_controller/news_controller - -/datum/news_controller - var/count = 0 //Count of articles pulled and published - var/publish_time //Ingame time for when the stored article is to be published - var/article_id //Stored article's primary-key - var/running = 1 //Boolean value, self-explanitory - var/fails = 0 //Counter for failed queries - var/max_fails = 5 //Maximum amount of failures before the controller is killed - -/datum/news_controller/proc/process() - if(!running) //Not running, return. - return - - if(fails >= max_fails) //Too many failures, killing. - kill() - return - - if(!article_id && !publish_time) //No entry stored. Update and get one. - update() - return - - if(publish_time < world.time) //Time to publish the article. - publish() - if(fails) - fails = 0 - -//Stores a new article for publishing. -/datum/news_controller/proc/update() - establish_db_connection(dbcon) - if(!dbcon.IsConnected()) - error("SQL database connection failed. News_controller failed to retreive information.") - fails++ - return - - var/DBQuery/update_query = dbcon.NewQuery("SELECT id, publishtime FROM ss13_news WHERE status = 2 ORDER BY publishtime ASC LIMIT :count, 1") - update_query.Execute(list(":count" = count)) - - if(update_query.ErrorMsg()) - fails++ - return - - if(!update_query.RowCount()) - kill() - return - - while(update_query.NextRow()) - article_id = text2num(update_query.item[1]) - publish_time = text2num(update_query.item[2]) * 600 - - count++ - -//Publish the stored article. -/datum/news_controller/proc/publish() - establish_db_connection(dbcon) - if(!dbcon.IsConnected()) - error("SQL database connection failed. News_controller failed to retreive information.") - fails++ - return - - var/DBQuery/publish_query = dbcon.NewQuery("SELECT channel, author, body FROM ss13_news WHERE id = :article_id") - publish_query.Execute(list(":article_id" = article_id)) - - if(publish_query.ErrorMsg()) - fails++ - return - - var/article_channel - var/article_author - var/article_content - while(publish_query.NextRow()) - article_channel = publish_query.item[1] - article_author = publish_query.item[2] - article_content = publish_query.item[3] - - var/channel_found - for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == article_channel) - channel_found = 1 - break - - if(!channel_found) - news_network.CreateFeedChannel(article_channel, article_author, 0) - - news_network.SubmitArticle(article_content, article_author, article_channel) - - article_id = null - publish_time = null - update() - -//Kills the controller. -/datum/news_controller/proc/kill() - running = 0 - return diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index 96ccb49d4d0..8320fc5c1c7 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -25,7 +25,7 @@ usr.client.debug_variables(antag) message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") -/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Wireless","Observation")) +/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Wireless","Observation","Lighting","Explosives")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -98,5 +98,11 @@ if("Observation") debug_variables(all_observable_events) feedback_add_details("admin_verb", "DObservation") + if("Lighting") + debug_variables(lighting_process) + feedback_add_details("admin_verb", "DLightingP") + if("Explosives") + debug_variables(bomb_processor) + feedback_add_details("admin_verb", "DExplosives") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/datums/expansions/expansion.dm b/code/datums/expansions/expansion.dm index 3fded0f9b21..4ea9c68c8f5 100644 --- a/code/datums/expansions/expansion.dm +++ b/code/datums/expansions/expansion.dm @@ -30,7 +30,7 @@ expansions.Cut() return ..() -/obj/ResetVars(var/list/exclude = list()) +/obj/resetVariables(var/list/exclude = list()) exclude += "expansions" ..(exclude) //expansions = list() diff --git a/code/defines/obj.dm b/code/defines/obj.dm index 5368e16c493..d7b4e32ae12 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -114,7 +114,7 @@ var/global/ManifestJSON department = 1 if(depthead && sci.len != 1) sci.Swap(1,sci.len) - + if(real_rank in cargo_positions) car[++car.len] = list("name" = name, "rank" = rank, "active" = isactive) department = 1 @@ -146,7 +146,7 @@ var/global/ManifestJSON "bot" = bot,\ "misc" = misc\ ) - ManifestJSON = list2json(PDA_Manifest) + ManifestJSON = json_encode(PDA_Manifest) return diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 9af355078c9..58353a44950 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -100,7 +100,7 @@ var/list/ghostteleportlocs = list() icon_state = "space" requires_power = 1 always_unpowered = 1 - lighting_use_dynamic = 1 + dynamic_lighting = 1 power_light = 0 power_equip = 0 power_environ = 0 @@ -357,7 +357,7 @@ area/space/atmosalert() name = "\improper Centcom" icon_state = "centcom" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 no_light_control = 1 /area/centcom/control @@ -396,7 +396,7 @@ area/space/atmosalert() name = "\improper Mercenary Base" icon_state = "syndie-ship" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 no_light_control = 1 /area/syndicate_mothership/control @@ -451,7 +451,7 @@ area/space/atmosalert() name = "\improper Thunderdome" icon_state = "thunder" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 sound_env = ARENA no_light_control = 1 @@ -475,7 +475,7 @@ area/space/atmosalert() /area/acting name = "\improper Centcom Acting Guild" icon_state = "red" - lighting_use_dynamic = 0 + dynamic_lighting = 0 requires_power = 0 no_light_control = 1 @@ -484,7 +484,7 @@ area/space/atmosalert() /area/acting/stage name = "\improper Stage" - lighting_use_dynamic = 1 + dynamic_lighting = 1 icon_state = "yellow" @@ -550,7 +550,7 @@ area/space/atmosalert() name = "\improper Wizard's Den" icon_state = "yellow" requires_power = 0 - lighting_use_dynamic = 0 + dynamic_lighting = 0 no_light_control = 1 /area/skipjack_station @@ -1125,7 +1125,7 @@ area/space/atmosalert() /area/holodeck name = "\improper Holodeck" icon_state = "Holodeck" - lighting_use_dynamic = 0 + dynamic_lighting = 0 sound_env = LARGE_ENCLOSED no_light_control = 1 @@ -1279,7 +1279,7 @@ area/space/atmosalert() /area/solar requires_power = 1 always_unpowered = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 base_turf = /turf/space auxport @@ -1668,6 +1668,7 @@ area/space/atmosalert() /area/hydroponics name = "\improper Hydroponics" icon_state = "hydro" + no_light_control = TRUE /area/hydroponics/garden name = "\improper Garden" @@ -1705,10 +1706,12 @@ area/space/atmosalert() /area/rnd/xenobiology/xenoflora_storage name = "\improper Xenoflora Storage" icon_state = "xeno_f_store" + no_light_control = TRUE /area/rnd/xenobiology/xenoflora name = "\improper Xenoflora Lab" icon_state = "xeno_f_lab" + no_light_control = TRUE /area/rnd/storage name = "\improper Toxins Storage" @@ -2053,25 +2056,25 @@ area/space/atmosalert() name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/AIsatextFS name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/AIsatextAS name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/AIsatextAP name = "\improper AI Sat Ext" icon_state = "storage" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 /area/turret_protected/NewAIMain name = "\improper AI Main New" @@ -2247,7 +2250,7 @@ area/space/atmosalert() name = "Beach" icon_state = "null" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 requires_power = 0 ambience = list() var/sound/mysound = null @@ -2369,7 +2372,7 @@ var/list/the_station_areas = list ( name = "Keelin's private beach" icon_state = "null" luminosity = 1 - lighting_use_dynamic = 0 + dynamic_lighting = 0 requires_power = 0 var/sound/mysound = null no_light_control = 1 diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index e714fe776ca..e516a11f868 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -18,7 +18,7 @@ power_equip = 0 power_environ = 0 - if(lighting_use_dynamic) + if(dynamic_lighting) luminosity = 0 else luminosity = 1 diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 25769bf00b8..0fa8af01ad0 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -223,7 +223,7 @@ its easier to just keep the beam vertical. /atom/proc/set_dir(new_dir) . = new_dir != dir dir = new_dir - for(var/datum/light_source/L in light_sources) + /*for(var/datum/light_source/L in light_sources) if (L.source_atom.offset_light) L.force_update = 1 if (world.tick_usage < 80) @@ -231,7 +231,7 @@ its easier to just keep the beam vertical. //This makes things more responsive, but probably has a performance cost for people spinning rapidly //Ergo, it checks tick usage first else - L.source_atom.update_light() + L.source_atom.update_light()*/ /atom/proc/ex_act() return @@ -505,3 +505,9 @@ its easier to just keep the beam vertical. else if(ismob(I)) var/mob/M = I M.show_message( message, 2, deaf_message, 1) + +/atom/proc/change_area(var/area/oldarea, var/area/newarea) + change_area_name(oldarea.name, newarea.name) + +/atom/proc/change_area_name(var/oldname, var/newname) + name = replacetext(name,oldname,newname) \ No newline at end of file diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 78e928f0f8b..097479b0ab9 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -72,7 +72,9 @@ loc.Exited(src) loc = destination loc.Entered(src) + update_client_hook(loc) return 1 + update_client_hook(loc) return 0 //called when src is thrown into hit_atom @@ -274,3 +276,19 @@ var/list/accessible_z_levels = list("1" = 5, "3" = 10, "4" = 15, "6" = 60) if(!candidates.len) return null return text2num(pickweight(candidates)) + +// Parallax stuff. + +/atom/movable/proc/update_client_hook(atom/destination) + if(locate(/mob) in src) + for(var/client/C in parallax_on_clients) + if((get_turf(C.eye) == destination) && (C.mob.hud_used)) + C.mob.hud_used.update_parallax_values() + +/mob/update_client_hook(atom/destination) + if(locate(/mob) in src) + for(var/client/C in parallax_on_clients) + if((get_turf(C.eye) == destination) && (C.mob.hud_used)) + C.mob.hud_used.update_parallax_values() + else if(client && hud_used) + hud_used.update_parallax_values() diff --git a/code/game/dna/dna.dm b/code/game/dna/dna.dm deleted file mode 100644 index 2835a1614ed..00000000000 --- a/code/game/dna/dna.dm +++ /dev/null @@ -1,128 +0,0 @@ -/////////////////////////// DNA DATUM -/datum/dna - var/unique_enzymes = null - var/struc_enzymes = null - var/uni_identity = null - var/b_type = "A+" - var/mutantrace = null //The type of mutant race the player is if applicable (i.e. potato-man) - var/real_name //Stores the real name of the person who originally got this dna datum. Used primarely for changelings, - -/datum/dna/proc/check_integrity(var/mob/living/carbon/human/character) - if(character) - if(length(uni_identity) != 39) - //Lazy. - var/temp - - //Hair - var/hair = 0 - if(!character.h_style) - character.h_style = "Skinhead" - - var/hrange = round(4095 / hair_styles_list.len) - var/index = hair_styles_list.Find(character.h_style) - if(index) - hair = index * hrange - rand(1,hrange-1) - - //Facial Hair - var/beard = 0 - if(!character.f_style) - character.f_style = "Shaved" - - var/f_hrange = round(4095 / facial_hair_styles_list.len) - index = facial_hair_styles_list.Find(character.f_style) - if(index) - beard = index * f_hrange - rand(1,f_hrange-1) - - temp = add_zero2(num2hex((character.r_hair),1), 3) - temp += add_zero2(num2hex((character.b_hair),1), 3) - temp += add_zero2(num2hex((character.g_hair),1), 3) - temp += add_zero2(num2hex((character.r_facial),1), 3) - temp += add_zero2(num2hex((character.b_facial),1), 3) - temp += add_zero2(num2hex((character.g_facial),1), 3) - temp += add_zero2(num2hex(((character.s_tone + 220) * 16),1), 3) - temp += add_zero2(num2hex((character.r_eyes),1), 3) - temp += add_zero2(num2hex((character.g_eyes),1), 3) - temp += add_zero2(num2hex((character.b_eyes),1), 3) - - var/gender - - if (character.gender == MALE) - gender = add_zero2(num2hex((rand(1,(2050+BLOCKADD))),1), 3) - else - gender = add_zero2(num2hex((rand((2051+BLOCKADD),4094)),1), 3) - - temp += gender - temp += add_zero2(num2hex((beard),1), 3) - temp += add_zero2(num2hex((hair),1), 3) - - uni_identity = temp - if(length(struc_enzymes)!= 3*STRUCDNASIZE) - var/mutstring = "" - for(var/i = 1, i <= STRUCDNASIZE, i++) - mutstring += add_zero2(num2hex(rand(1,1024)),3) - - struc_enzymes = mutstring - if(length(unique_enzymes) != 32) - unique_enzymes = md5(character.real_name) - else - if(length(uni_identity) != 39) uni_identity = "00600200A00E0110148FC01300B0095BD7FD3F4" - if(length(struc_enzymes)!= 3*STRUCDNASIZE) struc_enzymes = "43359156756131E13763334D1C369012032164D4FE4CD61544B6C03F251B6C60A42821D26BA3B0FD6" - -/datum/dna/proc/ready_dna(mob/living/carbon/human/character) - var/temp - - //Hair - var/hair = 0 - if(!character.h_style) - character.h_style = "Bald" - - var/hrange = round(4095 / hair_styles_list.len) - var/index = hair_styles_list.Find(character.h_style) - if(index) - hair = index * hrange - rand(1,hrange-1) - - //Facial Hair - var/beard = 0 - if(!character.f_style) - character.f_style = "Shaved" - - var/f_hrange = round(4095 / facial_hair_styles_list.len) - index = facial_hair_styles_list.Find(character.f_style) - if(index) - beard = index * f_hrange - rand(1,f_hrange-1) - - temp = add_zero2(num2hex((character.r_hair),1), 3) - temp += add_zero2(num2hex((character.b_hair),1), 3) - temp += add_zero2(num2hex((character.g_hair),1), 3) - temp += add_zero2(num2hex((character.r_facial),1), 3) - temp += add_zero2(num2hex((character.b_facial),1), 3) - temp += add_zero2(num2hex((character.g_facial),1), 3) - temp += add_zero2(num2hex(((character.s_tone + 220) * 16),1), 3) - temp += add_zero2(num2hex((character.r_eyes),1), 3) - temp += add_zero2(num2hex((character.g_eyes),1), 3) - temp += add_zero2(num2hex((character.b_eyes),1), 3) - - var/gender - - if (character.gender == MALE) - gender = add_zero2(num2hex((rand(1,(2050+BLOCKADD))),1), 3) - else - gender = add_zero2(num2hex((rand((2051+BLOCKADD),4094)),1), 3) - - temp += gender - temp += add_zero2(num2hex((beard),1), 3) - temp += add_zero2(num2hex((hair),1), 3) - - uni_identity = temp - - var/mutstring = "" - for(var/i = 1, i <= STRUCDNASIZE, i++) - mutstring += add_zero2(num2hex(rand(1,1024)),3) - - - struc_enzymes = mutstring - - unique_enzymes = md5(character.real_name) - reg_dna[unique_enzymes] = character.real_name - -/////////////////////////// DNA DATUM \ No newline at end of file diff --git a/code/game/gamemodes/cult/hell_universe.dm b/code/game/gamemodes/cult/hell_universe.dm index e81a6a2673d..3dcc852da4e 100644 --- a/code/game/gamemodes/cult/hell_universe.dm +++ b/code/game/gamemodes/cult/hell_universe.dm @@ -46,6 +46,7 @@ In short: escape_list = get_area_turfs(locate(/area/hallway/secondary/exit)) + convert_all_parallax() //Separated into separate procs for profiling AreaSet() MiscSet() @@ -62,23 +63,36 @@ In short: continue A.updateicon() + CHECK_TICK /datum/universal_state/hell/OverlayAndAmbientSet() - spawn(0) - for(var/atom/movable/lighting_overlay/L in world) - L.update_lumcount(1, 0, 0) + set waitfor = FALSE + for(var/turf/T in turfs) + if(istype(T, /turf/space)) + T.overlays += image(icon = T.icon, icon_state = "hell01") + else + if(!T.holy && prob(1) && !(T.z in config.admin_levels)) + new /obj/effect/gateway/active/cult(T) + T.underlays += "hell01" + CHECK_TICK - for(var/turf/space/T in turfs) - OnTurfChange(T) + for(var/datum/lighting_corner/C in global.all_lighting_corners) + if (!C.active) + continue + + C.update_lumcount(0.5, 0, 0) + CHECK_TICK /datum/universal_state/hell/proc/MiscSet() for(var/turf/simulated/floor/T in turfs) if(!T.holy && prob(1)) new /obj/effect/gateway/active/cult(T) + CHECK_TICK for (var/obj/machinery/firealarm/alm in machines) if (!(alm.stat & BROKEN)) alm.ex_act(2) + CHECK_TICK /datum/universal_state/hell/proc/APCSet() for (var/obj/machinery/power/apc/APC in machines) @@ -88,8 +102,26 @@ In short: APC.cell.charge = 0 APC.emagged = 1 APC.queue_icon_update() + CHECK_TICK /datum/universal_state/hell/proc/KillMobs() for(var/mob/living/simple_animal/M in mob_list) if(M && !M.client) M.stat = DEAD + CHECK_TICK + +// Parallax. + +/datum/universal_state/hell/convert_parallax(obj/screen/plane_master/parallax_spacemaster/PS) + PS.color = list( + 0,0,0,0, + 0,0,0,0, + 0,0,0,0, + 1,0,0,1) + +/datum/universal_state/hell/proc/convert_all_parallax() + for(var/client/C in clients) + var/obj/screen/plane_master/parallax_spacemaster/PS = locate() in C.screen + if(PS) + convert_parallax(PS) + CHECK_TICK diff --git a/code/game/gamemodes/cult/narsie.dm b/code/game/gamemodes/cult/narsie.dm index a3248a07e5b..4a696a3da49 100644 --- a/code/game/gamemodes/cult/narsie.dm +++ b/code/game/gamemodes/cult/narsie.dm @@ -72,6 +72,7 @@ var/global/list/narsie_list = list() /obj/singularity/narsie/large/eat() for (var/turf/A in orange(consume_range, src)) consume(A) + CHECK_TICK /obj/singularity/narsie/mezzer() for(var/mob/living/carbon/M in oviewers(8, src)) @@ -152,7 +153,7 @@ var/global/list/narsie_list = list() T.desc = "An opening has been made on that wall, but who can say if what you seek truly lies on the other side?" T.icon = 'icons/turf/walls.dmi' T.icon_state = "cult-narsie" - T.opacity = 0 + T.set_opacity(0) T.density = 0 set_light(1) diff --git a/code/game/gamemodes/endgame/endgame.dm b/code/game/gamemodes/endgame/endgame.dm index aef7894800c..652b02e8219 100644 --- a/code/game/gamemodes/endgame/endgame.dm +++ b/code/game/gamemodes/endgame/endgame.dm @@ -69,3 +69,5 @@ universe = new newstate if(on_enter) universe.OnEnter() + +/datum/universal_state/proc/convert_parallax(parallax_spacemaster) \ No newline at end of file diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index 3374f8f9be6..463ee14c328 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -13,11 +13,11 @@ var/global/universe_has_ended = 0 return 0 /datum/universal_state/supermatter_cascade/OnTurfChange(var/turf/T) - var/turf/space/S = T - if(istype(S)) - S.color = "#0066FF" + if(T.name == "space") + T.overlays += image(icon = T.icon, icon_state = "end01") + T.underlays -= "end01" else - S.color = initial(S.color) + T.overlays -= image(icon = T.icon, icon_state = "end01") /datum/universal_state/supermatter_cascade/DecayTurf(var/turf/T) if(istype(T,/turf/simulated/wall)) @@ -90,22 +90,31 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked continue A.updateicon() + CHECK_TICK /datum/universal_state/supermatter_cascade/OverlayAndAmbientSet() - spawn(0) - for(var/atom/movable/lighting_overlay/L in world) - if(L.z in config.admin_levels) - L.update_lumcount(1,1,1) - else - L.update_lumcount(0.0, 0.4, 1) + set waitfor = FALSE + for(var/turf/T in turfs) + if(istype(T, /turf/space)) + T.overlays += image(icon = T.icon, icon_state = "end01") + else + if (!(T.z in config.admin_levels)) + T.underlays += "end01" + CHECK_TICK - for(var/turf/space/T in turfs) - OnTurfChange(T) + for(var/datum/lighting_corner/C in global.all_lighting_corners) + if (!C.active) + continue + + if (!(C.z in config.admin_levels)) + C.update_lumcount(0.15, 0.5, 0) + CHECK_TICK /datum/universal_state/supermatter_cascade/proc/MiscSet() for (var/obj/machinery/firealarm/alm in machines) if (!(alm.stat & BROKEN)) alm.ex_act(2) + CHECK_TICK /datum/universal_state/supermatter_cascade/proc/APCSet() for (var/obj/machinery/power/apc/APC in machines) @@ -115,6 +124,7 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked APC.cell.charge = 0 APC.emagged = 1 APC.queue_icon_update() + CHECK_TICK /datum/universal_state/supermatter_cascade/proc/PlayerSet() for(var/datum/mind/M in player_list) @@ -125,3 +135,4 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked flick("e_flash", M.current.flash) clear_antag_roles(M) + CHECK_TICK diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 9b60a9043d2..71441625f1f 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -30,6 +30,8 @@ var/global/datum/controller/gameticker/ticker var/delay_end = 0 //if set to nonzero, the round will not restart on it's own var/triai = 0//Global holder for Triumvirate + var/tipped = 0 //Did we broadcast the tip of the day yet? + var/selected_tip // What will be the tip of the day? var/round_end_announced = 0 // Spam Prevention. Announce round end only once. @@ -60,6 +62,9 @@ var/global/datum/controller/gameticker/ticker for(var/i=0, i<10, i++) sleep(1) vote.process() + if(pregame_timeleft <= 10 && !tipped) + send_tip_of_the_round() + tipped = 1 if(pregame_timeleft <= 0) current_state = GAME_STATE_SETTING_UP while (!setup()) @@ -447,3 +452,16 @@ var/global/datum/controller/gameticker/ticker log_game("[i]s[total_antagonists[i]].") return 1 + +/datum/controller/gameticker/proc/send_tip_of_the_round() + var/m + if(selected_tip) + m = selected_tip + else + var/list/randomtips = file2list("config/tips.txt") + if(randomtips.len) + m = pick(randomtips) + + if(m) + world << "Tip of the round: \ + [html_encode(m)]" diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 6c1538698e2..e483bb0c30a 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -215,11 +215,7 @@ src << "Your powers are not capable of taking you that far." return - var/atom/movable/lighting_overlay/light = T.lighting_overlay - if (!light) - return - - if (max(light.lum_r, light.lum_g, light.lum_b) > 1) + if (!T.dynamic_lighting || T.get_lumcount() > 0.1) // Too bright, cannot jump into. src << "The destination is too bright." return diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index ccbae49934c..01f95d2a360 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -333,7 +333,7 @@ var/global/datum/controller/occupations/job_master else permitted = 1 - if(G.whitelisted && (G.whitelisted != H.species.name || !is_alien_whitelisted(H, G.whitelisted))) + if(G.whitelisted && !is_alien_whitelisted(H, all_species[G.whitelisted])) permitted = 0 if(!permitted) @@ -343,10 +343,11 @@ var/global/datum/controller/occupations/job_master if(G.slot && !(G.slot in custom_equip_slots)) // This is a miserable way to fix the loadout overwrite bug, but the alternative requires // adding an arg to a bunch of different procs. Will look into it after this merge. ~ Z + var/metadata = H.client.prefs.gear[G.display_name] if(G.slot == slot_wear_mask || G.slot == slot_wear_suit || G.slot == slot_head) custom_equip_leftovers += thing - else if(H.equip_to_slot_or_del(new G.path(H), G.slot)) - H << "Equipping you with [thing]!" + else if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot)) + H << "Equipping you with \the [thing]!" custom_equip_slots.Add(G.slot) else custom_equip_leftovers.Add(thing) @@ -365,8 +366,9 @@ var/global/datum/controller/occupations/job_master if(G.slot in custom_equip_slots) spawn_in_storage += thing else - if(H.equip_to_slot_or_del(new G.path(H), G.slot)) - H << "Equipping you with [thing]!" + var/metadata = H.client.prefs.gear[G.display_name] + if(H.equip_to_slot_or_del(G.spawn_item(H, metadata), G.slot)) + H << "Equipping you with \the [thing]!" custom_equip_slots.Add(G.slot) else spawn_in_storage += thing @@ -429,9 +431,10 @@ var/global/datum/controller/occupations/job_master if(!isnull(B)) for(var/thing in spawn_in_storage) - H << "Placing [thing] in your [B]!" + H << "Placing \the [thing] in your [B.name]!" var/datum/gear/G = gear_datums[thing] - new G.path(B) + var/metadata = H.client.prefs.gear[G.display_name] + G.spawn_item(B, metadata) else H << "Failed to locate a storage object on your mob, either you spawned with no arms and no backpack or this is a bug." diff --git a/code/game/json.dm b/code/game/json.dm deleted file mode 100644 index 340ffa23f93..00000000000 --- a/code/game/json.dm +++ /dev/null @@ -1,100 +0,0 @@ - -var/jsonpath = "/home/bay12/public_html" -var/dmepath = "/home/bay12/git/baystation12.dme" -var/makejson = 1 //temp -proc/makejson() - - if(!makejson) - return - fdel("[jsonpath]/info.json") - //usr << "Error cant delete json" - //else - //usr << "Deleted json in public html" - fdel("info.json") - //usr << "error cant delete local json" - //else - //usr << "Deleted local json" - var/F = file("info.json") - if(!isfile(F)) - return - var/mode - if(ticker) - if(ticker.current_state == 1) - mode = "Round Setup" - else if(ticker.hide_mode) - mode = "SECRET" - else - mode = master_mode - var/playerscount = 0 - var/players = "" - var/admins = "no" - for(var/client/C) - playerscount++ - if(C.holder && C.holder.level >= 0) // make sure retired admins don't make nt think admins are on - if(!C.stealth) - admins = "yes" - players += "[C.key];" - else - players += "[C.fakekey];" - else - players += "[C.key];" - F << "{\"mode\":\"[mode]\",\"players\" : \"[players]\",\"playercount\" : \"[playerscount]\",\"admin\" : \"[admins]\",\"time\" : \"[time2text(world.realtime,"MM/DD - hh:mm")]\"}" - fcopy("info.json","[jsonpath]/info.json") - -/proc/switchmap(newmap,newpath) - var/oldmap - var/obj/mapinfo/M = locate() - - if(M) - oldmap = M.mapname - - else - message_admins("Did not locate mapinfo object. Go bug the mapper to add a /obj/mapinfo to their map!\n For now, you can probably spawn one manually. If you do, be sure to set it's mapname var correctly, or else you'll just get an error again.") - return - - message_admins("Current map: [oldmap]") - var/text = file2text(dmepath) - var/path = "#include \"maps/[oldmap].dmm\"" - var/xpath = "#include \"maps/[newpath].dmm\"" - var/loc = findtext(text,path,1,0) - if(!loc) - path = "#include \"maps\\[oldmap].dmm\"" - xpath = "#include \"maps\\[newpath].dmm\"" - loc = findtext(text,path,1,0) - if(!loc) - message_admins("Could not find '#include \"maps\\[oldmap].dmm\"' or '\"maps/[oldmap].dmm\"' in the bs12.dme. The mapinfo probably has an incorrect mapname var. Alternatively, could not find the .dme itself, at [dmepath].") - return - - var/rest = copytext(text, loc + length(path)) - text = copytext(text,1,loc) - text += "\n[xpath]" - text += rest -/* for(var/A in lines) - if(findtext(A,path,1,0)) - lineloc = lines.Find(A,1,0) - lines[lineloc] = xpath - world << "FOUND"*/ - fdel(dmepath) - var/file = file(dmepath) - file << text - message_admins("Compiling...") - shell("./recompile") - message_admins("Done") - world.Reboot("Switching to [newmap]") - -obj/mapinfo - invisibility = 101 - var/mapname = "thismap" - var/decks = 4 -proc/GetMapInfo() -// var/obj/mapinfo/M = locate() -// Just removing these to try and fix the occasional JSON -> WORLD issue. -// world << M.name -// world << M.mapname -client/proc/ChangeMap(var/X as text) - set name = "Change Map" - set category = "Admin" - switchmap(X,X) -proc/send2adminirc(channel,msg) - world << channel << " "<< msg - shell("python nudge.py '[channel]' [msg]") \ No newline at end of file diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index a27e560a266..ecdea629406 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -361,7 +361,7 @@ icon_state = "alarm1" new_color = "#DA0205" - set_light(l_range = 2, l_power = 0.5, l_color = new_color) + set_light(l_range = L_WALLMOUNT_RANGE, l_power = L_WALLMOUNT_POWER, l_color = new_color) /obj/machinery/alarm/receive_signal(datum/signal/signal) if(stat & (NOPOWER|BROKEN)) diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index a59643411ec..31e5978f99f 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -76,6 +76,7 @@ obj/machinery/air_sensor/Destroy() /obj/machinery/computer/general_air_control icon = 'icons/obj/computer.dmi' icon_screen = "tank" + light_color = LIGHT_COLOR_CYAN name = "Computer" diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm index 16cbb7fa9d9..1b892c3911c 100644 --- a/code/game/machinery/bots/bots.dm +++ b/code/game/machinery/bots/bots.dm @@ -110,7 +110,7 @@ /obj/machinery/bot/emp_act(severity) var/was_on = on stat |= EMPED - var/obj/effect/overlay/pulse2 = PoolOrNew(/obj/effect/overlay, src.loc ) + var/obj/effect/overlay/pulse2 = getFromPool(/obj/effect/overlay, src.loc ) pulse2.icon = 'icons/effects/effects.dmi' pulse2.icon_state = "empdisable" pulse2.name = "emp sparks" diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm index 0f6f894e097..7284feb7482 100644 --- a/code/game/machinery/bots/mulebot.dm +++ b/code/game/machinery/bots/mulebot.dm @@ -870,8 +870,8 @@ var/turf/Tsec = get_turf(src) new /obj/item/device/assembly/prox_sensor(Tsec) - PoolOrNew(/obj/item/stack/rods, Tsec) - PoolOrNew(/obj/item/stack/rods, Tsec) + getFromPool(/obj/item/stack/rods, Tsec) + getFromPool(/obj/item/stack/rods, Tsec) new /obj/item/stack/cable_coil/cut(Tsec) if (cell) cell.loc = Tsec diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 46eff98421d..eef19766848 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -5,6 +5,7 @@ density = 1 anchored = 1.0 + light_color = LIGHT_COLOR_CYAN icon_screen = "crew" circuit = /obj/item/weapon/circuitboard/operating var/mob/living/carbon/human/victim = null diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index 7636640ca01..f2e62715d83 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -10,7 +10,7 @@ var/global/list/minor_air_alarms = list() circuit = /obj/item/weapon/circuitboard/atmos_alert icon_screen = "alert:0" - light_color = "#e6ffff" + light_color = LIGHT_COLOR_CYAN /obj/machinery/computer/atmos_alert/initialize() ..() diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm index adece8961b2..f9c7be55df0 100644 --- a/code/game/machinery/computer/guestpass.dm +++ b/code/game/machinery/computer/guestpass.dm @@ -45,6 +45,7 @@ desc = "Allows issuing temporary access to an area." icon_state = "guest" + light_color = LIGHT_COLOR_BLUE icon_screen = "pass" density = 0 diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 5a4a0372f31..7cf08d61fcd 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -3,6 +3,7 @@ /obj/machinery/computer/aiupload name = "\improper AI upload console" desc = "Used to upload laws to the AI." + light_color = LIGHT_COLOR_GREEN icon_screen = "command" circuit = /obj/item/weapon/circuitboard/aiupload @@ -59,6 +60,7 @@ /obj/machinery/computer/borgupload name = "cyborg upload console" desc = "Used to upload laws to Cyborgs." + light_color = LIGHT_COLOR_GREEN icon_screen = "command" circuit = /obj/item/weapon/circuitboard/borgupload diff --git a/code/game/machinery/computer/sentencing.dm b/code/game/machinery/computer/sentencing.dm index 70f62055723..09e125eb8ea 100644 --- a/code/game/machinery/computer/sentencing.dm +++ b/code/game/machinery/computer/sentencing.dm @@ -3,6 +3,7 @@ desc = "Used to generate a criminal sentence." icon_state = "securityw" icon_screen = null + light_color = LIGHT_COLOR_ORANGE req_one_access = list( access_brig, access_heads ) circuit = "/obj/item/weapon/circuitboard/sentencing" density = 0 diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm index 61ee8610ea2..c5039b0d68d 100644 --- a/code/game/machinery/computer/station_alert.dm +++ b/code/game/machinery/computer/station_alert.dm @@ -4,7 +4,7 @@ desc = "Used to access the station's automated alert system." icon_screen = "alert:0" - light_color = "#e6ffff" + light_color = LIGHT_COLOR_CYAN circuit = /obj/item/weapon/circuitboard/stationalert var/datum/nano_module/alarm_monitor/alarm_monitor var/monitor_type = /datum/nano_module/alarm_monitor diff --git a/code/game/machinery/computer/supply.dm b/code/game/machinery/computer/supply.dm index d1a64cc0d32..552b2302660 100644 --- a/code/game/machinery/computer/supply.dm +++ b/code/game/machinery/computer/supply.dm @@ -3,7 +3,7 @@ icon = 'icons/obj/computer.dmi' icon_screen = "supply" - light_color = "#b88b2e" + light_color = LIGHT_COLOR_ORANGE req_access = list(access_cargo) circuit = /obj/item/weapon/circuitboard/supplycomp var/temp = null @@ -16,6 +16,7 @@ name = "supply ordering console" icon = 'icons/obj/computer.dmi' icon_screen = "request" + light_color = LIGHT_COLOR_ORANGE circuit = /obj/item/weapon/circuitboard/ordercomp var/temp = null var/reqtime = 0 //Cooldown for requisitions - Quarxink diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 1ced85e8545..342187a2f54 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -14,6 +14,7 @@ desc = "An interface between crew and the cryogenic storage oversight systems." icon = 'icons/obj/Cryogenic2.dmi' icon_state = "cellconsole" + light_color = LIGHT_COLOR_GREEN circuit = /obj/item/weapon/circuitboard/cryopodcontrol density = 0 interact_offline = 1 diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 0140a33fe37..912e8416813 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -64,7 +64,7 @@ for reference: var/health = 100 var/maxhealth = 100 var/material/material - + /obj/structure/barricade/New(var/newloc, var/material_name) ..(newloc) if(!material_name) @@ -77,7 +77,7 @@ for reference: desc = "This space is blocked off by a barricade made of [material.display_name]." color = material.icon_colour maxhealth = material.integrity - health = maxhealth + health = maxhealth /obj/structure/barricade/get_material() return material @@ -239,7 +239,7 @@ for reference: var/turf/Tsec = get_turf(src) /* var/obj/item/stack/rods/ =*/ - PoolOrNew(/obj/item/stack/rods, Tsec) + getFromPool(/obj/item/stack/rods, Tsec) var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(3, 1, src) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 044e3973b51..208d03a2f1c 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -41,6 +41,7 @@ var/_wifi_id var/datum/wifi/receiver/button/door/wifi_receiver + var/has_set_boltlight = FALSE /obj/machinery/door/airlock/attack_generic(var/mob/user, var/damage) if(stat & (BROKEN|NOPOWER)) @@ -564,17 +565,22 @@ About the new airlock wires panel: else return 0 +// Only set_light() if there's a change, no need to waste processor cycles with lighting updates. /obj/machinery/door/airlock/update_icon() if (!isnull(gcDestroyed)) return - set_light(0) if(overlays) overlays.Cut() if(density) if(locked && lights && src.arePowerSystemsOn()) icon_state = "door_locked" - set_light(1.5, 0.5, COLOR_RED_LIGHT) + if (!has_set_boltlight) + set_light(2, 0.75, COLOR_RED_LIGHT, update_type = UPDATE_NONE) + has_set_boltlight = TRUE else icon_state = "door_closed" + if (has_set_boltlight) + set_light(0, update_type = UPDATE_NONE) + has_set_boltlight = FALSE if(p_open || welded) overlays = list() if(p_open) @@ -599,6 +605,14 @@ About the new airlock wires panel: icon_state = "door_open" if((stat & BROKEN) && !(stat & NOPOWER)) overlays += image(icon, "sparks_open") + if (has_set_boltlight) + set_light(0, update_type = UPDATE_NONE) + has_set_boltlight = FALSE + + if (src) + var/turf/T = get_turf(src) + if (T) + T.update_lights_now() return /obj/machinery/door/airlock/do_animate(animation) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index e94560ee394..3d4d087ab43 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -228,7 +228,7 @@ switch (Proj.damage_type) if(BRUTE) new /obj/item/stack/material/steel(src.loc, 2) - PoolOrNew(/obj/item/stack/rods, list(src.loc, 3)) + getFromPool(/obj/item/stack/rods, list(src.loc, 3)) if(BURN) new /obj/effect/decal/cleanable/ash(src.loc) // Turn it to ashes! qdel(src) @@ -534,9 +534,13 @@ if(!air_master) return 0 - for(var/turf/simulated/turf in locs) - update_heat_protection(turf) - air_master.mark_for_update(turf) + for(var/turf/T in locs) + if (istype(T, /turf/simulated)) + var/turf/simulated/turf = T + update_heat_protection(turf) + air_master.mark_for_update(turf) + + T.update_lights_now() return 1 diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 565eda9d96e..5ee94574a88 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -3,6 +3,8 @@ desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever." icon = 'icons/obj/monitors.dmi' icon_state = "fire0" + var/previous_state = 0 + var/previous_fire_state = FALSE var/detecting = 1 var/working = 1 var/time = 10 @@ -29,7 +31,6 @@ icon_state="fire_b1" if(0) icon_state="fire_b0" - set_light(0) return if(stat & BROKEN) @@ -42,14 +43,22 @@ var/area/A = get_area(src) if(A.fire) icon_state = "fire1" - set_light(l_range = 4, l_power = 2, l_color = COLOR_RED) + set_light(l_range = L_WALLMOUNT_HI_RANGE, l_power = L_WALLMOUNT_HI_POWER, l_color = COLOR_RED) else icon_state = "fire0" switch(seclevel) - if("green") set_light(l_range = 2, l_power = 0.5, l_color = COLOR_LIME) - if("blue") set_light(l_range = 2, l_power = 0.5, l_color = "#1024A9") - if("red") set_light(l_range = 4, l_power = 2, l_color = COLOR_RED) - if("delta") set_light(l_range = 4, l_power = 2, l_color = "#FF6633") + if("green") + previous_state = icon_state + set_light(l_range = L_WALLMOUNT_RANGE, l_power = L_WALLMOUNT_POWER, l_color = COLOR_LIME) + if("blue") + previous_state = icon_state + set_light(l_range = L_WALLMOUNT_RANGE, l_power = L_WALLMOUNT_POWER, l_color = "#1024A9") + if("red") + previous_state = icon_state + set_light(l_range = L_WALLMOUNT_HI_RANGE, l_power = L_WALLMOUNT_HI_POWER, l_color = COLOR_RED) + if("delta") + previous_state = icon_state + set_light(l_range = L_WALLMOUNT_HI_RANGE, l_power = L_WALLMOUNT_HI_POWER, l_color = "#FF6633") src.overlays += image('icons/obj/monitors.dmi', "overlay_[seclevel]") @@ -74,11 +83,14 @@ src.add_fingerprint(user) if (istype(W, /obj/item/weapon/screwdriver) && buildstage == 2) + if(!wiresexposed) + set_light(0) wiresexposed = !wiresexposed update_icon() return if(wiresexposed) + set_light(0) switch(buildstage) if(2) if (istype(W, /obj/item/device/multitool)) @@ -129,11 +141,18 @@ return /obj/machinery/firealarm/process()//Note: this processing was mostly phased out due to other code, and only runs when needed + var/area/A = get_area(src) + if (A.fire != previous_fire_state) + update_icon() + previous_fire_state = A.fire + + if (stat != previous_state) + update_icon() + previous_state = stat + if(stat & (NOPOWER|BROKEN)) return - update_icon() - if(src.timing) if(src.time > 0) src.time = src.time - ((world.timeofday - last_process)/10) diff --git a/code/game/machinery/kitchen/cooking_machines/_cooker.dm b/code/game/machinery/kitchen/cooking_machines/_cooker.dm index abb57f19109..301d042b34d 100644 --- a/code/game/machinery/kitchen/cooking_machines/_cooker.dm +++ b/code/game/machinery/kitchen/cooking_machines/_cooker.dm @@ -157,7 +157,7 @@ cooking_obj = new /obj/item/weapon/reagent_containers/food/snacks/badrecipe(src) // Produce nasty smoke. visible_message("\The [src] vomits a gout of rancid smoke!") - var/datum/effect/effect/system/smoke_spread/bad/smoke = PoolOrNew(/datum/effect/effect/system/smoke_spread/bad) + var/datum/effect/effect/system/smoke_spread/bad/smoke = getFromPool(/datum/effect/effect/system/smoke_spread/bad) smoke.attach(src) smoke.set_up(10, 0, usr.loc) smoke.start() diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index ffad72d08ac..f6db5cfb41d 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -147,7 +147,7 @@ Class Procs: if(use_power && stat == 0) use_power(7500/severity) - var/obj/effect/overlay/pulse2 = PoolOrNew(/obj/effect/overlay, src.loc) + var/obj/effect/overlay/pulse2 = getFromPool(/obj/effect/overlay, src.loc) pulse2.icon = 'icons/effects/effects.dmi' pulse2.icon_state = "empdisable" pulse2.name = "emp sparks" diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index cd267c59376..29117efb936 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -544,7 +544,7 @@ var/list/turret_icons set_raised_raising(raised, 1) update_icon() - var/atom/flick_holder = PoolOrNew(/atom/movable/porta_turret_cover, loc) + var/atom/flick_holder = getFromPool(/atom/movable/porta_turret_cover, loc) flick_holder.layer = layer + 0.1 flick("popup", flick_holder) sleep(10) @@ -564,7 +564,7 @@ var/list/turret_icons set_raised_raising(raised, 1) update_icon() - var/atom/flick_holder = PoolOrNew(/atom/movable/porta_turret_cover, loc) + var/atom/flick_holder = getFromPool(/atom/movable/porta_turret_cover, loc) flick_holder.layer = layer + 0.1 flick("popdown", flick_holder) sleep(10) diff --git a/code/game/magic/archived_book.dm b/code/game/magic/archived_book.dm deleted file mode 100644 index 61967933f64..00000000000 --- a/code/game/magic/archived_book.dm +++ /dev/null @@ -1,126 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 29/05/2012 15:03:04 - -#define BOOK_VERSION_MIN 1 -#define BOOK_VERSION_MAX 2 -#define BOOK_PATH "data/books/" -#define BOOKS_USE_SQL 0 // no guarentee for this branch to work right with sql - -var/global/datum/book_manager/book_mgr = new() - -datum/book_manager/proc/path(id) - if(isnum(id)) // kill any path exploits - return "[BOOK_PATH][id].sav" - -datum/book_manager/proc/getall() - var/list/paths = flist(BOOK_PATH) - var/list/books = new() - - for(var/path in paths) - var/datum/archived_book/B = new(BOOK_PATH + path) - books += B - - return books - -datum/book_manager/proc/freeid() - var/list/paths = flist(BOOK_PATH) - var/id = paths.len + 101 - - // start at 101+number of books, which will be correct id if none have been deleted, etc - // otherwise, keep moving forward until we find an open id - while(fexists(path(id))) - id++ - - return id - -/client/proc/delbook() - set name = "Delete Book" - set desc = "Permamently deletes a book from the database." - set category = "Admin" - if(!src.holder) - src << "Only administrators may use this command." - return - - var/isbn = input("ISBN number?", "Delete Book") as num | null - if(!isbn) - return - - if(BOOKS_USE_SQL && config.sql_enabled) - var/DBConnection/dbcon = new() - dbcon.Connect("dbi:mysql:[sqldb]:[sqladdress]:[sqlport]","[sqllogin]","[sqlpass]") - if(!dbcon.IsConnected()) - alert("Connection to Archive has been severed. Aborting.") - else - var/DBQuery/query = dbcon.NewQuery("DELETE FROM ss13_library WHERE id=[isbn]") - if(!query.Execute()) - usr << query.ErrorMsg() - dbcon.Disconnect() - else - book_mgr.remove(isbn) - log_admin("[usr.key] has deleted the book [isbn]") - -// delete a book -datum/book_manager/proc/remove(var/id) - fdel(path(id)) - -datum/archived_book - var/author // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned - var/title // The real name of the book. - var/category // The category/genre of the book - var/id // the id of the book (like an isbn number) - var/dat // Actual page content - - var/author_real // author's real_name - var/author_key // author's byond key - var/list/icon/photos // in-game photos used - -// loads the book corresponding by the specified id -datum/archived_book/New(var/path) - if(isnull(path)) - return - - var/savefile/F = new(path) - - var/version - F["version"] >> version - - if (isnull(version) || version < BOOK_VERSION_MIN || version > BOOK_VERSION_MAX) - fdel(path) - usr << "What book?" - return 0 - - F["author"] >> author - F["title"] >> title - F["category"] >> category - F["id"] >> id - F["dat"] >> dat - - F["author_real"] >> author_real - F["author_key"] >> author_key - F["photos"] >> photos - if(!photos) - photos = new() - - // let's sanitize it here too! - for(var/tag in paper_blacklist) - if(findtext(dat,"<"+tag)) - dat = "" - return - - -datum/archived_book/proc/save() - var/savefile/F = new(book_mgr.path(id)) - - F["version"] << BOOK_VERSION_MAX - F["author"] << author - F["title"] << title - F["category"] << category - F["id"] << id - F["dat"] << dat - - F["author_real"] << author_real - F["author_key"] << author_key - F["photos"] << photos - -#undef BOOK_VERSION_MIN -#undef BOOK_VERSION_MAX -#undef BOOK_PATH diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index 6a3decc5cf5..9e0d8e7bfbb 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -221,7 +221,7 @@ for(var/a = 1 to 5) spawn(0) - var/obj/effect/effect/water/W = PoolOrNew(/obj/effect/effect/water, get_turf(chassis)) + var/obj/effect/effect/water/W = getFromPool(/obj/effect/effect/water, get_turf(chassis)) var/turf/my_target if(a == 1) my_target = T diff --git a/code/game/objects/effects/chem/chemsmoke.dm b/code/game/objects/effects/chem/chemsmoke.dm index ba337f9d11d..1e06328564c 100644 --- a/code/game/objects/effects/chem/chemsmoke.dm +++ b/code/game/objects/effects/chem/chemsmoke.dm @@ -26,7 +26,7 @@ //switching opacity on after the smoke has spawned, and then turning it off before it is deleted results in cleaner //lighting and view range updates (Is this still true with the new lighting system?) - opacity = 1 + set_opacity(1) //float over to our destination, if we have one destination = dest_turf @@ -34,7 +34,7 @@ walk_to(src, destination) /obj/effect/effect/smoke/chem/Destroy() - opacity = 0 + set_opacity(0) fadeOut() ..() @@ -250,7 +250,7 @@ if(passed_smoke) smoke = passed_smoke else - smoke = PoolOrNew(/obj/effect/effect/smoke/chem, list(location, smoke_duration + rand(smoke_duration*-0.25, smoke_duration*0.25), T, I)) + smoke = getFromPool(/obj/effect/effect/smoke/chem, list(location, smoke_duration + rand(smoke_duration*-0.25, smoke_duration*0.25), T, I)) if(chemholder.reagents.reagent_list.len) chemholder.reagents.trans_to_obj(smoke, chemholder.reagents.total_volume / dist, copy = 1) //copy reagents to the smoke so mob/breathe() can handle inhaling the reagents @@ -261,7 +261,7 @@ /datum/effect/effect/system/smoke_spread/chem/spores/spawnSmoke(var/turf/T, var/smoke_duration, var/icon/I, var/dist = 1) - var/obj/effect/effect/smoke/chem/spores = PoolOrNew(/obj/effect/effect/smoke/chem, location) + var/obj/effect/effect/smoke/chem/spores = getFromPool(/obj/effect/effect/smoke/chem, location) spores.name = "cloud of [seed.seed_name] [seed.seed_noun]" ..(T, I, smoke_duration, dist, spores) diff --git a/code/game/objects/effects/chem/foam.dm b/code/game/objects/effects/chem/foam.dm index b29b2440e6c..73ea7cf3c67 100644 --- a/code/game/objects/effects/chem/foam.dm +++ b/code/game/objects/effects/chem/foam.dm @@ -108,7 +108,7 @@ F.amount += amount return - F = PoolOrNew(/obj/effect/effect/foam, list(location, metal)) + F = getFromPool(/obj/effect/effect/foam, list(location, metal)) F.amount = amount if(!metal) // don't carry other chemicals if a metal foam diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 73de783335b..bd47bea6939 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -221,7 +221,7 @@ var/global/list/image/splatter_cache=list() for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) sleep(3) if (i > 0) - var/obj/effect/decal/cleanable/blood/b = PoolOrNew(/obj/effect/decal/cleanable/blood/splatter, src.loc) + var/obj/effect/decal/cleanable/blood/b = getFromPool(/obj/effect/decal/cleanable/blood/splatter, src.loc) b.basecolor = src.basecolor b.update_icon() for(var/datum/disease/D in src.viruses) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index dd18df9296f..41186d9a939 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -75,7 +75,7 @@ steam.start() -- spawns the effect spawn(0) if(holder) src.location = get_turf(holder) - var/obj/effect/effect/steam/steam = PoolOrNew(/obj/effect/effect/steam, src.location) + var/obj/effect/effect/steam/steam = getFromPool(/obj/effect/effect/steam, src.location) var/direction if(src.cardinals) direction = pick(cardinal) @@ -146,7 +146,7 @@ steam.start() -- spawns the effect spawn(0) if(holder) src.location = get_turf(holder) - var/obj/effect/sparks/sparks = PoolOrNew(/obj/effect/sparks, src.location) + var/obj/effect/sparks/sparks = getFromPool(/obj/effect/sparks, src.location) src.total_sparks++ var/direction if(src.cardinals) @@ -331,7 +331,7 @@ steam.start() -- spawns the effect spawn(0) if(holder) src.location = get_turf(holder) - var/obj/effect/effect/smoke/smoke = PoolOrNew(smoke_type, src.location) + var/obj/effect/effect/smoke/smoke = getFromPool(smoke_type, src.location) src.total_smoke++ var/direction = src.direction if(!direction) @@ -389,7 +389,7 @@ steam.start() -- spawns the effect var/turf/T = get_turf(src.holder) if(T != src.oldposition) if(istype(T, /turf/space)) - var/obj/effect/effect/ion_trails/I = PoolOrNew(/obj/effect/effect/ion_trails, src.oldposition) + var/obj/effect/effect/ion_trails/I = getFromPool(/obj/effect/effect/ion_trails, src.oldposition) src.oldposition = T I.set_dir(src.holder.dir) flick("ion_fade", I) @@ -435,7 +435,7 @@ steam.start() -- spawns the effect src.processing = 0 spawn(0) if(src.number < 3) - var/obj/effect/effect/steam/I = PoolOrNew(/obj/effect/effect/steam, src.oldposition) + var/obj/effect/effect/steam/I = getFromPool(/obj/effect/effect/steam, src.oldposition) src.number++ src.oldposition = get_turf(holder) I.set_dir(src.holder.dir) @@ -475,7 +475,7 @@ steam.start() -- spawns the effect start() if (amount <= 2) - var/datum/effect/effect/system/spark_spread/s = PoolOrNew(/datum/effect/effect/system/spark_spread) + var/datum/effect/effect/system/spark_spread/s = getFromPool(/datum/effect/effect/system/spark_spread) s.set_up(2, 1, location) s.start() diff --git a/code/game/objects/effects/gibs.dm b/code/game/objects/effects/gibs.dm index 696d3aa0fa6..8d98b615eae 100644 --- a/code/game/objects/effects/gibs.dm +++ b/code/game/objects/effects/gibs.dm @@ -28,7 +28,7 @@ qdel(D) if(sparks) - var/datum/effect/effect/system/spark_spread/s = PoolOrNew(/datum/effect/effect/system/spark_spread) + var/datum/effect/effect/system/spark_spread/s = getFromPool(/datum/effect/effect/system/spark_spread) s.set_up(2, 1, get_turf(location)) // Not sure if it's safe to pass an arbitrary object to set_up, todo s.start() diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 27e6d7c74a2..a78417696e5 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -26,7 +26,7 @@ call(src,triggerproc)(M) /obj/effect/mine/proc/triggerrad(obj) - var/datum/effect/effect/system/spark_spread/s = PoolOrNew(/datum/effect/effect/system/spark_spread) + var/datum/effect/effect/system/spark_spread/s = getFromPool(/datum/effect/effect/system/spark_spread) s.set_up(3, 1, src) s.start() obj:radiation += 50 @@ -39,7 +39,7 @@ if(ismob(obj)) var/mob/M = obj M.Stun(30) - var/datum/effect/effect/system/spark_spread/s = PoolOrNew(/datum/effect/effect/system/spark_spread) + var/datum/effect/effect/system/spark_spread/s = getFromPool(/datum/effect/effect/system/spark_spread) s.set_up(3, 1, src) s.start() spawn(0) @@ -67,7 +67,7 @@ qdel(src) /obj/effect/mine/proc/triggerkick(obj) - var/datum/effect/effect/system/spark_spread/s = PoolOrNew(/datum/effect/effect/system/spark_spread) + var/datum/effect/effect/system/spark_spread/s = getFromPool(/datum/effect/effect/system/spark_spread) s.set_up(3, 1, src) s.start() qdel(obj:client) diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index bf176a2b354..5265e05531a 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -101,7 +101,7 @@ O = loc for(var/i=0, i[src] dies!") - PoolOrNew(/obj/effect/decal/cleanable/spiderling_remains, src.loc) + getFromPool(/obj/effect/decal/cleanable/spiderling_remains, src.loc) qdel(src) /obj/effect/spider/spiderling/healthcheck() diff --git a/code/game/objects/empulse.dm b/code/game/objects/empulse.dm index c1df6b5454b..ad666f88637 100644 --- a/code/game/objects/empulse.dm +++ b/code/game/objects/empulse.dm @@ -15,7 +15,7 @@ proc/empulse(turf/epicenter, heavy_range, light_range, log=0) log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ") if(heavy_range > 1) - var/obj/effect/overlay/pulse = PoolOrNew(/obj/effect/overlay, epicenter) + var/obj/effect/overlay/pulse = getFromPool(/obj/effect/overlay, epicenter) pulse.icon = 'icons/effects/effects.dmi' pulse.icon_state = "emppulse" pulse.name = "emp pulse" diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 3733bec1546..62b7ace7012 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -12,8 +12,8 @@ var/global/list/obj/item/device/pda/PDAs = list() w_class = 2.0 slot_flags = SLOT_ID | SLOT_BELT sprite_sheets = list("Resomi" = 'icons/mob/species/resomi/id.dmi') - offset_light = 1 - diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona + //offset_light = 1 + //diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona //Main variables var/owner = null @@ -49,6 +49,7 @@ var/global/list/obj/item/device/pda/PDAs = list() var/list/conversations = list() // For keeping up with who we have PDA messsages from. var/new_message = 0 //To remove hackish overlay check var/new_news = 0 + var/pdafilter = 0 //0-all,1-synth,2-command,3-sec,4-eng,5-sci,6-cargo,7-service,8-med var/active_feed // The selected feed var/list/warrant // The warrant as we last knew it @@ -440,12 +441,39 @@ var/global/list/obj/item/device/pda/PDAs = list() if(conversations.Find("\ref[P]")) convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1"))) else - pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + switch(pdafilter) + if(0) //All + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(1) //Synth -- Not working + if(P == /obj/item/device/pda/ai) + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(2) //Command + if(P.icon_state == "pda-hop"||P.icon_state == "pda-hos"||P.icon_state == "pda-ce"||P.icon_state == "pda-cmo"||P.icon_state == "pda-rd"||P.icon_state == "pda-c"||P.icon_state == "pda-h") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(3) //sec + if(P.icon_state == "pda-hos"||P.icon_state == "pda-warden"||P.icon_state == "pda-det"||P.icon_state == "pda-sec"||P.icon_state == "pda-s") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(4) //eng + if(P.icon_state == "pda-ce"||P.icon_state == "pda-e"||P.icon_state == "pda-atmo") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(5) //sci + if(P.icon_state == "pda-rd"||P.icon_state == "pda-tox"||P.icon_state == "pda-v"||P.icon_state == "pda-robot") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(6) //cargo + if(P.icon_state == "pda-hop"||P.icon_state == "pda-cargo"||P.icon_state == "pda-q"||P.icon_state == "pda-miner") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(7) //service + if(P.icon_state == "pda-hop"||P.icon_state == "pda-j"||P.icon_state == "pda-bar"||P.icon_state == "pda-holy"||P.icon_state == "pda-lawyer"||P.icon_state == "pda-libb"||P.icon_state == "pda-hydro"||P.icon_state == "pda-chef") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) + if(8) //medical + if(P.icon_state == "pda-cmo"||P.icon_state == "pda-v"||P.icon_state == "pda-m"||P.icon_state == "pda-chem") + pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0"))) count++ data["convopdas"] = convopdas data["pdas"] = pdas data["pda_count"] = count + data["pdafilter"] = pdafilter if(mode==21) data["messagescount"] = tnote.len @@ -702,7 +730,12 @@ var/global/list/obj/item/device/pda/PDAs = list() active_conversation = null if(mode==21) mode=2 - + + + if("Filter") // Filters through available pdas + if (href_list["option"]) + pdafilter = sanitize_integer(text2num(href_list["option"]), 0, 8, pdafilter) + if("Ringtone") var/t = input(U, "Please enter new ringtone", name, ttone) as text|null if (in_range(src, U) && loc == U) diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index 5b694e19184..0bdfa6af1b8 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -46,7 +46,7 @@ qdel(active_dummy) active_dummy = null usr << "You deactivate the [src]." - var/obj/effect/overlay/T = PoolOrNew(/obj/effect/overlay, get_turf(src)) + var/obj/effect/overlay/T = getFromPool(/obj/effect/overlay, get_turf(src)) T.icon = 'icons/effects/effects.dmi' flick("emppulse",T) spawn(8) qdel(T) @@ -54,7 +54,7 @@ playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6) var/obj/O = new saved_item(src) if(!O) return - var/obj/effect/dummy/chameleon/C = PoolOrNew(/obj/effect/dummy/chameleon, usr.loc) + var/obj/effect/dummy/chameleon/C = getFromPool(/obj/effect/dummy/chameleon, usr.loc) C.activate(O, usr, saved_icon, saved_icon_state, saved_overlays, src) qdel(O) usr << "You activate the [src]." diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm index 90e5dc40224..a7270b39c22 100644 --- a/code/game/objects/items/devices/flash.dm +++ b/code/game/objects/items/devices/flash.dm @@ -86,7 +86,7 @@ var/obj/item/organ/eyes/E = H.internal_organs_by_name["eyes"] if(!E) return - usr << "\red Your eyes burn with the intense light of the flash!." + usr << span("alert", "Your eyes burn with the intense light of the flash!.") E.damage += rand(10, 11) if(E.damage > 12) M.eye_blurry += rand(3,6) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index a45cf6fe92b..bda57dd9cff 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -7,14 +7,15 @@ w_class = 2 flags = CONDUCT slot_flags = SLOT_BELT - offset_light = 1 - diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona + light_color = LIGHT_COLOR_HALOGEN + //offset_light = 1 + //diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) action_button_name = "Toggle Flashlight" var/on = 0 - var/brightness_on = 4 //luminosity when on + var/brightness_on = 3 //luminosity when on /obj/item/device/flashlight/initialize() ..() @@ -23,10 +24,10 @@ /obj/item/device/flashlight/update_icon() if(on) icon_state = "[initial(icon_state)]-on" - set_light(brightness_on) + set_light(brightness_on, update_type = UPDATE_NOW) else icon_state = "[initial(icon_state)]" - set_light(0) + set_light(0, update_type = UPDATE_NOW) /obj/item/device/flashlight/attack_self(mob/user) if(!isturf(user.loc)) @@ -110,7 +111,7 @@ desc = "A high-luminosity flashlight for specialist duties." icon_state = "heavyflashlight" item_state = "heavyflashlight" - brightness_on = 7 + brightness_on = 4 w_class = 3 matter = list(DEFAULT_WALL_MATERIAL = 100,"glass" = 70) contained_sprite = 1 @@ -166,15 +167,15 @@ w_class = 2.0 brightness_on = 8 // Pretty bright. light_power = 3 - light_color = "#e58775" + light_color = LIGHT_COLOR_FLARE icon_state = "flare" item_state = "flare" action_button_name = null //just pull it manually, neckbeard. var/fuel = 0 var/on_damage = 7 var/produce_heat = 1500 - offset_light = 0//Emits light all around, not directional - diona_restricted_light = 0 + //offset_light = 0//Emits light all around, not directional + //diona_restricted_light = 0 /obj/item/device/flashlight/flare/New() fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds. @@ -224,12 +225,13 @@ w_class = 1 brightness_on = 6 on = 1 //Bio-luminesence has one setting, on. - offset_light = 0//Emits light all around, not directional - diona_restricted_light = 0 + light_color = LIGHT_COLOR_SLIME_LAMP + //offset_light = 0//Emits light all around, not directional + //diona_restricted_light = 0 /obj/item/device/flashlight/slime/New() ..() - set_light(brightness_on) + set_light(brightness_on, update_type = UPDATE_NOW) /obj/item/device/flashlight/slime/update_icon() return @@ -243,15 +245,15 @@ name = "green glowstick" desc = "A green military-grade glowstick." w_class = 2 - brightness_on = 3 - light_power = 2 + brightness_on = 1.5 + light_power = 1 light_color = "#49F37C" icon = 'icons/obj/glowsticks.dmi' icon_state = "glowstick" item_state = "glowstick" contained_sprite = 1 - offset_light = 0 - diona_restricted_light = 0 + //offset_light = 0 + //diona_restricted_light = 0 var/fuel = 0 /obj/item/device/flashlight/glowstick/New() @@ -296,27 +298,27 @@ /obj/item/device/flashlight/glowstick/red name = "red glowstick" desc = "A red military-grade glowstick." - light_color = "#FC0F29" + light_color = LIGHT_COLOR_RED //"#FC0F29" icon_state = "glowstick_red" item_state = "glowstick_red" /obj/item/device/flashlight/glowstick/blue name = "blue glowstick" desc = "A blue military-grade glowstick." - light_color = "#599DFF" + light_color = LIGHT_COLOR_BLUE //"#599DFF" icon_state = "glowstick_blue" item_state = "glowstick_blue" /obj/item/device/flashlight/glowstick/orange name = "orange glowstick" desc = "A orange military-grade glowstick." - light_color = "#FA7C0B" + light_color = LIGHT_COLOR_ORANGE//"#FA7C0B" icon_state = "glowstick_orange" item_state = "glowstick_orange" /obj/item/device/flashlight/glowstick/yellow name = "yellow glowstick" desc = "A yellow military-grade glowstick." - light_color = "#FEF923" + light_color = LIGHT_COLOR_YELLOW //"#FEF923" icon_state = "glowstick_yellow" item_state = "glowstick_yellow" diff --git a/code/game/objects/items/devices/lightmeter.dm b/code/game/objects/items/devices/lightmeter.dm new file mode 100644 index 00000000000..0807bcd5bf8 --- /dev/null +++ b/code/game/objects/items/devices/lightmeter.dm @@ -0,0 +1,55 @@ +// Light meter, intended for debugging. + +/obj/item/device/light_meter + name = "light meter" + desc = "A simple device that measures ambient light levels." + icon = 'icons/obj/device.dmi' + icon_state = "locator" + + // Copied from debugger.dm + flags = CONDUCT + force = 5.0 + w_class = 2.0 + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + var/low = 0 + var/high = 1 + +/obj/item/device/light_meter/attack_self(mob/user as mob) + var/turf/T = get_turf(user.loc) + if (!T) + user << span("alert", "Unable to read light levels.") + return + + var/visible_reading = T.get_lumcount(low, high) + var/uv_reading = T.get_uv_lumcount(low, high) + + var/reading = "Light analysis for \the [T].
" + reading += "Visible light: [visible_reading] lx
" + reading += "Ultraviolet light: [uv_reading] lx ([uv_reading * 5.5 - 1.5] adlx)" + + usr << span("notice", reading) + +/obj/item/device/light_meter/verb/set_low_bound() + set category = "Object" + set name = "Set Detector Low-Bound" + set src in usr + + var/num = input(usr, "Please enter the low-bound for the detector") as num|null + if (null) + return + + low = num + +/obj/item/device/light_meter/verb/set_high_bound() + set category = "Object" + set name = "Set Detector High-Bound" + set src in usr + + var/num = input(usr, "Please enter the high-bound for the detector") as num|null + if (null) + return + + high = num diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index 5be1c321a9f..4cdf35254d0 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -116,7 +116,7 @@ spawn(0) if(!src || !reagents.total_volume) return - var/obj/effect/effect/water/W = PoolOrNew(/obj/effect/effect/water, get_turf(src)) + var/obj/effect/effect/water/W = getFromPool(/obj/effect/effect/water, get_turf(src)) var/turf/my_target if(a <= the_targets.len) my_target = the_targets[a] diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index bbdd46cdb39..731c2e34602 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -82,7 +82,7 @@ if(ptank) ptank.loc = T ptank = null - PoolOrNew(/obj/item/stack/rods, T) + getFromPool(/obj/item/stack/rods, T) qdel(src) return diff --git a/code/game/objects/items/weapons/grenades/smokebomb.dm b/code/game/objects/items/weapons/grenades/smokebomb.dm index 704df83db8a..f354cb607f1 100644 --- a/code/game/objects/items/weapons/grenades/smokebomb.dm +++ b/code/game/objects/items/weapons/grenades/smokebomb.dm @@ -10,7 +10,7 @@ /obj/item/weapon/grenade/smokebomb/New() ..() - src.smoke = PoolOrNew(/datum/effect/effect/system/smoke_spread/bad) + src.smoke = getFromPool(/datum/effect/effect/system/smoke_spread/bad) src.smoke.attach(src) /obj/item/weapon/grenade/smokebomb/Destroy() diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 2d56c460a1d..4e9be5f1673 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -111,7 +111,7 @@ . = ..() if(.) - var/datum/effect/effect/system/spark_spread/spark_system = PoolOrNew(/datum/effect/effect/system/spark_spread) + var/datum/effect/effect/system/spark_spread/spark_system = getFromPool(/datum/effect/effect/system/spark_spread) spark_system.set_up(5, 0, user.loc) spark_system.start() playsound(user.loc, 'sound/weapons/blade1.ogg', 50, 1) diff --git a/code/game/objects/items/weapons/storage/toolbox.dm b/code/game/objects/items/weapons/storage/toolbox.dm index 09ddfaea85b..0265f40d5ea 100644 --- a/code/game/objects/items/weapons/storage/toolbox.dm +++ b/code/game/objects/items/weapons/storage/toolbox.dm @@ -105,3 +105,80 @@ update_force() user.visible_message(span("danger", "[user] smashes the [src] into [M], causing it to break open and strew its contents across the area")) + +/obj/item/weapon/storage/toolbox/lunchbox + name = "rainbow lunchbox" + icon = 'icons/obj/lunchbox.dmi' + force = 3 + throwforce = 5 + contained_sprite = 1 + icon_state = "lunchbox_rainbow" + item_state = "lunchbox_rainbow" + desc = "A little lunchbox. This one is the colors of the rainbow." + attack_verb = list("lunched") + w_class = 3 + max_storage_space = 8 + var/filled = FALSE + +/obj/item/weapon/storage/toolbox/lunchbox/New() + ..() + if(filled) + var/list/lunches = lunchables_lunches() + var/lunch = lunches[pick(lunches)] + new lunch(src) + + var/list/snacks = lunchables_snacks() + var/snack = snacks[pick(snacks)] + new snack(src) + + var/list/drinks = lunchables_drinks() + var/drink = drinks[pick(drinks)] + new drink(src) + +/obj/item/weapon/storage/toolbox/lunchbox/filled + filled = TRUE + +/obj/item/weapon/storage/toolbox/lunchbox/heart + name = "heart lunchbox" + icon_state = "lunchbox_hearts" + item_state = "lunchbox_hearts" + desc = "A little lunchbox. This one has little hearts on it." + +/obj/item/weapon/storage/toolbox/lunchbox/heart/filled + filled = TRUE + +/obj/item/weapon/storage/toolbox/lunchbox/cat + name = "cat lunchbox" + icon_state = "lunchbox_cat" + item_state = "lunchbox_cat" + desc = "A little lunchbox. This one has a cat stamp on it." + +/obj/item/weapon/storage/toolbox/lunchbox/cat/filled + filled = TRUE + +/obj/item/weapon/storage/toolbox/lunchbox/nt + name = "NanoTrasen brand lunchbox" + icon_state = "lunchbox_nanotrasen" + item_state = "lunchbox_nanotrasen" + desc = "A little lunchbox. This one is branded with the NanoTrasen logo." + +/obj/item/weapon/storage/toolbox/lunchbox/nt/filled + filled = TRUE + +/obj/item/weapon/storage/toolbox/lunchbox/nymph + name = "\improper diona nymph lunchbox" + icon_state = "lunchbox_dionanymph" + item_state = "lunchbox_dionanymph" + desc = "A little lunchbox. This one has a diona nymph on the side." + +/obj/item/weapon/storage/toolbox/lunchbox/nymph/filled + filled = TRUE + +/obj/item/weapon/storage/toolbox/lunchbox/syndicate + name = "black and red lunchbox" + icon_state = "lunchbox_syndie" + item_state = "lunchbox_syndie" + desc = "A little lunchbox. This one is a sleek black and red." + +/obj/item/weapon/storage/toolbox/lunchbox/syndicate/filled + filled = TRUE diff --git a/code/game/objects/structures/curtains.dm b/code/game/objects/structures/curtains.dm index f8e8a0a414b..bba9fb776e9 100644 --- a/code/game/objects/structures/curtains.dm +++ b/code/game/objects/structures/curtains.dm @@ -27,7 +27,7 @@ ..() /obj/structure/curtain/proc/toggle() - opacity = !opacity + src.set_opacity(!src.opacity) if(opacity) icon_state = "closed" layer = SHOWER_CLOSED_LAYER diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index dcf500d1541..4d9e4ec5526 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -96,7 +96,7 @@ if(iswirecutter(W)) if(!shock(user, 100)) playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1) - PoolOrNew(/obj/item/stack/rods, list(get_turf(src), destroyed ? 1 : 2)) + getFromPool(/obj/item/stack/rods, list(get_turf(src), destroyed ? 1 : 2)) qdel(src) else if((isscrewdriver(W)) && (istype(loc, /turf/simulated) || anchored)) if(!shock(user, 90)) @@ -151,7 +151,7 @@ else if(!(W.flags & CONDUCT) || !shock(user, 70)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - user.do_attack_animation(src) + user.do_attack_animation(src) playsound(loc, 'sound/effects/grillehit.ogg', 80, 1) switch(W.damtype) if("fire") @@ -169,11 +169,11 @@ density = 0 destroyed = 1 update_icon() - PoolOrNew(/obj/item/stack/rods, get_turf(src)) + getFromPool(/obj/item/stack/rods, get_turf(src)) else if(health <= -6) - PoolOrNew(/obj/item/stack/rods, get_turf(src)) + getFromPool(/obj/item/stack/rods, get_turf(src)) qdel(src) return return diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 3ead5503314..4c31a8530fb 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -58,7 +58,7 @@ var/obj/item/weapon/weldingtool/WT = C if(WT.remove_fuel(0, user)) user << "Slicing lattice joints ..." - PoolOrNew(/obj/item/stack/rods, src.loc) + getFromPool(/obj/item/stack/rods, src.loc) qdel(src) return diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index 3245234fc3e..1742cd09b0f 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -180,13 +180,13 @@ spawn(50) if(src && on) ismist = 1 - mymist = PoolOrNew(/obj/effect/mist,loc) + mymist = getFromPool(/obj/effect/mist,loc) else ismist = 1 - mymist = PoolOrNew(/obj/effect/mist,loc) + mymist = getFromPool(/obj/effect/mist,loc) else if(ismist) ismist = 1 - mymist = PoolOrNew(/obj/effect/mist,loc) + mymist = getFromPool(/obj/effect/mist,loc) spawn(250) if(src && !on) qdel(mymist) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index fb48f6249dd..dbf92c1b11c 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -79,7 +79,7 @@ obj/structure/windoor_assembly/Destroy() user << "You dissasembled the windoor assembly!" new /obj/item/stack/material/glass/reinforced(get_turf(src), 5) if(secure) - PoolOrNew(/obj/item/stack/rods, list(get_turf(src), 4)) + getFromPool(/obj/item/stack/rods, list(get_turf(src), 4)) qdel(src) else user << "You need more welding fuel to dissassemble the windoor assembly." diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index f93fb39ce59..262e9414378 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -91,11 +91,11 @@ index = 0 while(index < 2) new shardtype(loc) //todo pooling? - if(reinf) PoolOrNew(/obj/item/stack/rods, loc) + if(reinf) getFromPool(/obj/item/stack/rods, loc) index++ else new shardtype(loc) //todo pooling? - if(reinf) PoolOrNew(/obj/item/stack/rods, loc) + if(reinf) getFromPool(/obj/item/stack/rods, loc) qdel(src) return diff --git a/code/game/objects/structures/window_spawner.dm b/code/game/objects/structures/window_spawner.dm index c6e2d69f842..a1cec9eb55c 100644 --- a/code/game/objects/structures/window_spawner.dm +++ b/code/game/objects/structures/window_spawner.dm @@ -35,7 +35,7 @@ /obj/effect/wingrille_spawn/proc/activate() if(activated) return if (!locate(/obj/structure/grille) in get_turf(src)) - var/obj/structure/grille/G = PoolOrNew(/obj/structure/grille, src.loc) + var/obj/structure/grille/G = getFromPool(/obj/structure/grille, src.loc) handle_grille_spawn(G) var/list/neighbours = list() for (var/dir in cardinal) @@ -49,7 +49,7 @@ found_connection = 1 qdel(W) if(!found_connection) - var/obj/structure/window/new_win = PoolOrNew(win_path, src.loc) + var/obj/structure/window/new_win = getFromPool(win_path, src.loc) new_win.set_dir(dir) handle_window_spawn(new_win) else diff --git a/code/game/turfs/initialization/maintenance.dm b/code/game/turfs/initialization/maintenance.dm index 16b1d03d21e..833c0cd68dc 100644 --- a/code/game/turfs/initialization/maintenance.dm +++ b/code/game/turfs/initialization/maintenance.dm @@ -15,9 +15,9 @@ T.update_dirt() if(prob(2)) - PoolOrNew(junk(), T) + getFromPool(junk(), T) if(prob(2)) - PoolOrNew(/obj/effect/decal/cleanable/blood/oil, T) + getFromPool(/obj/effect/decal/cleanable/blood/oil, T) if(prob(25)) // Keep in mind that only "corners" get any sort of web attempt_web(T, cardinal_turfs) @@ -54,7 +54,7 @@ var/global/list/random_junk var/turf/neighbour = get_step(T, dir) if(neighbour && neighbour.density) if(dir == WEST) - PoolOrNew(/obj/effect/decal/cleanable/cobweb, T) + getFromPool(/obj/effect/decal/cleanable/cobweb, T) if(dir == EAST) - PoolOrNew(/obj/effect/decal/cleanable/cobweb2, T) + getFromPool(/obj/effect/decal/cleanable/cobweb2, T) return diff --git a/code/game/turfs/simulated/wall_attacks.dm b/code/game/turfs/simulated/wall_attacks.dm index 9264b1a0afd..fee8eeb96d2 100644 --- a/code/game/turfs/simulated/wall_attacks.dm +++ b/code/game/turfs/simulated/wall_attacks.dm @@ -9,14 +9,14 @@ //flick("[material.icon_base]fwall_opening", src) sleep(15) density = 0 - opacity = 0 + set_opacity(0) update_icon() set_light(0) else can_open = WALL_OPENING //flick("[material.icon_base]fwall_closing", src) density = 1 - opacity = 1 + set_opacity(1) update_icon() sleep(15) set_light(1) diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm index 76be9e556ec..9031d62a856 100644 --- a/code/game/turfs/space/space.dm +++ b/code/game/turfs/space/space.dm @@ -1,17 +1,24 @@ /turf/space icon = 'icons/turf/space.dmi' name = "\proper space" + desc = "The final frontier." icon_state = "0" dynamic_lighting = 0 footstep_sound = null //Override to make sure because yeah + plane = PLANE_SPACE_BACKGROUND + temperature = T20C thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT // heat_capacity = 700000 No. /turf/space/New() - if(!istype(src, /turf/space/transit)) - icon_state = "[((x + y) ^ ~(x * y) + z) % 25]" + icon_state = "[((x + y) ^ ~(x * y) + z) % 25]" + var/image/I = image('icons/turf/space_parallax1.dmi',"[icon_state]") + I.plane = PLANE_SPACE_DUST + I.alpha = 80 + I.blend_mode = BLEND_ADD + overlays += I update_starlight() ..() diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index d84b33dbfe9..ec46a81207d 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -1,77 +1,100 @@ /turf/space/transit var/pushdirection // push things that get caught in the transit tile this direction + plane = 0 + +/turf/space/transit/New() + update_icon() + +/turf/space/transit/update_icon() + icon_state = "" + + var/dira="" + var/i=0 + switch(pushdirection) + if(SOUTH) // North to south + dira="ns" + i=1+(abs((x^2)-y)%15) // Vary widely across X, but just decrement across Y + + if(NORTH) // South to north I HAVE NO IDEA HOW THIS WORKS I'M SORRY. -Probe + dira="ns" + i=1+(abs((x^2)-y)%15) // Vary widely across X, but just decrement across Y + + if(WEST) // East to west + dira="ew" + i=1+(((y^2)+x)%15) // Vary widely across Y, but just increment across X + + if(EAST) // West to east + dira="ew" + i=1+(((y^2)-x)%15) // Vary widely across Y, but just increment across X + + + /* + if(NORTH) // South to north (SPRITES DO NOT EXIST!) + dira="sn" + i=1+(((x^2)+y)%15) // Vary widely across X, but just increment across Y + + if(EAST) // West to east (SPRITES DO NOT EXIST!) + dira="we" + i=1+(abs((y^2)-x)%15) // Vary widely across X, but just increment across Y + */ + + else + icon_state="black" + if(icon_state != "black") + icon_state = "speedspace_[dira]_[i]" + +/turf/space/transit/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0, var/allow = 0) + return ..(N, tell_universe, 1, allow) //Overwrite because we dont want people building rods in space. /turf/space/transit/attackby(obj/O as obj, mob/user as mob) - return + return 0 /turf/space/transit/north // moving to the north pushdirection = SOUTH // south because the space tile is scrolling south + icon_state="debug-north" - //IF ANYONE KNOWS A MORE EFFICIENT WAY OF MANAGING THESE SPRITES, BE MY GUEST. + // Isn't legacy code fun. + // These are here so I don't have to remap all this shit. shuttlespace_ns1 - icon_state = "speedspace_ns_1" shuttlespace_ns2 - icon_state = "speedspace_ns_2" shuttlespace_ns3 - icon_state = "speedspace_ns_3" shuttlespace_ns4 - icon_state = "speedspace_ns_4" shuttlespace_ns5 - icon_state = "speedspace_ns_5" shuttlespace_ns6 - icon_state = "speedspace_ns_6" shuttlespace_ns7 - icon_state = "speedspace_ns_7" shuttlespace_ns8 - icon_state = "speedspace_ns_8" shuttlespace_ns9 - icon_state = "speedspace_ns_9" shuttlespace_ns10 - icon_state = "speedspace_ns_10" shuttlespace_ns11 - icon_state = "speedspace_ns_11" shuttlespace_ns12 - icon_state = "speedspace_ns_12" shuttlespace_ns13 - icon_state = "speedspace_ns_13" shuttlespace_ns14 - icon_state = "speedspace_ns_14" shuttlespace_ns15 - icon_state = "speedspace_ns_15" + +/turf/space/transit/south // moving to the south + + pushdirection = NORTH + icon_state="debug-south" /turf/space/transit/east // moving to the east pushdirection = WEST + icon_state="debug-east" shuttlespace_ew1 - icon_state = "speedspace_ew_1" shuttlespace_ew2 - icon_state = "speedspace_ew_2" shuttlespace_ew3 - icon_state = "speedspace_ew_3" shuttlespace_ew4 - icon_state = "speedspace_ew_4" shuttlespace_ew5 - icon_state = "speedspace_ew_5" shuttlespace_ew6 - icon_state = "speedspace_ew_6" shuttlespace_ew7 - icon_state = "speedspace_ew_7" shuttlespace_ew8 - icon_state = "speedspace_ew_8" shuttlespace_ew9 - icon_state = "speedspace_ew_9" shuttlespace_ew10 - icon_state = "speedspace_ew_10" shuttlespace_ew11 - icon_state = "speedspace_ew_11" shuttlespace_ew12 - icon_state = "speedspace_ew_12" shuttlespace_ew13 - icon_state = "speedspace_ew_13" shuttlespace_ew14 - icon_state = "speedspace_ew_14" shuttlespace_ew15 - icon_state = "speedspace_ew_15" \ No newline at end of file diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index fd41829d79b..8db23214265 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -21,7 +21,6 @@ var/icon_old = null var/pathweight = 1 // How much does it cost to pathfind over this turf? var/blessed = 0 // Has the turf been blessed? - var/dynamic_lighting = 1 // Does the turf use dynamic lighting? var/footstep_sound = "defaultstep" diff --git a/code/game/turfs/turf_changing.dm b/code/game/turfs/turf_changing.dm index 10ffb3a8cc4..04adf11fb94 100644 --- a/code/game/turfs/turf_changing.dm +++ b/code/game/turfs/turf_changing.dm @@ -25,6 +25,7 @@ var/old_dynamic_lighting = dynamic_lighting var/list/old_affecting_lights = affecting_lights var/old_lighting_overlay = lighting_overlay + var/list/old_corners = corners //world << "Replacing [src.type] with [N]" @@ -78,10 +79,11 @@ lighting_overlay = old_lighting_overlay affecting_lights = old_affecting_lights + corners = old_corners if((old_opacity != opacity) || (dynamic_lighting != old_dynamic_lighting) || force_lighting_update) reconsider_lights() if(dynamic_lighting != old_dynamic_lighting) if(dynamic_lighting) - lighting_build_overlays() + lighting_build_overlay() else - lighting_clear_overlays() \ No newline at end of file + lighting_clear_overlay() diff --git a/code/game/turfs/turf_flick_animations.dm b/code/game/turfs/turf_flick_animations.dm index 94f5fec4c58..fae622460a0 100644 --- a/code/game/turfs/turf_flick_animations.dm +++ b/code/game/turfs/turf_flick_animations.dm @@ -5,7 +5,7 @@ location = get_turf(target) if(location && !target) target = location - var/atom/movable/overlay/animation = PoolOrNew(/atom/movable/overlay, location) + var/atom/movable/overlay/animation = getFromPool(/atom/movable/overlay, location) if(direction) animation.set_dir(direction) animation.icon = a_icon diff --git a/code/game/vehicles/vehicle.dm b/code/game/vehicles/vehicle.dm deleted file mode 100644 index 4088528b35f..00000000000 --- a/code/game/vehicles/vehicle.dm +++ /dev/null @@ -1,190 +0,0 @@ - - -/obj/vehicle - name = "Vehicle" - icon = 'icons/vehicles/vehicles.dmi' - density = 1 - anchored = 1 - unacidable = 1 //To avoid the pilot-deleting shit that came with mechas - layer = MOB_LAYER - //var/can_move = 1 - var/mob/living/carbon/occupant = null - //var/step_in = 10 //make a step in step_in/10 sec. - //var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South. - //var/step_energy_drain = 10 - var/health = 300 //health is health - //var/deflect_chance = 10 //chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. - //the values in this list show how much damage will pass through, not how much will be absorbed. - var/list/damage_absorption = list("brute"=0.8,"fire"=1.2,"bullet"=0.9,"laser"=1,"energy"=1,"bomb"=1) - var/obj/item/weapon/cell/cell //Our power source - var/state = 0 - var/list/log = new - var/last_message = 0 - var/add_req_access = 1 - var/maint_access = 1 - //var/dna //dna-locking the mech - var/list/proc_res = list() //stores proc owners, like proc_res["functionname"] = owner reference - var/datum/effect/effect/system/spark_spread/spark_system = new - var/lights = 0 - var/lights_power = 6 - - //inner atmos //These go in airtight.dm, not all vehicles are space-faring -Agouri - //var/use_internal_tank = 0 - //var/internal_tank_valve = ONE_ATMOSPHERE - //var/obj/machinery/portable_atmospherics/canister/internal_tank - //var/datum/gas_mixture/cabin_air - //var/obj/machinery/atmospherics/portables_connector/connected_port = null - - var/obj/item/device/radio/radio = null - - var/max_temperature = 2500 - //var/internal_damage_threshold = 50 //health percentage below which internal damage is possible - var/internal_damage = 0 //contains bitflags - - var/list/operation_req_access = list()//required access level for mecha operation - var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment - - //var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature //In airtight.dm you go -Agouri - var/datum/global_iterator/pr_inertial_movement //controls intertial movement in spesss - - //var/datum/global_iterator/pr_give_air //moves air from tank to cabin //Y-you too -Agouri - - var/datum/global_iterator/pr_internal_damage //processes internal damage - - - var/wreckage - - var/list/equipment = new - var/obj/selected - //var/max_equip = 3 - - var/datum/events/events - - - -/obj/vehicle/New() - ..() - events = new - icon_state += "-unmanned" - add_radio() - //add_cabin() //No cabin for non-airtights - - spark_system.set_up(2, 0, src) - spark_system.attach(src) - add_cell() - add_iterators() - removeVerb(/obj/mecha/verb/disconnect_from_port) - removeVerb(/atom/movable/verb/pull) - log_message("[src.name]'s functions initialised. Work protocols active - Entering IDLE mode.") - loc.Entered(src) - return - - -//################ Helpers ########################################################### - - -/obj/vehicle/proc/removeVerb(verb_path) - verbs -= verb_path - -/obj/vehicle/proc/addVerb(verb_path) - verbs += verb_path - -/*/obj/vehicle/proc/add_airtank() //In airtight.dm -Agouri - internal_tank = new /obj/machinery/portable_atmospherics/canister/air(src) - return internal_tank*/ - -/obj/vehicle/proc/add_cell(var/obj/item/weapon/cell/C=null) - if(C) - C.forceMove(src) - cell = C - return - cell = new(src) - cell.charge = 15000 - cell.maxcharge = 15000 - -/*/obj/vehicle/proc/add_cabin() //In airtight.dm -Agouri - cabin_air = new - cabin_air.temperature = T20C - cabin_air.volume = 200 - cabin_air.oxygen = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) - cabin_air.nitrogen = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) - return cabin_air*/ - -/obj/vehicle/proc/add_radio() - radio = new(src) - radio.name = "[src] radio" - radio.icon = icon - radio.icon_state = icon_state - radio.subspace_transmission = 1 - -/obj/vehicle/proc/add_iterators() - pr_inertial_movement = new /datum/global_iterator/vehicle_intertial_movement(null,0) - //pr_internal_damage = new /datum/global_iterator/vehicle_internal_damage(list(src),0) - //pr_int_temp_processor = new /datum/global_iterator/vehicle_preserve_temp(list(src)) //In airtight.dm's add_airtight_iterators -Agouri - //pr_give_air = new /datum/global_iterator/vehicle_tank_give_air(list(src) //Same here -Agouri - -/obj/vehicle/proc/check_for_support() - if(locate(/obj/structure/grille, orange(1, src)) || locate(/obj/structure/lattice, orange(1, src)) || locate(/turf/simulated, orange(1, src)) || locate(/turf/unsimulated, orange(1, src))) - return 1 - else - return 0 - -//################ Logs and messages ############################################ - - -/obj/vehicle/proc/log_message(message as text,red=null) - log.len++ - log[log.len] = list("time"=world.timeofday,"message"="[red?"":null][message][red?"":null]") - return log.len - - - -//################ Global Iterator Datums ###################################### - - -/datum/global_iterator/vehicle_intertial_movement //inertial movement in space - delay = 7 - - process(var/obj/vehicle/V as obj, direction) - if(direction) - if(!step(V, direction)||V.check_for_support()) - src.stop() - else - src.stop() - return - - -/datum/global_iterator/mecha_internal_damage // processing internal damage - - process(var/obj/mecha/mecha) - if(!mecha.hasInternalDamage()) - return stop() - if(mecha.hasInternalDamage(MECHA_INT_FIRE)) - if(!mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL) && prob(5)) - mecha.clearInternalDamage(MECHA_INT_FIRE) - if(mecha.internal_tank) - if(mecha.internal_tank.return_pressure()>mecha.internal_tank.maximum_pressure && !(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH))) - mecha.setInternalDamage(MECHA_INT_TANK_BREACH) - var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() - if(int_tank_air && int_tank_air.return_volume()>0) //heat the air_contents - int_tank_air.temperature = min(6000+T0C, int_tank_air.temperature+rand(10,15)) - if(mecha.cabin_air && mecha.cabin_air.return_volume()>0) - mecha.cabin_air.temperature = min(6000+T0C, mecha.cabin_air.return_temperature()+rand(10,15)) - if(mecha.cabin_air.return_temperature()>mecha.max_temperature/2) - mecha.take_damage(4/round(mecha.max_temperature/mecha.cabin_air.return_temperature(),0.1),"fire") - if(mecha.hasInternalDamage(MECHA_INT_TEMP_CONTROL)) //stop the mecha_preserve_temp loop datum - mecha.pr_int_temp_processor.stop() - if(mecha.hasInternalDamage(MECHA_INT_TANK_BREACH)) //remove some air from internal tank - if(mecha.internal_tank) - var/datum/gas_mixture/int_tank_air = mecha.internal_tank.return_air() - var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) - if(mecha.loc && hascall(mecha.loc,"assume_air")) - mecha.loc.assume_air(leaked_gas) - else - qdel(leaked_gas) - if(mecha.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) - if(mecha.get_charge()) - mecha.spark_system.start() - mecha.cell.charge -= min(20,mecha.cell.charge) - mecha.cell.maxcharge -= min(20,mecha.cell.maxcharge) - return \ No newline at end of file diff --git a/code/modules/admin/admin_report.dm b/code/modules/admin/admin_report.dm deleted file mode 100644 index 9bc1c91ef3f..00000000000 --- a/code/modules/admin/admin_report.dm +++ /dev/null @@ -1,180 +0,0 @@ -// Reports are a way to notify admins of wrongdoings that happened -// while no admin was present. They work a bit similar to news, but -// they can only be read by admins and moderators. - -// a single admin report -datum/admin_report/var - ID // the ID of the report - body // the content of the report - author // key of the author - date // date on which this was created - done // whether this was handled - - offender_key // store the key of the offender - offender_cid // store the cid of the offender - -datum/report_topic_handler - Topic(href,href_list) - ..() - var/client/C = locate(href_list["client"]) - if(href_list["action"] == "show_reports") - C.display_admin_reports() - else if(href_list["action"] == "remove") - C.mark_report_done(text2num(href_list["ID"])) - else if(href_list["action"] == "edit") - C.edit_report(text2num(href_list["ID"])) - -var/datum/report_topic_handler/report_topic_handler - -world/New() - ..() - report_topic_handler = new - -// add a new news datums -proc/make_report(body, author, okey, cid) - var/savefile/Reports = new("data/reports.sav") - var/list/reports - var/lastID - - Reports["reports"] >> reports - Reports["lastID"] >> lastID - - if(!reports) reports = list() - if(!lastID) lastID = 0 - - var/datum/admin_report/created = new() - created.ID = ++lastID - created.body = body - created.author = author - created.date = world.realtime - created.done = 0 - created.offender_key = okey - created.offender_cid = cid - - reports.Insert(1, created) - - Reports["reports"] << reports - Reports["lastID"] << lastID - -// load the reports from disk -proc/load_reports() - var/savefile/Reports = new("data/reports.sav") - var/list/reports - - Reports["reports"] >> reports - - if(!reports) reports = list() - - return reports - -// check if there are any unhandled reports -client/proc/unhandled_reports() - if(!src.holder) return 0 - var/list/reports = load_reports() - - for(var/datum/admin_report/N in reports) - if(N.done) - continue - else return 1 - - return 0 - -// checks if the player has an unhandled report against him -client/proc/is_reported() - var/list/reports = load_reports() - - for(var/datum/admin_report/N in reports) if(!N.done) - if(N.offender_key == src.key) - return 1 - - return 0 - -// display only the reports that haven't been handled -client/proc/display_admin_reports() - set category = "Admin" - set name = "Display Admin Reports" - if(!src.holder) return - - var/list/reports = load_reports() - - var/output = "" - if(unhandled_reports()) - // load the list of unhandled reports - for(var/datum/admin_report/N in reports) - if(N.done) - continue - output += "Reported player: [N.offender_key](CID: [N.offender_cid])
" - output += "Offense:[N.body]
" - output += "Occured at [time2text(N.date,"MM/DD hh:mm:ss")]
" - output += "authored by [N.author]
" - output += " Flag as Handled" - if(src.key == N.author) - output += " Edit" - output += "
" - output += "
" - else - output += "Whoops, no reports!" - - usr << browse(output, "window=news;size=600x400") - - -client/proc/Report(mob/M as mob in mob_list) - set category = "Admin" - if(!src.holder) - return - - var/CID = "Unknown" - if(M.client) - CID = M.client.computer_id - - var/body = input(src.mob, "Describe in detail what you're reporting [M] for", "Report") as null|text - if(!body) return - - - make_report(body, key, M.key, CID) - - spawn(1) - display_admin_reports() - -client/proc/mark_report_done(ID as num) - if(!src.holder || src.holder.level < 0) - return - - var/savefile/Reports = new("data/reports.sav") - var/list/reports - - Reports["reports"] >> reports - - var/datum/admin_report/found - for(var/datum/admin_report/N in reports) - if(N.ID == ID) - found = N - if(!found) src << "* An error occured, sorry." - - found.done = 1 - - Reports["reports"] << reports - - -client/proc/edit_report(ID as num) - if(!src.holder || src.holder.level < 0) - src << "You tried to modify the news, but you're not an admin!" - return - - var/savefile/Reports = new("data/reports.sav") - var/list/reports - - Reports["reports"] >> reports - - var/datum/admin_report/found - for(var/datum/admin_report/N in reports) - if(N.ID == ID) - found = N - if(!found) src << "* An error occured, sorry." - - var/body = input(src.mob, "Enter a body for the news", "Body") as null|message - if(!body) return - - found.body = body - - Reports["reports"] << reports diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 172a408a22c..771b9c417a9 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -98,7 +98,8 @@ var/list/admin_verbs_admin = list( /client/proc/view_duty_log, /client/proc/cmd_dev_bst, /client/proc/clear_toxins, - /client/proc/wipe_ai // allow admins to force-wipe AIs + /client/proc/wipe_ai, // allow admins to force-wipe AIs + /client/proc/flush_lighting_queues ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, @@ -127,7 +128,9 @@ var/list/admin_verbs_fun = list( /client/proc/roll_dices, /datum/admins/proc/create_admin_fax, /datum/admins/proc/call_supply_drop, - /datum/admins/proc/call_drop_pod + /datum/admins/proc/call_drop_pod, + /client/proc/show_tip, + /client/proc/fab_tip ) var/list/admin_verbs_spawn = list( @@ -200,7 +203,8 @@ var/list/admin_verbs_debug = list( /client/proc/jumptocoord, /client/proc/dsay, /client/proc/toggle_recursive_explosions, - /client/proc/restart_sql + /client/proc/restart_sql, + /client/proc/flush_lighting_queues ) var/list/admin_verbs_paranoid_debug = list( @@ -351,7 +355,8 @@ var/list/admin_verbs_dev = list( //will need to be altered - Ryan784 /client/proc/togglebuildmodeself, /client/proc/toggledebuglogs, /client/proc/ZASSettings, - /client/proc/cmd_dev_bst + /client/proc/cmd_dev_bst, + /client/proc/flush_lighting_queues ) var/list/admin_verbs_cciaa = list( /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ @@ -1032,10 +1037,10 @@ var/list/admin_verbs_cciaa = list( if (alert("Are you sure you want to wipe [target.name]? They will be ghosted and their job slot freed.", "Confirm AI Termination", "No", "No", "Yes") != "Yes") return - + log_and_message_admins("admin-wiped [key_name_admin(target)]'s core.") target.do_wipe_core() - + /client/proc/restart_sql() set category = "Debug" set name = "Reconnect SQL" @@ -1050,3 +1055,19 @@ var/list/admin_verbs_cciaa = list( log_and_message_admins("is attempting to reconnect the server to MySQL.") dbcon.Reconnect() + +/client/proc/flush_lighting_queues() + set category = "Debug" + set name = "Reset Lighting" + set desc = "Flushes the lighting processor's work queue. Useful if the processor is hung with an invalid source." + + if (!check_rights(R_DEBUG|R_ADMIN|R_DEV)) + return + + if (alert("Flush Lighting Work Queue? This will invalidate all pending lighting updates.", "Reset Lighting", "No", "No", "Yes") != "Yes") + return + + log_and_message_admins("has flushed the lighting processor queues.") + lighting_update_lights = list() + lighting_update_corners = list() + lighting_update_overlays = list() diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index c9f2497abc7..ca78cebe391 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -972,3 +972,17 @@ else alert("Invalid mob") +/client/proc/cmd_debug_profile_lighting() + set category = "Debug" + set name = "Profile Lighting" + set desc = "Spams the database with lighting updates. Y'know, just 'cause." + + if (!check_rights(R_DEBUG|R_SERVER)) + return + + if (!establish_db_connection(dbcon)) + usr << span("alert", "Unable to start profiling: No active database connection.") + return + + lighting_profiling = !lighting_profiling + log_and_message_admins("has [lighting_profiling ? "enabled" : "disabled"] lighting profiling.") diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 64f5d759769..60dd248dd9c 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -163,6 +163,7 @@ var/list/debug_verbs = list ( ,/datum/admins/proc/setup_supermatter ,/client/proc/atmos_toggle_debug ,/client/proc/spawn_tanktransferbomb + ,/client/proc/cmd_debug_profile_lighting ) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 00e701bd57a..e6c7168a5d7 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -949,3 +949,50 @@ Traitors and the like can also be revived with the previous role mostly intact. usr << "Random events disabled" message_admins("Admin [key_name_admin(usr)] has disabled random events.", 1) feedback_add_details("admin_verb","TRE") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/fab_tip() + set category = "Admin" + set name = "Fabricate Tip" + set desc = "Sends a tip (that you specify) to all players. After all \ + you're the experienced player here." + + if(!holder) + return + + var/input = input(usr, "Please specify your tip that you want to send to the players.", "Tip", "") as message|null + if(!input) + return + + if(!ticker) + return + + ticker.selected_tip = input + + // If we've already tipped, then send it straight away. + if(ticker.tipped) + ticker.send_tip_of_the_round() + ticker.selected_tip = initial(ticker.selected_tip) + + + message_admins("[key_name_admin(usr)] sent a tip of the round.") + log_admin("[key_name(usr)] sent \"[input]\" as the Tip of the Round.") + feedback_add_details("admin_verb","TIP") + +/client/proc/show_tip() + set category = "Debug" + set name = "Show Tip" + set desc = "Sends a tip (that the config specifies) to all players. After all \ + you're not the experienced player here." + + if(!holder) + return + + if(!ticker) + return + + ticker.send_tip_of_the_round() + + + message_admins("[key_name_admin(usr)] sent a pregenerated tip of the round.") + log_admin("[key_name(usr)] sent a pregenerated Tip of the Round.") + feedback_add_details("admin_verb","FAP") \ No newline at end of file diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 665a005b99c..3d66037bd16 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -49,3 +49,14 @@ var/need_saves_migrated = "Requires database" //Used to determine whether or not the ckey needs their saves migrated over to the database. Default is 0 upon successful connection. preload_rsc = 0 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server. + + //////////// + //PARALLAX// + //////////// + var/list/parallax = list() + var/list/parallax_movable = list() + var/list/parallax_offset = list() + var/turf/previous_turf = null + var/obj/screen/plane_master/parallax_master/parallax_master = null + var/obj/screen/plane_master/parallax_dustmaster/parallax_dustmaster = null + var/obj/screen/plane_master/parallax_spacemaster/parallax_spacemaster = null \ No newline at end of file diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index e1bce814e36..08bcb180119 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -278,6 +278,8 @@ prefs.last_id = computer_id //these are gonna be used for banning . = ..() //calls mob.Login() + + prefs.sanitize_preferences() if (byond_version < config.client_error_version) src << "Your version of BYOND is too old!" diff --git a/code/modules/client/movement.dm b/code/modules/client/movement.dm index efcf51c02ee..5ba3a87e1e4 100644 --- a/code/modules/client/movement.dm +++ b/code/modules/client/movement.dm @@ -3,6 +3,9 @@ ..() dir = NORTH +// These break the lighting system, comment out for now until +// someone can be arsed to fix it. +/* /client/verb/spinleft() set name = "Spin View CCW" set category = "OOC" @@ -13,3 +16,4 @@ set category = "OOC" dir = turn(dir, -90) +*/ diff --git a/code/modules/client/preference_setup/general/04_equipment.dm b/code/modules/client/preference_setup/general/04_equipment.dm index 74c6ff7077a..2ceb8aea4d3 100644 --- a/code/modules/client/preference_setup/general/04_equipment.dm +++ b/code/modules/client/preference_setup/general/04_equipment.dm @@ -7,37 +7,31 @@ S["undershirt"] >> pref.undershirt S["socks"] >> pref.socks S["backbag"] >> pref.backbag - S["gear"] >> pref.gear /datum/category_item/player_setup_item/general/equipment/save_character(var/savefile/S) S["underwear"] << pref.underwear S["undershirt"] << pref.undershirt S["socks"] << pref.socks S["backbag"] << pref.backbag - S["gear"] << pref.gear /datum/category_item/player_setup_item/general/equipment/gather_load_query() - return list("ss13_characters" = list("vars" = list("underwear", "undershirt", "socks", "backbag", "gear"), "args" = list("id"))) + return list("ss13_characters" = list("vars" = list("underwear", "undershirt", "socks", "backbag"), "args" = list("id"))) /datum/category_item/player_setup_item/general/equipment/gather_load_parameters() return list(":id" = pref.current_character) /datum/category_item/player_setup_item/general/equipment/gather_save_query() - return list("ss13_characters" = list("underwear", "undershirt", "socks", "backbag", "gear", "id" = 1, "ckey" = 1)) + return list("ss13_characters" = list("underwear", "undershirt", "socks", "backbag", "id" = 1, "ckey" = 1)) /datum/category_item/player_setup_item/general/equipment/gather_save_parameters() - return list(":underwear" = pref.underwear, ":undershirt" = pref.undershirt, ":socks" = pref.socks, ":backbag" = pref.backbag, ":gear" = list2params(pref.gear), ":id" = pref.current_character, ":ckey" = pref.client.ckey) + return list(":underwear" = pref.underwear, ":undershirt" = pref.undershirt, ":socks" = pref.socks, ":backbag" = pref.backbag, ":id" = pref.current_character, ":ckey" = pref.client.ckey) /datum/category_item/player_setup_item/general/equipment/sanitize_character(var/sql_load = 0) if (sql_load) pref.backbag = text2num(pref.backbag) - pref.gear = params2list(pref.gear) pref.backbag = sanitize_integer(pref.backbag, 1, backbaglist.len, initial(pref.backbag)) - if (!islist(pref.gear)) - pref.gear = list() - var/undies = get_undies() var/gender_socks = get_gender_socks() if(!get_key_by_value(undies, pref.underwear)) @@ -47,45 +41,14 @@ if(!get_key_by_value(gender_socks, pref.socks)) pref.socks = gender_socks[gender_socks[1]] - var/total_cost = 0 - for(var/gear_name in pref.gear) - if(!gear_datums[gear_name]) - pref.gear -= gear_name - else if(!(gear_name in valid_gear_choices())) - pref.gear -= gear_name - else - var/datum/gear/G = gear_datums[gear_name] - if(total_cost + G.cost > MAX_GEAR_COST) - pref.gear -= gear_name - else - total_cost += G.cost /datum/category_item/player_setup_item/general/equipment/content() - . += "Equipment Loadout:
" + . += "Equipment:
" . += "Underwear: [get_key_by_value(get_undies(),pref.underwear)]
" . += "Undershirt: [get_key_by_value(undershirt_t,pref.undershirt)]
" . += "Socks: [get_key_by_value(get_gender_socks(),pref.socks)]
" . += "Backpack Type: [backbaglist[pref.backbag]]
" - . += "
Custom Loadout:
" - var/total_cost = 0 - - if(pref.gear && pref.gear.len) - for(var/i = 1; i <= pref.gear.len; i++) - var/datum/gear/G = gear_datums[pref.gear[i]] - if(G) - total_cost += G.cost - . += "[pref.gear[i]] ([G.cost] points) Remove
" - - . += "Used: [total_cost] points." - else - . += "None." - - if(total_cost < MAX_GEAR_COST) - . += " Add" - if(pref.gear && pref.gear.len) - . += " Clear" - . += "
" /datum/category_item/player_setup_item/general/equipment/proc/get_undies() return pref.gender == MALE ? underwear_m : underwear_f @@ -93,17 +56,6 @@ /datum/category_item/player_setup_item/general/equipment/proc/get_gender_socks() return pref.gender == MALE ? socks_m : socks_f -/datum/category_item/player_setup_item/general/equipment/proc/valid_gear_choices(var/max_cost) - . = list() - var/mob/preference_mob = preference_mob() - for(var/gear_name in gear_datums) - var/datum/gear/G = gear_datums[gear_name] - if(G.whitelisted && !is_alien_whitelisted(preference_mob, G.whitelisted)) - continue - if(max_cost && G.cost > max_cost) - continue - . += gear_name - /datum/category_item/player_setup_item/general/equipment/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["change_underwear"]) var/underwear_options = get_undies() @@ -131,32 +83,4 @@ pref.backbag = backbaglist.Find(new_backbag) return TOPIC_REFRESH - else if(href_list["add_loadout"]) - var/total_cost = 0 - for(var/gear_name in pref.gear) - if(gear_datums[gear_name]) - var/datum/gear/G = gear_datums[gear_name] - total_cost += G.cost - - var/choice = input(user, "Select gear to add:", "Character Preference") as null|anything in valid_gear_choices(MAX_GEAR_COST - total_cost) - if(choice && gear_datums[choice] && CanUseTopic(user)) - var/datum/gear/C = gear_datums[choice] - total_cost += C.cost - if(C && total_cost <= MAX_GEAR_COST) - pref.gear += choice - user << "Added \the '[choice]' for [C.cost] points ([MAX_GEAR_COST - total_cost] points remaining)." - else - user << "Adding \the '[choice]' will exceed the maximum loadout cost of [MAX_GEAR_COST] points." - return TOPIC_REFRESH - - else if(href_list["remove_loadout"]) - var/i_remove = text2num(href_list["remove_loadout"]) - if(i_remove < 1 || i_remove > pref.gear.len) return TOPIC_NOACTION - pref.gear.Cut(i_remove, i_remove + 1) - return TOPIC_REFRESH - - else if(href_list["clear_loadout"]) - pref.gear.Cut() - return TOPIC_REFRESH - return ..() diff --git a/code/modules/client/preference_setup/global/02_settings.dm b/code/modules/client/preference_setup/global/02_settings.dm index f826f1b2fae..04a82b4336f 100644 --- a/code/modules/client/preference_setup/global/02_settings.dm +++ b/code/modules/client/preference_setup/global/02_settings.dm @@ -9,6 +9,8 @@ S["asfx_togs"] >> pref.asfx_togs S["motd_hash"] >> pref.motd_hash S["memo_hash"] >> pref.memo_hash + S["parallax_speed"] >> pref.parallax_speed + S["parallax_toggles"] >> pref.parallax_togs /datum/category_item/player_setup_item/player_global/settings/save_preferences(var/savefile/S) S["lastchangelog"] << pref.lastchangelog @@ -17,6 +19,8 @@ S["asfx_togs"] << pref.asfx_togs S["motd_hash"] << pref.motd_hash S["memo_hash"] << pref.memo_hash + S["parallax_speed"] << pref.parallax_speed + S["parallax_toggles"] << pref.parallax_togs /datum/category_item/player_setup_item/player_global/settings/gather_load_query() return list("ss13_player_preferences" = list("vars" = list("lastchangelog", "current_character", "toggles", "asfx_togs", "lastmotd" = "motd_hash", "lastmemo" = "memo_hash"), "args" = list("ckey"))) @@ -25,7 +29,7 @@ return list(":ckey" = pref.client.ckey) /datum/category_item/player_setup_item/player_global/settings/gather_save_query() - return list("ss13_player_preferences" = list("lastchangelog", "current_character", "toggles", "asfx_togs", "lastmotd", "lastmemo", "ckey" = 1)) + return list("ss13_player_preferences" = list("lastchangelog", "current_character", "toggles", "asfx_togs", "lastmotd", "lastmemo", "ckey" = 1, "parallax_toggles", "parallax_speed")) /datum/category_item/player_setup_item/player_global/settings/gather_save_parameters() return list(":ckey" = pref.client.ckey, @@ -34,7 +38,9 @@ ":toggles" = pref.toggles, ":asfx_togs" = pref.asfx_togs, ":lastmotd" = pref.motd_hash, - ":lastmemo" = pref.memo_hash) + ":lastmemo" = pref.memo_hash, + ":parallax_toggles" = pref.parallax_togs, + ":parallax_speed" = pref.parallax_speed) /datum/category_item/player_setup_item/player_global/settings/sanitize_preferences(var/sql_load = 0) if (sql_load) @@ -46,6 +52,8 @@ pref.asfx_togs = sanitize_integer(text2num(pref.asfx_togs), 0, 65535, initial(pref.toggles)) pref.motd_hash = sanitize_text(pref.motd_hash, initial(pref.motd_hash)) pref.memo_hash = sanitize_text(pref.memo_hash, initial(pref.memo_hash)) + pref.parallax_speed = sanitize_integer(text2num(pref.parallax_speed), 1, 10, initial(pref.parallax_speed)) + pref.parallax_togs = sanitize_integer(text2num(pref.parallax_togs), 0, 65535, initial(pref.parallax_togs)) /datum/category_item/player_setup_item/player_global/settings/content(var/mob/user) . += "Play admin midis: [(pref.toggles & SOUND_MIDI) ? "Yes" : "No"]
" @@ -53,6 +61,8 @@ . += "Ghost ears: [(pref.toggles & CHAT_GHOSTEARS) ? "All Speech" : "Nearest Creatures"]
" . += "Ghost sight: [(pref.toggles & CHAT_GHOSTSIGHT) ? "All Emotes" : "Nearest Creatures"]
" . += "Ghost radio: [(pref.toggles & CHAT_GHOSTRADIO) ? "All Chatter" : "Nearest Speakers"]
" + . += "Space Parallax: [(pref.parallax_togs & PARALLAX_SPACE) ? "Yes" : "No"]
" + . += "Space Dust: [(pref.parallax_togs & PARALLAX_DUST) ? "Yes" : "No"]
" /datum/category_item/player_setup_item/player_global/settings/OnTopic(var/href,var/list/href_list, var/mob/user) if(href_list["toggle"]) @@ -65,4 +75,9 @@ user << sound(null, repeat = 0, wait = 0, volume = 85, channel = 1) return TOPIC_REFRESH + if(href_list["paratoggle"]) + var/flag = text2num(href_list["paratoggle"]) + pref.parallax_togs ^= flag + return TOPIC_REFRESH + return ..() diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm new file mode 100644 index 00000000000..8620e866793 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm @@ -0,0 +1,145 @@ +/datum/gear_tweak/proc/get_contents(var/metadata) + return + +/datum/gear_tweak/proc/get_metadata(var/user, var/metadata) + return + +/datum/gear_tweak/proc/get_default() + return + +/datum/gear_tweak/proc/tweak_gear_data(var/metadata, var/datum/gear_data) + return + +/datum/gear_tweak/proc/tweak_item(var/obj/item/I, var/metadata) + return + +/* +Color adjustment +*/ + +var/datum/gear_tweak/color/gear_tweak_free_color_choice = new() + +/datum/gear_tweak/color + var/list/valid_colors + +/datum/gear_tweak/color/New(var/list/valid_colors) + src.valid_colors = valid_colors + ..() + +/datum/gear_tweak/color/get_contents(var/metadata) + return "Color: " + +/datum/gear_tweak/color/get_default() + return valid_colors ? valid_colors[1] : COLOR_GRAY + +/datum/gear_tweak/color/get_metadata(var/user, var/metadata) + if(valid_colors) + return input(user, "Choose an item color.", "Character Preference", metadata) as null|anything in valid_colors + return input(user, "Choose an item color.", "Global Preference", metadata) as color|null + +/datum/gear_tweak/color/tweak_item(var/obj/item/I, var/metadata) + if(valid_colors && !(metadata in valid_colors)) + return + I.color = metadata + +/* +Path adjustment +*/ + +/datum/gear_tweak/path + var/list/valid_paths + +/datum/gear_tweak/path/New(var/list/valid_paths) + src.valid_paths = valid_paths + ..() + +/datum/gear_tweak/path/get_contents(var/metadata) + return "Type: [metadata]" + +/datum/gear_tweak/path/get_default() + return valid_paths[1] + +/datum/gear_tweak/path/get_metadata(var/user, var/metadata) + return input(user, "Choose a type.", "Character Preference", metadata) as null|anything in valid_paths + +/datum/gear_tweak/path/tweak_gear_data(var/metadata, var/datum/gear_data/gear_data) + if(!(metadata in valid_paths)) + return + gear_data.path = valid_paths[metadata] + +/* +Content adjustment +*/ + +/datum/gear_tweak/contents + var/list/valid_contents + +/datum/gear_tweak/contents/New() + valid_contents = args.Copy() + ..() + +/datum/gear_tweak/contents/get_contents(var/metadata) + return "Contents: [english_list(metadata, and_text = ", ")]" + +/datum/gear_tweak/contents/get_default() + . = list() + for(var/i = 1 to valid_contents.len) + . += "Random" + +/datum/gear_tweak/contents/get_metadata(var/user, var/list/metadata) + . = list() + for(var/i = metadata.len to (valid_contents.len - 1)) + metadata += "Random" + for(var/i = 1 to valid_contents.len) + var/entry = input(user, "Choose an entry.", "Character Preference", metadata[i]) as null|anything in (valid_contents[i] + list("Random", "None")) + if(entry) + . += entry + else + return metadata + +/datum/gear_tweak/contents/tweak_item(var/obj/item/I, var/list/metadata) + if(metadata.len != valid_contents.len) + return + for(var/i = 1 to valid_contents.len) + var/path + var/list/contents = valid_contents[i] + if(metadata[i] == "Random") + path = pick(contents) + path = contents[path] + else if(metadata[i] == "None") + continue + else + path = contents[metadata[i]] + new path(I) + +/* +Reagents adjustment +*/ + + +/datum/gear_tweak/reagents + var/list/valid_reagents + +/datum/gear_tweak/reagents/New(var/list/reagents) + valid_reagents = reagents.Copy() + ..() + +/datum/gear_tweak/reagents/get_contents(var/metadata) + return "Reagents: [metadata]" + +/datum/gear_tweak/reagents/get_default() + return "Random" + +/datum/gear_tweak/reagents/get_metadata(var/user, var/list/metadata) + . = input(user, "Choose an entry.", "Character Preference", metadata) as null|anything in (valid_reagents + list("Random", "None")) + if(!.) + return metadata + +/datum/gear_tweak/reagents/tweak_item(var/obj/item/I, var/list/metadata) + if(metadata == "None") + return + if(metadata == "Random") + . = valid_reagents[pick(valid_reagents)] + else + . = valid_reagents[metadata] + I.reagents.add_reagent(., I.reagents.get_free_space()) \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm new file mode 100644 index 00000000000..70a18e5b8a6 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout.dm @@ -0,0 +1,228 @@ +var/list/loadout_categories = list() +var/list/gear_datums = list() + +/datum/loadout_category + var/category = "" + var/list/gear = list() + +/datum/loadout_category/New(var/cat) + category = cat + ..() + +/hook/startup/proc/populate_gear_list() + + //create a list of gear datums to sort + for(var/geartype in typesof(/datum/gear)-/datum/gear) + var/datum/gear/G = geartype + + var/use_name = initial(G.display_name) + var/use_category = initial(G.sort_category) + + if(!loadout_categories[use_category]) + loadout_categories[use_category] = new /datum/loadout_category(use_category) + var/datum/loadout_category/LC = loadout_categories[use_category] + gear_datums[use_name] = new geartype + LC.gear[use_name] = gear_datums[use_name] + + loadout_categories = sortAssoc(loadout_categories) + for(var/loadout_category in loadout_categories) + var/datum/loadout_category/LC = loadout_categories[loadout_category] + LC.gear = sortAssoc(LC.gear) + return 1 + +/datum/category_item/player_setup_item/loadout + name = "Loadout" + sort_order = 1 + var/current_tab = "General" + +/datum/category_item/player_setup_item/loadout/load_character(var/savefile/S) + S["gear"] >> pref.gear + +/datum/category_item/player_setup_item/loadout/save_character(var/savefile/S) + S["gear"] << pref.gear + +/datum/category_item/player_setup_item/loadout/gather_load_query() + return list("ss13_characters" = list("vars" = list("gear"), "args" = list("id"))) + +/datum/category_item/player_setup_item/loadout/gather_save_query() + return list("ss13_characters" = list("gear", "id" = 1, "ckey" = 1)) + +/datum/category_item/player_setup_item/loadout/gather_save_parameters() + return list(":gear" = list2params(pref.gear), ":id" = pref.current_character, ":ckey" = pref.client.ckey) + +/datum/category_item/player_setup_item/loadout/proc/valid_gear_choices(var/max_cost) + . = list() + var/mob/preference_mob = preference_mob() + for(var/gear_name in gear_datums) + var/datum/gear/G = gear_datums[gear_name] + + if(G.whitelisted && !is_alien_whitelisted(preference_mob, all_species[G.whitelisted])) + continue + if(max_cost && G.cost > max_cost) + continue + . += gear_name + +/datum/category_item/player_setup_item/loadout/sanitize_character(var/sql_load = 0) + + if (sql_load) + pref.gear = params2list(pref.gear) + + var/mob/preference_mob = preference_mob() + if(!islist(pref.gear)) + pref.gear = list() + + for(var/gear_name in pref.gear) + if(!(gear_name in gear_datums)) + pref.gear -= gear_name + var/total_cost = 0 + for(var/gear_name in pref.gear) + if(!gear_datums[gear_name]) + preference_mob << "You cannot have more than one of the \the [gear_name]" + pref.gear -= gear_name + else if(!(gear_name in valid_gear_choices())) + preference_mob << "You cannot take \the [gear_name] as you are not whitelisted for the species." + pref.gear -= gear_name + else + var/datum/gear/G = gear_datums[gear_name] + if(total_cost + G.cost > MAX_GEAR_COST) + pref.gear -= gear_name + preference_mob << "You cannot afford to take \the [gear_name]" + else + total_cost += G.cost + +/datum/category_item/player_setup_item/loadout/content() + var/total_cost = 0 + if(pref.gear && pref.gear.len) + for(var/i = 1; i <= pref.gear.len; i++) + var/datum/gear/G = gear_datums[pref.gear[i]] + if(G) + total_cost += G.cost + + var/fcolor = "#3366CC" + if(total_cost < MAX_GEAR_COST) + fcolor = "#E67300" + . = list() + . += "" + . += "" + + . += "" + + var/datum/loadout_category/LC = loadout_categories[current_tab] + . += "" + . += "" + . += "" + for(var/gear_name in LC.gear) + if(!(gear_name in valid_gear_choices())) + continue + var/datum/gear/G = LC.gear[gear_name] + var/ticked = (G.display_name in pref.gear) + . += "" + . += "" + . += "" + if(ticked) + . += "" + . += "
[total_cost]/[MAX_GEAR_COST] loadout points spent. \[Clear Loadout\]
" + var/firstcat = 1 + for(var/category in loadout_categories) + + if(firstcat) + firstcat = 0 + else + . += " |" + if(category == current_tab) + . += " [category] " + else + var/datum/loadout_category/LC = loadout_categories[category] + var/tcolor = "#3366CC" + for(var/thing in LC.gear) + if(thing in pref.gear) + tcolor = "#E67300" + break + . += " [category] " + . += "

[LC.category]

[G.display_name][G.cost][G.description]
" + for(var/datum/gear_tweak/tweak in G.gear_tweaks) + . += " [tweak.get_contents(get_tweak_metadata(G, tweak))]" + . += "
" + . = jointext(.,null) + +/datum/category_item/player_setup_item/loadout/proc/get_gear_metadata(var/datum/gear/G) + . = pref.gear[G.display_name] + if(!.) + . = list() + pref.gear[G.display_name] = . + +/datum/category_item/player_setup_item/loadout/proc/get_tweak_metadata(var/datum/gear/G, var/datum/gear_tweak/tweak) + var/list/metadata = get_gear_metadata(G) + . = metadata["[tweak]"] + if(!.) + . = tweak.get_default() + metadata["[tweak]"] = . + +/datum/category_item/player_setup_item/loadout/proc/set_tweak_metadata(var/datum/gear/G, var/datum/gear_tweak/tweak, var/new_metadata) + var/list/metadata = get_gear_metadata(G) + metadata["[tweak]"] = new_metadata + +/datum/category_item/player_setup_item/loadout/OnTopic(href, href_list, user) + if(href_list["toggle_gear"]) + var/datum/gear/TG = gear_datums[href_list["toggle_gear"]] + if(TG.display_name in pref.gear) + pref.gear -= TG.display_name + else + var/total_cost = 0 + for(var/gear_name in pref.gear) + var/datum/gear/G = gear_datums[gear_name] + if(istype(G)) total_cost += G.cost + if((total_cost+TG.cost) <= MAX_GEAR_COST) + pref.gear += TG.display_name + return TOPIC_REFRESH + if(href_list["gear"] && href_list["tweak"]) + var/datum/gear/gear = gear_datums[href_list["gear"]] + var/datum/gear_tweak/tweak = locate(href_list["tweak"]) + if(!tweak || !istype(gear) || !(tweak in gear.gear_tweaks)) + return TOPIC_NOACTION + var/metadata = tweak.get_metadata(user, get_tweak_metadata(gear, tweak)) + if(!metadata || !CanUseTopic(user)) + return TOPIC_NOACTION + set_tweak_metadata(gear, tweak, metadata) + return TOPIC_REFRESH + else if(href_list["select_category"]) + current_tab = href_list["select_category"] + return TOPIC_REFRESH + else if(href_list["clear_loadout"]) + pref.gear.Cut() + return TOPIC_REFRESH + return ..() + +/datum/gear + var/display_name //Name/index. Must be unique. + var/description //Description of this gear. If left blank will default to the description of the pathed item. + var/path //Path to item. + var/cost = 1 //Number of points used. Items in general cost 1 point, storage/armor/gloves/special use costs 2 points. + var/slot //Slot to equip to. + var/list/allowed_roles //Roles that can spawn with this item. + var/whitelisted //Term to check the whitelist for.. + var/sort_category = "General" + var/list/gear_tweaks = list() //List of datums which will alter the item after it has been spawned. + +/datum/gear/New() + ..() + if(!description) + var/obj/O = path + description = initial(O.desc) + +/datum/gear_data + var/path + var/location + +/datum/gear_data/New(var/path, var/location) + src.path = path + src.location = location + +/datum/gear/proc/spawn_item(var/location, var/metadata) + var/datum/gear_data/gd = new(path, location) + for(var/datum/gear_tweak/gt in gear_tweaks) + gt.tweak_gear_data(metadata["[gt]"], gd) + var/item = new gd.path(gd.location) + for(var/datum/gear_tweak/gt in gear_tweaks) + gt.tweak_item(item, metadata["[gt]"]) + return item diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm new file mode 100644 index 00000000000..04cffbef2e6 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm @@ -0,0 +1,69 @@ +/datum/gear/accessory + display_name = "suspenders" + path = /obj/item/clothing/accessory/suspenders + slot = slot_tie + sort_category = "Accessories" + +/datum/gear/accessory/waistcoat + display_name = "waistcoat" + path = /obj/item/clothing/accessory/wcoat + +/datum/gear/accessory/armband + display_name = "armband selection" + path = /obj/item/clothing/accessory/armband + +/datum/gear/accessory/armband/New() + ..() + var/armbands = list() + armbands["red armband"] = /obj/item/clothing/accessory/armband + armbands["cargo armband"] = /obj/item/clothing/accessory/armband/cargo + armbands["EMT armband"] = /obj/item/clothing/accessory/armband/medgreen + armbands["medical armband"] = /obj/item/clothing/accessory/armband/med + armbands["engineering armband"] = /obj/item/clothing/accessory/armband/engine + armbands["hydroponics armband"] = /obj/item/clothing/accessory/armband/hydro + armbands["science armband"] = /obj/item/clothing/accessory/armband/science + armbands["synthetic intelligence movement armband"] = /obj/item/clothing/accessory/armband/movement + armbands["ATLAS armband"] = /obj/item/clothing/accessory/armband/atlas + gear_tweaks += new/datum/gear_tweak/path(armbands) + +/datum/gear/accessory/holster + display_name = "holster selection" + path = /obj/item/clothing/accessory/holster + allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective", "Security Cadet") + +/datum/gear/accessory/holster/New() + ..() + var/holsters = list() + holsters["holster, armpit"] = /obj/item/clothing/accessory/holster/armpit + holsters["holster, hip"] = /obj/item/clothing/accessory/holster/hip + holsters["holster, waist"] = /obj/item/clothing/accessory/holster/waist + holsters["holster, thigh"] = /obj/item/clothing/accessory/holster/thigh + gear_tweaks += new/datum/gear_tweak/path(holsters) + +/datum/gear/accessory/tie + display_name = "tie selection" + path = /obj/item/clothing/accessory + +/datum/gear/accessory/tie/New() + ..() + var/ties = list() + ties["blue tie"] = /obj/item/clothing/accessory/blue + ties["red tie"] = /obj/item/clothing/accessory/red + ties["horrible tie"] = /obj/item/clothing/accessory/horrible + gear_tweaks += new/datum/gear_tweak/path(ties) + +/datum/gear/accessory/brown_vest + display_name = "webbing, engineering" + path = /obj/item/clothing/accessory/storage/brown_vest + allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer") + +/datum/gear/accessory/black_vest + display_name = "webbing, security" + path = /obj/item/clothing/accessory/storage/black_vest + allowed_roles = list("Security Officer","Head of Security","Warden") + +/datum/gear/accessory/webbing + display_name = "webbing, simple" + path = /obj/item/clothing/accessory/storage/webbing + cost = 2 + diff --git a/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm b/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm new file mode 100644 index 00000000000..c75a557675b --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_cosmetics.dm @@ -0,0 +1,21 @@ +/datum/gear/cosmetic + display_name = "purple comb" + path = /obj/item/weapon/haircomb + sort_category = "Cosmetics" + +/datum/gear/cosmetic/lipstick + display_name = "lipstick selection" + path = /obj/item/weapon/lipstick + +/datum/gear/cosmetic/lipstick/New() + ..() + var/lipsticks = list() + lipsticks["lipstick, red"] = /obj/item/weapon/lipstick + lipsticks["lipstick, purple"] = /obj/item/weapon/lipstick/purple + lipsticks["lipstick, jade"] = /obj/item/weapon/lipstick/jade + lipsticks["lipstick, back"] = /obj/item/weapon/lipstick/black + gear_tweaks += new/datum/gear_tweak/path(lipsticks) + +/datum/gear/cosmetic/mirror + display_name = "handheld mirror" + path = /obj/item/weapon/mirror diff --git a/code/modules/client/preference_setup/loadout/loadout_ears.dm b/code/modules/client/preference_setup/loadout/loadout_ears.dm new file mode 100644 index 00000000000..11685305ca3 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_ears.dm @@ -0,0 +1,19 @@ +// Stuff worn on the ears. Items here go in the "ears" sort_category but they must not use +// the slot_r_ear or slot_l_ear as the slot, or else players will spawn with no headset. +/datum/gear/ears + display_name = "earmuffs" + path = /obj/item/clothing/ears/earmuffs + sort_category = "Earwear" + +/datum/gear/ears/bandanna + display_name = "neck bandanna selection" + path = /obj/item/clothing/ears/bandanna + +/datum/gear/ears/bandanna/New() + ..() + var/bandanna = list() + bandanna["red bandanna"] = /obj/item/clothing/ears/bandanna + bandanna["blue bandanna"] = /obj/item/clothing/ears/bandanna/blue + bandanna["black bandanna"] = /obj/item/clothing/ears/bandanna/black + gear_tweaks += new/datum/gear_tweak/path(bandanna) + diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/client/preference_setup/loadout/loadout_eyes.dm new file mode 100644 index 00000000000..fef99095d78 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_eyes.dm @@ -0,0 +1,50 @@ +// Eyes +/datum/gear/eyes + display_name = "eyepatch" + path = /obj/item/clothing/glasses/eyepatch + slot = slot_glasses + sort_category = "Glasses and Eyewear" + +/datum/gear/eyes/glasses + display_name = "glasses, prescription" + path = /obj/item/clothing/glasses/regular + +/datum/gear/eyes/glasses/green + display_name = "glasses, green" + path = /obj/item/clothing/glasses/gglasses + +/datum/gear/eyes/glasses/prescriptionhipster + display_name = "glasses, hipster" + path = /obj/item/clothing/glasses/regular/hipster + +/datum/gear/eyes/glasses/monocle + display_name = "monocle" + path = /obj/item/clothing/glasses/monocle + +/datum/gear/eyes/scanning_goggles + display_name = "scanning goggles" + path = /obj/item/clothing/glasses/regular/scanners + +/datum/gear/eyes/sciencegoggles + display_name = "science Goggles" + path = /obj/item/clothing/glasses/science + +/datum/gear/eyes/security + display_name = "security HUD" + path = /obj/item/clothing/glasses/hud/security + allowed_roles = list("Security Officer","Head of Security","Warden") + +/datum/gear/eyes/medical + display_name = "medical HUD" + path = /obj/item/clothing/glasses/hud/health + allowed_roles = list("Medical Doctor","Chief Medical Officer","Chemist","Paramedic","Geneticist") + +/datum/gear/eyes/shades + display_name = "sunglasses, fat" + path = /obj/item/clothing/glasses/sunglasses/big + allowed_roles = list("Security Officer","Head of Security","Warden","Captain","Head of Personnel","Quartermaster","Internal Affairs Agent","Detective") + +/datum/gear/eyes/shades/prescriptionsun + display_name = "sunglasses, presciption" + path = /obj/item/clothing/glasses/sunglasses/prescription + cost = 2 diff --git a/code/modules/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm new file mode 100644 index 00000000000..7c3c9da7e5a --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_general.dm @@ -0,0 +1,69 @@ +/datum/gear/cane + display_name = "cane" + path = /obj/item/weapon/cane + +/datum/gear/dice + display_name = "d20" + path = /obj/item/weapon/dice/d20 + +/datum/gear/cards + display_name = "deck of cards" + path = /obj/item/weapon/deck/cards + +/datum/gear/tarot + display_name = "deck of tarot cards" + path = /obj/item/weapon/deck/tarot + +/datum/gear/holder + display_name = "card holder" + path = /obj/item/weapon/deck/holder + +/datum/gear/cardemon_pack + display_name = "cardemon booster pack" + path = /obj/item/weapon/pack/cardemon + +/datum/gear/spaceball_pack + display_name = "spaceball booster pack" + path = /obj/item/weapon/pack/spaceball + +/datum/gear/flask + display_name = "flask" + path = /obj/item/weapon/reagent_containers/food/drinks/flask/barflask + +/datum/gear/flask/New() + ..() + gear_tweaks += new/datum/gear_tweak/reagents(lunchables_ethanol_reagents()) + +/datum/gear/vacflask + display_name = "vacuum-flask" + path = /obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask + +/datum/gear/vacflask/New() + ..() + gear_tweaks += new/datum/gear_tweak/reagents(lunchables_drink_reagents()) + +/datum/gear/boot_knife + display_name = "boot knife" + path = /obj/item/weapon/material/kitchen/utensil/knife/boot + cost = 3 + +/datum/gear/cape + display_name = "tunnel cloak" + path = /obj/item/weapon/storage/backpack/cloak + cost = 1 + +/datum/gear/lunchbox + display_name = "lunchbox" + description = "A little lunchbox." + cost = 2 + path = /obj/item/weapon/storage/toolbox/lunchbox + +/datum/gear/lunchbox/New() + ..() + var/list/lunchboxes = list() + for(var/lunchbox_type in typesof(/obj/item/weapon/storage/toolbox/lunchbox)) + var/obj/item/weapon/storage/toolbox/lunchbox/lunchbox = lunchbox_type + if(!initial(lunchbox.filled)) + lunchboxes[initial(lunchbox.name)] = lunchbox_type + gear_tweaks += new/datum/gear_tweak/path(sortAssoc(lunchboxes)) + gear_tweaks += new/datum/gear_tweak/contents(lunchables_lunches(), lunchables_snacks(), lunchables_drinks()) \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_gloves.dm b/code/modules/client/preference_setup/loadout/loadout_gloves.dm new file mode 100644 index 00000000000..3680312c54f --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_gloves.dm @@ -0,0 +1,25 @@ +/datum/gear/gloves + display_name = "watch" + path = /obj/item/clothing/gloves/watch + cost = 2 + slot = slot_gloves + sort_category = "Gloves and Handwear" + +/datum/gear/gloves/color + display_name = "gloves selection" + path = /obj/item/clothing/gloves/black + +/datum/gear/gloves/color/New() + ..() + var/gloves = list() + gloves["black gloves"] = /obj/item/clothing/gloves + gloves["red gloves"] = /obj/item/clothing/gloves/red + gloves["blue gloves"] = /obj/item/clothing/gloves/blue + gloves["orange gloves"] = /obj/item/clothing/gloves/orange + gloves["purple gloves"] = /obj/item/clothing/gloves/purple + gloves["brown gloves"] = /obj/item/clothing/gloves/brown + gloves["light-brown gloves"] = /obj/item/clothing/gloves/light_brown + gloves["white gloves"] = /obj/item/clothing/gloves/green + gloves["grey gloves"] = /obj/item/clothing/gloves/grey + gloves["rainbow gloves"] = /obj/item/clothing/gloves/rainbow + gear_tweaks += new/datum/gear_tweak/path(gloves) diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/client/preference_setup/loadout/loadout_head.dm new file mode 100644 index 00000000000..081b6536564 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_head.dm @@ -0,0 +1,113 @@ +/datum/gear/head + display_name = "hat, boatsman" + path = /obj/item/clothing/head/boaterhat + slot = slot_head + sort_category = "Hats and Headwear" + +/datum/gear/head/bandana + display_name = "bandana selection" + path = /obj/item/clothing/head/bandana + +/datum/gear/head/bandana/New() + ..() + var/bandanas = list() + bandanas["green bandana"] = /obj/item/clothing/head/greenbandana + bandanas["orange bandana"] = /obj/item/clothing/head/orangebandana + bandanas["pirate bandana"] = /obj/item/clothing/head/bandana + gear_tweaks += new/datum/gear_tweak/path(bandanas) + +/datum/gear/head/cap + display_name = "cap selection" + path = /obj/item/clothing/head/soft/blue + +/datum/gear/head/cap/New() + ..() + var/caps = list() + caps["blue cap"] = /obj/item/clothing/head/soft/blue + caps["flat cap"] = /obj/item/clothing/head/flatcap + caps["green cap"] = /obj/item/clothing/head/soft/green + caps["grey cap"] = /obj/item/clothing/head/soft/grey + caps["mailman cap"] = /obj/item/clothing/head/mailman + caps["orange cap"] = /obj/item/clothing/head/soft/orange + caps["purple cap"] = /obj/item/clothing/head/soft/purple + caps["rainbow cap"] = /obj/item/clothing/head/soft/rainbow + caps["red cap"] = /obj/item/clothing/head/soft/red + caps["white cap"] = /obj/item/clothing/head/soft/mime + caps["yellow cap"] = /obj/item/clothing/head/soft/yellow + gear_tweaks += new/datum/gear_tweak/path(caps) + +/datum/gear/head/beret + display_name = "beret, red" + path = /obj/item/clothing/head/beret + +/datum/gear/head/beret/eng + display_name = "beret, engie-orange" + path = /obj/item/clothing/head/beret/engineering + allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") + +/datum/gear/head/beret/purp + display_name = "beret, purple" + path = /obj/item/clothing/head/beret/purple + +/datum/gear/head/beret/sec + display_name = "beret,security" + path = /obj/item/clothing/head/beret/sec + allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") + +/datum/gear/head/beret/warden + display_name = "beret,security (warden)" + path = /obj/item/clothing/head/beret/sec/warden + allowed_roles = list("Head of Security","Warden") + +/datum/gear/head/beret/hos + display_name = "beret,security (head of security)" + path = /obj/item/clothing/head/beret/sec/hos + allowed_roles = list("Head of Security") + +/datum/gear/head/cap/corp + display_name = "cap, corporate (security)" + path = /obj/item/clothing/head/soft/sec/corp + allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") + +/datum/gear/head/cap/sec + display_name = "cap, security" + path = /obj/item/clothing/head/soft/sec + allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") + +/datum/gear/head/hardhat + display_name = "hardhat, yellow" + path = /obj/item/clothing/head/hardhat + allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") + +/datum/gear/head/hardhat/New() + ..() + var/hardhat = list() + hardhat["hardhat, yellow"] = /obj/item/clothing/head/hardhat + hardhat["hardhat, blue"] = /obj/item/clothing/head/hardhat/dblue + hardhat["hardhat, orange"] = /obj/item/clothing/head/hardhat/orange + hardhat["hardhat, red"] = /obj/item/clothing/head/hardhat/red + gear_tweaks += new/datum/gear_tweak/path(hardhat) + +/datum/gear/head/hairflower + display_name = "hair flower pin, red" + path = /obj/item/clothing/head/hairflower + +/datum/gear/head/bowler + display_name = "hat, bowler" + path = /obj/item/clothing/head/bowler + +/datum/gear/head/fez + display_name = "hat, fez" + path = /obj/item/clothing/head/fez + +/datum/gear/head/tophat + display_name = "hat, tophat" + path = /obj/item/clothing/head/that + +/datum/gear/head/philosopher_wig + display_name = "natural philosopher's wig" + path = /obj/item/clothing/head/philosopher_wig + +/datum/gear/head/ushanka + display_name = "ushanka" + path = /obj/item/clothing/head/ushanka diff --git a/code/modules/client/preference_setup/loadout/loadout_mask.dm b/code/modules/client/preference_setup/loadout/loadout_mask.dm new file mode 100644 index 00000000000..c6342904f67 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_mask.dm @@ -0,0 +1,5 @@ +// Mask +/datum/gear/mask + display_name = "sterile mask" + path = /obj/item/clothing/mask/surgical + cost = 2 diff --git a/code/modules/client/preference_setup/loadout/loadout_shoes.dm b/code/modules/client/preference_setup/loadout/loadout_shoes.dm new file mode 100644 index 00000000000..473714a5b81 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_shoes.dm @@ -0,0 +1,45 @@ +// Shoelocker +/datum/gear/shoes + display_name = "jackboots" + path = /obj/item/clothing/shoes/jackboots + slot = slot_shoes + sort_category = "Shoes and Footwear" + +/datum/gear/shoes/toeless + display_name = "toe-less jackboots" + path = /obj/item/clothing/shoes/jackboots/unathi + +/datum/gear/shoes/workboots + display_name = "workboots" + path = /obj/item/clothing/shoes/workboots + +/datum/gear/shoes/sandals + display_name = "sandals" + path = /obj/item/clothing/shoes/sandal + +/datum/gear/shoes/color + display_name = "shoe selection" + path = /obj/item/clothing/shoes/black + +/datum/gear/shoes/color/New() + ..() + var/shoes = list() + shoes["black shoes"] = /obj/item/clothing/shoes/black + shoes["blue shoes"] = /obj/item/clothing/shoes/blue + shoes["brown shoes"] = /obj/item/clothing/shoes/brown + shoes["green shoes"] = /obj/item/clothing/shoes/green + shoes["orange shoes"] = /obj/item/clothing/shoes/orange + shoes["purple shoes"] = /obj/item/clothing/shoes/purple + shoes["rainbow shoes"] = /obj/item/clothing/shoes/rainbow + shoes["red shoes"] = /obj/item/clothing/shoes/red + shoes["white shoes"] = /obj/item/clothing/shoes/white + shoes["yellow shoes"] = /obj/item/clothing/shoes/yellow + gear_tweaks += new/datum/gear_tweak/path(shoes) + +/datum/gear/shoes/dress + display_name = "shoes, dress" + path = /obj/item/clothing/shoes/laceup + +/datum/gear/shoes/leather + display_name = "shoes, leather" + path = /obj/item/clothing/shoes/leather diff --git a/code/modules/client/preference_setup/loadout/loadout_smoking.dm b/code/modules/client/preference_setup/loadout/loadout_smoking.dm new file mode 100644 index 00000000000..d41c0d44c18 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_smoking.dm @@ -0,0 +1,27 @@ +/datum/gear/smokingpipe + display_name = "pipe, smoking" + path = /obj/item/clothing/mask/smokable/pipe + +/datum/gear/cornpipe + display_name = "pipe, corn" + path = /obj/item/clothing/mask/smokable/pipe/cobpipe + +/datum/gear/matchbook + display_name = "matchbook" + path = /obj/item/weapon/storage/box/matches + +/datum/gear/zippo + display_name = "zippo" + path = /obj/item/weapon/flame/lighter/zippo + +/datum/gear/cigarcase + display_name = "cigar case" + path = /obj/item/weapon/storage/fancy/cigar + +/datum/gear/cigarette + display_name = "cigarette packet" + path = /obj/item/weapon/storage/fancy/cigarettes + +/datum/gear/dromedaryco + display_name = "dromedaryco cigarette packet" + path = /obj/item/weapon/storage/fancy/cigarettes/dromedaryco \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm new file mode 100644 index 00000000000..2973900b7c2 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm @@ -0,0 +1,129 @@ +// Suit slot +/datum/gear/suit + display_name = "apron, blue" + path = /obj/item/clothing/suit/apron + slot = slot_wear_suit + sort_category = "Suits and Overwear" + cost = 2 + +/datum/gear/suit/leather + display_name = "jacket selection" + path = /obj/item/clothing/suit/storage/leather_jacket + +/datum/gear/suit/leather/New() + ..() + var/jackets = list() + jackets["bomber jacket"] = /obj/item/clothing/suit/storage/toggle/bomber + jackets["corporate black jacket"] = /obj/item/clothing/suit/storage/leather_jacket/nanotrasen + jackets["corporate brown jacket"] = /obj/item/clothing/suit/storage/toggle/brown_jacket/nanotrasen + jackets["black jacket"] = /obj/item/clothing/suit/storage/leather_jacket + jackets["brown jacket"] = /obj/item/clothing/suit/storage/toggle/brown_jacket + gear_tweaks += new/datum/gear_tweak/path(jackets) + +/datum/gear/suit/hazard_vest + display_name = "hazard vest" + path = /obj/item/clothing/suit/storage/hazardvest + +/datum/gear/suit/hoodie + display_name = "hoodie, grey" + path = /obj/item/clothing/suit/storage/toggle/hoodie + +/datum/gear/suit/hoodie/black + display_name = "hoodie, black" + path = /obj/item/clothing/suit/storage/toggle/hoodie/black + +/datum/gear/suit/labcoat + display_name = "labcoat selection" + path = /obj/item/clothing/suit/storage/toggle/labcoat + +/datum/gear/suit/labcoat/New() + ..() + var/labcoat = list() + labcoat["labcoat"] = /obj/item/clothing/suit/storage/toggle/labcoat + labcoat["labcoat, blue"] = /obj/item/clothing/suit/storage/toggle/labcoat/blue + labcoat["labcoat, green"] = /obj/item/clothing/suit/storage/toggle/labcoat/green + labcoat["labcoat, orange"] = /obj/item/clothing/suit/storage/toggle/labcoat/orange + labcoat["labcoat, purple"] = /obj/item/clothing/suit/storage/toggle/labcoat/purple + labcoat["labcoat, red"] = /obj/item/clothing/suit/storage/toggle/labcoat/red + gear_tweaks += new/datum/gear_tweak/path(labcoat) + +/datum/gear/suit/overalls + display_name = "overalls" + path = /obj/item/clothing/suit/apron/overalls + cost = 1 + +/datum/gear/suit/poncho + display_name = "poncho selection" + path = /obj/item/clothing/suit/poncho + cost = 1 + +/datum/gear/suit/poncho/New() + ..() + var/poncho = list() + poncho["poncho, tan"] = /obj/item/clothing/suit/poncho + poncho["poncho, blue"] = /obj/item/clothing/suit/poncho/blue + poncho["poncho, green"] = /obj/item/clothing/suit/poncho/green + poncho["poncho, purple"] = /obj/item/clothing/suit/poncho/purple + poncho["poncho, red"] = /obj/item/clothing/suit/poncho/red + gear_tweaks += new/datum/gear_tweak/path(poncho) + +/datum/gear/suit/blue_lawyer_jacket + display_name = "suit jacket, blue" + path = /obj/item/clothing/suit/storage/toggle/lawyer/bluejacket + +/datum/gear/suit/purple_lawyer_jacket + display_name = "suit jacket, purple" + path = /obj/item/clothing/suit/storage/lawyer/purpjacket + +/datum/gear/suit/track_jacket + display_name = "track jacket" + path = /obj/item/clothing/suit/storage/toggle/tracksuit + +/datum/gear/suit/winter + display_name = "winter coat" + path = /obj/item/clothing/suit/storage/hooded/wintercoat + +/datum/gear/suit/winter/captain + display_name = "winter coat, captain" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/captain + allowed_roles = list("Captain") + +/datum/gear/suit/winter/security + display_name = "winter coat, security" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/security + allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") + +/datum/gear/suit/winter/science + display_name = "winter coat, science" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/science + allowed_roles = list("Research Director","Scientist","Xenobiologist","Roboticist","Lab Assistant","Geneticist") + +/datum/gear/suit/winter/medical + display_name = "winter coat, medical" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/medical + allowed_roles = list("Chief Medical Officer","Medical Doctor","Paramedic","Nursing Intern","Psychiatrist","Chemist",) + +/datum/gear/suit/winter/engineering + display_name = "winter coat, engineering" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/engineering + allowed_roles = list("Station Engineer","Chief Engineer","Engineering Apprentice") + +/datum/gear/suit/winter/atmos + display_name = "winter coat, atmospherics" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/engineering/atmos + allowed_roles = list("Atmospheric Technician","Chief Engineer") + +/datum/gear/suit/winter/hydro + display_name = "winter coat, hydroponics" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/hydro + allowed_roles = list("Head of Personnel","Gardener") + +/datum/gear/suit/winter/cargo + display_name = "winter coat, cargo" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/cargo + allowed_roles = list("Cargo Technician","Quartermaster","Head of Personnel") + +/datum/gear/suit/winter/mining + display_name = "winter coat, mining" + path = /obj/item/clothing/suit/storage/hooded/wintercoat/miner + allowed_roles = list("Quartermaster","Head of Personnel","Shaft Miner") \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm new file mode 100644 index 00000000000..22705c17560 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm @@ -0,0 +1,150 @@ +// Uniform slot +/datum/gear/uniform + display_name = "blazer, blue" + path = /obj/item/clothing/under/blazer + slot = slot_w_uniform + sort_category = "Uniforms and Casual Dress" + +/datum/gear/uniform/cheongsam + display_name = "cheongsam, white" + path = /obj/item/clothing/under/cheongsam + +/datum/gear/uniform/kilt + display_name = "kilt" + path = /obj/item/clothing/under/kilt + +/datum/gear/uniform/jumpskirt + display_name = "jumpskirt, black" + path = /obj/item/clothing/under/blackjumpskirt + +/datum/gear/uniform/jumpsuit + display_name = "generic jumpsuits" + path = /obj/item/clothing/under/color/grey + +/datum/gear/uniform/jumpsuit/New() + ..() + var/jumpsuit = list() + jumpsuit["grey jumpsuit"] = /obj/item/clothing/under/color/grey + jumpsuit["black jumpsuit"] = /obj/item/clothing/under/color/black + jumpsuit["blue jumpsuit"] = /obj/item/clothing/under/color/blue + jumpsuit["green jumpsuit"] = /obj/item/clothing/under/color/green + jumpsuit["orange jumpsuit"] = /obj/item/clothing/under/color/orange + jumpsuit["pink jumpsuit"] = /obj/item/clothing/under/color/pink + jumpsuit["red jumpsuit"] = /obj/item/clothing/under/color/red + jumpsuit["white jumpsuit"] = /obj/item/clothing/under/color/white + jumpsuit["yellow jumpsuit"] = /obj/item/clothing/under/color/yellow + jumpsuit["light blue jumpsuit"] = /obj/item/clothing/under/lightblue + jumpsuit["aqua jumpsuit"] = /obj/item/clothing/under/aqua + jumpsuit["purple jumpsuit"] = /obj/item/clothing/under/purple + jumpsuit["light purple jumpsuit"] = /obj/item/clothing/under/lightpurple + jumpsuit["light green jumpsuit"] = /obj/item/clothing/under/lightgreen + jumpsuit["brown jumpsuit"] = /obj/item/clothing/under/brown + jumpsuit["light brown jumpsuit"] = /obj/item/clothing/under/lightbrown + jumpsuit["yellow green jumpsuit"] = /obj/item/clothing/under/yellowgreen + jumpsuit["light red jumpsuit"] = /obj/item/clothing/under/lightred + jumpsuit["dark red jumpsuit"] = /obj/item/clothing/under/darkred + gear_tweaks += new/datum/gear_tweak/path(jumpsuit) + +/datum/gear/uniform/skirt + display_name = "plaid skirt, blue" + path = /obj/item/clothing/under/dress/plaid_blue + +/datum/gear/uniform/skirt/purple + display_name = "plaid skirt, purple" + path = /obj/item/clothing/under/dress/plaid_purple + +/datum/gear/uniform/skirt/red + display_name = "plaid skirt, red" + path = /obj/item/clothing/under/dress/plaid_red + +/datum/gear/uniform/suit + display_name = "suit selection" + path = /obj/item/clothing/under/lawyer/bluesuit + +/datum/gear/uniform/suit/New() + ..() + var/suits = list() + suits["amish suit"] = /obj/item/clothing/under/sl_suit + suits["black suit"] = /obj/item/clothing/under/suit_jacket + suits["blue suit"] = /obj/item/clothing/under/lawyer/blue + suits["burgundy suit"] = /obj/item/clothing/under/suit_jacket/burgundy + suits["charcoal suit"] = /obj/item/clothing/under/suit_jacket/charcoal + suits["checkered suit"] = /obj/item/clothing/under/suit_jacket/checkered + suits["executive suit"] = /obj/item/clothing/under/suit_jacket/really_black + suits["female executive suit"] = /obj/item/clothing/under/suit_jacket/female + suits["gentleman suit"] = /obj/item/clothing/under/gentlesuit + suits["navy suit"] = /obj/item/clothing/under/suit_jacket/navy + suits["old man suit"] = /obj/item/clothing/under/lawyer/oldman + suits["purple suit"] = /obj/item/clothing/under/lawyer/purpsuit + suits["red suit"] = /obj/item/clothing/under/suit_jacket/red + suits["red lawyer suit"] = /obj/item/clothing/under/lawyer/red + suits["shiny black suit"] = /obj/item/clothing/under/lawyer/black + suits["tan suit"] = /obj/item/clothing/under/suit_jacket/tan + suits["white suit"] = /obj/item/clothing/under/scratch + suits["white-blue suit"] = /obj/item/clothing/under/lawyer/bluesuit + gear_tweaks += new/datum/gear_tweak/path(suits) + +/datum/gear/uniform/scrubs + display_name = "scrubs selection" + path = /obj/item/clothing/under/rank/medical/black + allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective",) + +/datum/gear/uniform/scrubs/New() + ..() + var/scrubs = list() + scrubs["scrubs, black"] = /obj/item/clothing/under/rank/medical/black + scrubs["scrubs, blue"] = /obj/item/clothing/under/rank/medical/blue + scrubs["scrubs, green"] = /obj/item/clothing/under/rank/medical/green + scrubs["scrubs, purple"] = /obj/item/clothing/under/rank/medical/purple + gear_tweaks += new/datum/gear_tweak/path(scrubs) + +/datum/gear/uniform/sundress + display_name = "sundress" + path = /obj/item/clothing/under/sundress + +/datum/gear/uniform/sundress/white + display_name = "sundress, white" + path = /obj/item/clothing/under/sundress_white + +/datum/gear/uniform/dress_fire + display_name = "flame dress" + path = /obj/item/clothing/under/dress/dress_fire + +/datum/gear/uniform/uniform_captain + display_name = "uniform, captain's dress" + path = /obj/item/clothing/under/dress/dress_cap + allowed_roles = list("Captain") + +/datum/gear/uniform/corpsecsuit + display_name = "uniform, corporate (Security)" + path = /obj/item/clothing/under/rank/security/corp + allowed_roles = list("Security Officer","Head of Security","Warden") + +/datum/gear/uniform/uniform_hop + display_name = "uniform, HoP's dress" + path = /obj/item/clothing/under/dress/dress_hop + allowed_roles = list("Head of Personnel") + +/datum/gear/uniform/uniform_hr + display_name = "uniform, HR director (HoP)" + path = /obj/item/clothing/under/dress/dress_hr + allowed_roles = list("Head of Personnel") + +/datum/gear/uniform/navysecsuit + display_name = "uniform, navyblue (Security)" + path = /obj/item/clothing/under/rank/security/navyblue + allowed_roles = list("Security Officer","Head of Security","Warden") + +/datum/gear/uniform/gearharness + display_name = "gear harness" + path = /obj/item/clothing/under/gearharness + cost = 2 + +/datum/gear/uniform/track_pants + display_name = "track pants" + path = /obj/item/clothing/under/track + +/datum/gear/uniform/turtleneck + display_name = "tacticool turtleneck" + path = /obj/item/clothing/under/syndicate/tacticool + diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm new file mode 100644 index 00000000000..6fd34e628c3 --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -0,0 +1,55 @@ +/datum/gear/utility + display_name = "briefcase" + path = /obj/item/weapon/storage/briefcase + sort_category = "Utility" + +/datum/gear/utility/secure + display_name = "secure briefcase" + path = /obj/item/weapon/storage/secure/briefcase + cost = 2 + +/datum/gear/utility/clipboard + display_name = "clipboard" + path = /obj/item/weapon/clipboard + +/datum/gear/utility/folder + display_name = "folders" + path = /obj/item/weapon/folder + +/datum/gear/utility/folder/New() + ..() + var/folders = list() + folders["blue folder"] = /obj/item/weapon/folder/blue + folders["grey folder"] = /obj/item/weapon/folder + folders["red folder"] = /obj/item/weapon/folder/red + folders["white folder"] = /obj/item/weapon/folder/white + folders["yellow folder"] = /obj/item/weapon/folder/yellow + gear_tweaks += new/datum/gear_tweak/path(folders) + +/datum/gear/utility/paicard + display_name = "personal AI device" + path = /obj/item/device/paicard + +/datum/gear/utility/wallet + display_name = "wallet" + path = /obj/item/weapon/storage/wallet + +/* +/datum/gear/utility/cheaptablet + display_name = "cheap tablet computer" + path = /obj/item/modular_computer/tablet/preset/custom_loadout/cheap + cost = 3 + +/datum/gear/utility/normaltablet + display_name = "tablet computer" + path = /obj/item/modular_computer/tablet/preset/custom_loadout/advanced + cost = 4 +*/ + +/datum/gear/utility/recorder + display_name = "universal recorder" + path = /obj/item/device/taperecorder + +/datum/gear/utility/camera + display_name = "camera" + path = /obj/item/device/camera diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm new file mode 100644 index 00000000000..6ee001c5ace --- /dev/null +++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm @@ -0,0 +1,108 @@ +//unathi clothing + +/datum/gear/suit/unathi_mantle + display_name = "hide mantle (Unathi)" + path = /obj/item/clothing/suit/unathi/mantle + cost = 1 + whitelisted = "Unathi" + sort_category = "Xenowear" + +/datum/gear/suit/unathi_robe + display_name = "roughspun robe (Unathi)" + path = /obj/item/clothing/suit/unathi/robe + cost = 1 + whitelisted = "Unathi" + sort_category = "Xenowear" + +//skrell headtail adorns + +/datum/gear/ears/f_skrell + display_name = "headtail-wear, female (Skrell)" + path = /obj/item/clothing/ears/skrell/chain + sort_category = "Xenowear" + whitelisted = "Skrell" + +/datum/gear/ears/f_skrell/New() + ..() + var/f_chains = list() + f_chains["headtail chains"] = /obj/item/clothing/ears/skrell/chain + f_chains["headtail cloth"] = /obj/item/clothing/ears/skrell/cloth_female + f_chains["red-jeweled chain"] = /obj/item/clothing/ears/skrell/redjewel_chain + f_chains["ebony chain"] = /obj/item/clothing/ears/skrell/ebony_chain + f_chains["blue-jeweled chain"] = /obj/item/clothing/ears/skrell/bluejeweled_chain + f_chains["silver chain"] = /obj/item/clothing/ears/skrell/silver_chain + f_chains["blue cloth"] = /obj/item/clothing/ears/skrell/blue_skrell_cloth_band_female + gear_tweaks += new/datum/gear_tweak/path(f_chains) + +/datum/gear/ears/m_skrell + display_name = "headtail-wear, male (Skrell)" + path = /obj/item/clothing/ears/skrell/band + sort_category = "Xenowear" + whitelisted = "Skrell" + +/datum/gear/ears/m_skrell/New() + ..() + var/m_chains = list() + m_chains["headtail bands"] = /obj/item/clothing/ears/skrell/chain + m_chains["headtail cloth"] = /obj/item/clothing/ears/skrell/cloth_male + m_chains["red-jeweled bands"] = /obj/item/clothing/ears/skrell/redjeweled_band + m_chains["ebony bands"] = /obj/item/clothing/ears/skrell/ebony_band + m_chains["blue-jeweled bands"] = /obj/item/clothing/ears/skrell/bluejeweled_band + m_chains["silver bands"] = /obj/item/clothing/ears/skrell/silver_band + m_chains["blue cloth"] = /obj/item/clothing/ears/skrell/blue_skrell_cloth_band_male + gear_tweaks += new/datum/gear_tweak/path(m_chains) + +//vaurca items + +/datum/gear/eyes/blindfold + display_name = "vaurca blindfold (Vaurca)" + path = /obj/item/clothing/glasses/sunglasses/blinders + cost = 2 + whitelisted = "Vaurca" + sort_category = "Xenowear" + +/datum/gear/mask/vaurca + display_name = "mandible garment (Vaurca)" + path = /obj/item/clothing/mask/breath/vaurca + cost = 1 + whitelisted = "Vaurca" + sort_category = "Xenowear" + +//beastmen gloves + +/datum/gear/gloves/unathi + display_name = "gloves selection (Unathi)" + path = /obj/item/clothing/gloves/black/unathi + whitelisted = "Unathi" + sort_category = "Xenowear" + +/datum/gear/gloves/unathi/New() + ..() + var/un_gloves = list() + un_gloves["black gloves"] = /obj/item/clothing/gloves/black/unathi + un_gloves["red gloves"] = /obj/item/clothing/gloves/red/unathi + un_gloves["blue gloves"] = /obj/item/clothing/gloves/blue/unathi + un_gloves["orange gloves"] = /obj/item/clothing/gloves/orange/unathi + un_gloves["purple gloves"] = /obj/item/clothing/gloves/purple/unathi + un_gloves["brown gloves"] = /obj/item/clothing/gloves/brown/unathi + un_gloves["green gloves"] = /obj/item/clothing/gloves/green/unathi + un_gloves["white gloves"] = /obj/item/clothing/gloves/white/unathi + gear_tweaks += new/datum/gear_tweak/path(un_gloves) + +/datum/gear/gloves/tajara + display_name = "gloves selection (Tajara)" + path = /obj/item/clothing/gloves/black/tajara + whitelisted = "Tajara" + sort_category = "Xenowear" + +/datum/gear/gloves/tajara/New() + ..() + var/taj_gloves = list() + taj_gloves["black gloves"] = /obj/item/clothing/gloves/black/tajara + taj_gloves["red gloves"] = /obj/item/clothing/gloves/red/tajara + taj_gloves["blue gloves"] = /obj/item/clothing/gloves/blue/tajara + taj_gloves["orange gloves"] = /obj/item/clothing/gloves/orange/tajara + taj_gloves["purple gloves"] = /obj/item/clothing/gloves/purple/tajara + taj_gloves["brown gloves"] = /obj/item/clothing/gloves/brown/tajara + taj_gloves["white gloves"] = /obj/item/clothing/gloves/green/tajara + gear_tweaks += new/datum/gear_tweak/path(taj_gloves) diff --git a/code/modules/client/preference_setup/preference_setup.dm b/code/modules/client/preference_setup/preference_setup.dm index 237c4fa0a78..99af44e65eb 100644 --- a/code/modules/client/preference_setup/preference_setup.dm +++ b/code/modules/client/preference_setup/preference_setup.dm @@ -27,6 +27,11 @@ sort_order = 4 category_item_type = /datum/category_item/player_setup_item/antagonism +/datum/category_group/player_setup_category/loadout_preferences + name = "Loadout" + sort_order = 5 + category_item_type = /datum/category_item/player_setup_item/loadout + /datum/category_group/player_setup_category/global_preferences name = "Global" sort_order = 5 diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 036df67ecd1..5455a4370ed 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -125,6 +125,10 @@ datum/preferences // OOC Metadata: var/metadata = "" + // SPAAAACE + var/parallax_speed = 2 + var/parallax_togs = PARALLAX_SPACE + var/list/pai = list() // A list for holding pAI related data. var/client/client = null diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm deleted file mode 100644 index d355926c873..00000000000 --- a/code/modules/client/preferences_gear.dm +++ /dev/null @@ -1,1546 +0,0 @@ -var/global/list/gear_datums = list() - -/hook/startup/proc/populate_gear_list() - var/list/sort_categories = list( - "[slot_head]" = list(), - "ears" = list(), - "[slot_glasses]" = list(), - "[slot_wear_mask]" = list(), - "[slot_w_uniform]" = list(), - "[slot_tie]" = list(), - "[slot_wear_suit]" = list(), - "[slot_gloves]" = list(), - "[slot_shoes]" = list(), - "utility" = list(), - "misc" = list(), - "unknown" = list() - ) - - //create a list of gear datums to sort - for(var/type in typesof(/datum/gear)-/datum/gear) - var/datum/gear/G = type - if(!initial(G.display_name)) - error("Loadout - Missing display name: [G]") - continue - if(!initial(G.cost)) - error("Loadout - Missing cost: [G]") - continue - if(!initial(G.path)) - error("Loadout - Missing path definition: [G]") - continue - G = new G() - - var/category = (G.sort_category in sort_categories)? G.sort_category : "unknown" - sort_categories[category][G.display_name] = G - - for (var/category in sort_categories) - gear_datums.Add(sortAssoc(sort_categories[category])) - - return 1 - -/datum/gear - var/display_name //Name/index. Must be unique. - var/path //Path to item. - var/cost //Number of points used. Items in general cost 1 point, storage/armor/gloves/special use costs 2 points. - var/slot //Slot to equip to. - var/list/allowed_roles //Roles that can spawn with this item. - var/whitelisted //Term to check the whitelist for.. - var/sort_category - -/datum/gear/New() - ..() - if (!sort_category) - sort_category = "[slot]" - -// This is sorted both by slot and alphabetically! Don't fuck it up! -// Headslot items - -/datum/gear/gbandana - display_name = "bandana, green" - path = /obj/item/clothing/head/greenbandana - cost = 1 - slot = slot_head - -/datum/gear/obandana - display_name = "bandana, orange" - path = /obj/item/clothing/head/orangebandana - cost = 1 - slot = slot_head - -/datum/gear/bandana - display_name = "bandana, pirate-red" - path = /obj/item/clothing/head/bandana - cost = 1 - slot = slot_head - -/datum/gear/bsec_beret - display_name = "beret, navy (officer)" - path = /obj/item/clothing/head/beret/sec - cost = 1 - slot = slot_head - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -/datum/gear/bsec_beret_warden - display_name = "beret, navy (warden)" - path = /obj/item/clothing/head/beret/sec/warden - cost = 1 - slot = slot_head - allowed_roles = list("Head of Security","Warden") - -/datum/gear/bsec_beret_hos - display_name = "beret, navy (hos)" - path = /obj/item/clothing/head/beret/sec/hos - cost = 1 - slot = slot_head - allowed_roles = list("Head of Security") - -/datum/gear/eng_beret - display_name = "beret, engie-orange" - path = /obj/item/clothing/head/beret/engineering - cost = 1 - slot = slot_head - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/purp_beret - display_name = "beret, purple" - path = /obj/item/clothing/head/beret/purple - cost = 1 - slot = slot_head - -/datum/gear/red_beret - display_name = "beret, red" - path = /obj/item/clothing/head/beret - cost = 1 - slot = slot_head - -/datum/gear/sec_beret - display_name = "beret, security" - path = /obj/item/clothing/head/beret/sec - cost = 1 - slot = slot_head - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -/datum/gear/bcap - display_name = "cap, blue" - path = /obj/item/clothing/head/soft/blue - cost = 1 - slot = slot_head - -/datum/gear/mailman - display_name = "cap, blue station" - path = /obj/item/clothing/head/mailman - cost = 1 - slot = slot_head - -/datum/gear/flatcap - display_name = "cap, brown-flat" - path = /obj/item/clothing/head/flatcap - cost = 1 - slot = slot_head - -/datum/gear/corpcap - display_name = "cap, corporate (Security)" - path = /obj/item/clothing/head/soft/sec/corp - cost = 1 - slot = slot_head - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -/datum/gear/gcap - display_name = "cap, green" - path = /obj/item/clothing/head/soft/green - cost = 1 - slot = slot_head - -/datum/gear/grcap - display_name = "cap, grey" - path = /obj/item/clothing/head/soft/grey - cost = 1 - slot = slot_head - -/datum/gear/ocap - display_name = "cap, orange" - path = /obj/item/clothing/head/soft/orange - cost = 1 - slot = slot_head - -/datum/gear/purcap - display_name = "cap, purple" - path = /obj/item/clothing/head/soft/purple - cost = 1 - slot = slot_head - -/datum/gear/raincap - display_name = "cap, rainbow" - path = /obj/item/clothing/head/soft/rainbow - cost = 1 - slot = slot_head - -/datum/gear/rcap - display_name = "cap, red" - path = /obj/item/clothing/head/soft/red - cost = 1 - slot = slot_head - -/datum/gear/ycap - display_name = "cap, yellow" - path = /obj/item/clothing/head/soft/yellow - cost = 1 - slot = slot_head - -/datum/gear/wcap - display_name = "cap, white" - path = /obj/item/clothing/head/soft/mime - cost = 1 - slot = slot_head - -/datum/gear/hairflower - display_name = "hair flower pin" - path = /obj/item/clothing/head/hairflower - cost = 1 - slot = slot_head - -/datum/gear/dbhardhat - display_name = "hardhat, blue" - path = /obj/item/clothing/head/hardhat/dblue - cost = 2 - slot = slot_head - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/ohardhat - display_name = "hardhat, orange" - path = /obj/item/clothing/head/hardhat/orange - cost = 2 - slot = slot_head - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/rhardhat - display_name = "hardhat, red" - path = /obj/item/clothing/head/hardhat/red - cost = 2 - slot = slot_head - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/yhardhat - display_name = "hardhat, yellow" - path = /obj/item/clothing/head/hardhat - cost = 2 - slot = slot_head - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/boater - display_name = "hat, boatsman" - path = /obj/item/clothing/head/boaterhat - cost = 1 - slot = slot_head - -/datum/gear/bowler - display_name = "hat, bowler" - path = /obj/item/clothing/head/bowler - cost = 1 - slot = slot_head - -/datum/gear/fez - display_name = "hat, fez" - path = /obj/item/clothing/head/fez - cost = 1 - slot = slot_head - -/datum/gear/tophat - display_name = "hat, tophat" - path = /obj/item/clothing/head/that - cost = 1 - slot = slot_head - -// Wig by Earthcrusher, blame him. -/datum/gear/philosopher_wig - display_name = "natural philosopher's wig" - path = /obj/item/clothing/head/philosopher_wig - cost = 1 - slot = slot_head - -/datum/gear/ushanka - display_name = "ushanka" - path = /obj/item/clothing/head/ushanka - cost = 1 - slot = slot_head - -//lol fuck bay ~LordFowl -/datum/gear/zhan_scarf - display_name = "Zhan headscarf" - path = /obj/item/clothing/head/tajaran/scarf - cost = 1 - slot = slot_head - whitelisted = "Tajara" - -// Eyes - -/datum/gear/eyepatch - display_name = "eyepatch" - path = /obj/item/clothing/glasses/eyepatch - cost = 1 - slot = slot_glasses - -/datum/gear/green_glasses - display_name = "glasses, green" - path = /obj/item/clothing/glasses/gglasses - cost = 1 - slot = slot_glasses - -/datum/gear/prescriptionhipster - display_name = "glasses, hipster" - path = /obj/item/clothing/glasses/regular/hipster - cost = 1 - slot = slot_glasses - -/datum/gear/prescription - display_name = "glasses, prescription" - path = /obj/item/clothing/glasses/regular - cost = 1 - slot = slot_glasses - -/datum/gear/monocle - display_name = "monocle" - path = /obj/item/clothing/glasses/monocle - cost = 1 - slot = slot_glasses - -/datum/gear/scanning_goggles - display_name = "scanning goggles" - path = /obj/item/clothing/glasses/regular/scanners - cost = 1 - slot = slot_glasses - -/datum/gear/sciencegoggles - display_name = "science Goggles" - path = /obj/item/clothing/glasses/science - cost = 1 - slot = slot_glasses - -/datum/gear/security - display_name = "security HUD" - path = /obj/item/clothing/glasses/hud/security - cost = 1 - slot = slot_glasses - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -/datum/gear/thugshades - display_name = "sunglasses, fat" - path = /obj/item/clothing/glasses/sunglasses/big - cost = 1 - slot = slot_glasses - allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain","Security Cadet") - -/datum/gear/prescriptionsun - display_name = "sunglasses, presciption" - path = /obj/item/clothing/glasses/sunglasses/prescription - cost = 2 - slot = slot_glasses - allowed_roles = list("Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain","Security Cadet") - -/datum/gear/blindfold - display_name = "vaurca blindfold" - path = /obj/item/clothing/glasses/sunglasses/blinders - cost = 2 - slot = slot_glasses - whitelisted = "Vaurca" - -// Mask - -/datum/gear/sterilemask - display_name = "sterile mask" - path = /obj/item/clothing/mask/surgical - slot = slot_wear_mask - cost = 2 - -// Uniform slot - -/datum/gear/blazer_blue - display_name = "blazer, blue" - path = /obj/item/clothing/under/blazer - slot = slot_w_uniform - cost = 1 - -/datum/gear/cheongsam - display_name = "cheongsam, white" - path = /obj/item/clothing/under/cheongsam - slot = slot_w_uniform - cost = 1 - -/datum/gear/gearharness - display_name = "gear harness" - path = /obj/item/clothing/under/gearharness - slot = slot_w_uniform - cost = 2 - -/datum/gear/kilt - display_name = "kilt" - path = /obj/item/clothing/under/kilt - slot = slot_w_uniform - cost = 1 - -/datum/gear/track_pants - display_name = "track pants" - path = /obj/item/clothing/under/track - slot = slot_w_uniform - cost = 1 - -/datum/gear/blackjumpskirt - display_name = "jumpskirt, black" - path = /obj/item/clothing/under/blackjumpskirt - slot = slot_w_uniform - cost = 1 - -/datum/gear/blackfjumpsuit - display_name = "jumpsuit, female-black" - path = /obj/item/clothing/under/color/blackf - slot = slot_w_uniform - cost = 1 - -/datum/gear/blackfjumpsuit - display_name = "jumpsuit, rainbow" - path = /obj/item/clothing/under/rainbow - slot = slot_w_uniform - cost = 1 - -/datum/gear/skirt_blue - display_name = "plaid skirt, blue" - path = /obj/item/clothing/under/dress/plaid_blue - slot = slot_w_uniform - cost = 1 - -/datum/gear/skirt_purple - display_name = "plaid skirt, purple" - path = /obj/item/clothing/under/dress/plaid_purple - slot = slot_w_uniform - cost = 1 - -/datum/gear/skirt_red - display_name = "plaid skirt, red" - path = /obj/item/clothing/under/dress/plaid_red - slot = slot_w_uniform - cost = 1 - -/datum/gear/skirt_black - display_name = "skirt, black" - path = /obj/item/clothing/under/blackskirt - slot = slot_w_uniform - cost = 1 - -/datum/gear/amishsuit - display_name = "suit, amish" - path = /obj/item/clothing/under/sl_suit - slot = slot_w_uniform - cost = 1 - -/datum/gear/blacksuit - display_name = "suit, black" - path = /obj/item/clothing/under/suit_jacket - slot = slot_w_uniform - cost = 1 - -/datum/gear/shinyblacksuit - display_name = "suit, shiny-black" - path = /obj/item/clothing/under/lawyer/black - slot = slot_w_uniform - cost = 1 - -/datum/gear/bluesuit - display_name = "suit, blue" - path = /obj/item/clothing/under/lawyer/blue - slot = slot_w_uniform - cost = 1 - -/datum/gear/burgundysuit - display_name = "suit, burgundy" - path = /obj/item/clothing/under/suit_jacket/burgundy - slot = slot_w_uniform - cost = 1 - -/datum/gear/checkeredsuit - display_name = "suit, checkered" - path = /obj/item/clothing/under/suit_jacket/checkered - slot = slot_w_uniform - cost = 1 - -/datum/gear/charcoalsuit - display_name = "suit, charcoal" - path = /obj/item/clothing/under/suit_jacket/charcoal - slot = slot_w_uniform - cost = 1 - -/datum/gear/execsuit - display_name = "suit, executive" - path = /obj/item/clothing/under/suit_jacket/really_black - slot = slot_w_uniform - cost = 1 - -/datum/gear/femaleexecsuit - display_name = "suit, female-executive" - path = /obj/item/clothing/under/suit_jacket/female - slot = slot_w_uniform - cost = 1 - -/datum/gear/gentlesuit - display_name = "suit, gentlemen" - path = /obj/item/clothing/under/gentlesuit - slot = slot_w_uniform - cost = 1 - -/datum/gear/navysuit - display_name = "suit, navy" - path = /obj/item/clothing/under/suit_jacket/navy - slot = slot_w_uniform - cost = 1 - -/datum/gear/redsuit - display_name = "suit, red" - path = /obj/item/clothing/under/suit_jacket/red - slot = slot_w_uniform - cost = 1 - -/datum/gear/redlawyer - display_name = "suit, lawyer-red" - path = /obj/item/clothing/under/lawyer/red - slot = slot_w_uniform - cost = 1 - -/datum/gear/oldmansuit - display_name = "suit, old-man" - path = /obj/item/clothing/under/lawyer/oldman - slot = slot_w_uniform - cost = 1 - -/datum/gear/purplesuit - display_name = "suit, purple" - path = /obj/item/clothing/under/lawyer/purpsuit - slot = slot_w_uniform - cost = 1 - -/datum/gear/tansuit - display_name = "suit, tan" - path = /obj/item/clothing/under/suit_jacket/tan - slot = slot_w_uniform - cost = 1 - -/datum/gear/whitesuit - display_name = "suit, white" - path = /obj/item/clothing/under/scratch - slot = slot_w_uniform - cost = 1 - -/datum/gear/whitebluesuit - display_name = "suit, white-blue" - path = /obj/item/clothing/under/lawyer/bluesuit - slot = slot_w_uniform - cost = 1 - -/datum/gear/sundress - display_name = "sundress" - path = /obj/item/clothing/under/sundress - slot = slot_w_uniform - cost = 1 - -/datum/gear/sundress_white - display_name = "sundress, white" - path = /obj/item/clothing/under/sundress_white - slot = slot_w_uniform - cost = 1 - -/datum/gear/uniform_captain - display_name = "uniform, captain's dress" - path = /obj/item/clothing/under/dress/dress_cap - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Captain") - -/datum/gear/corpsecsuit - display_name = "uniform, corporate (Security)" - path = /obj/item/clothing/under/rank/security/corp - cost = 1 - slot = slot_w_uniform - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -/datum/gear/uniform_hop - display_name = "uniform, HoP's dress" - path = /obj/item/clothing/under/dress/dress_hop - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Head of Personnel") - -/datum/gear/uniform_hr - display_name = "uniform, HR director (HoP)" - path = /obj/item/clothing/under/dress/dress_hr - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Head of Personnel") - -/datum/gear/navysecsuit - display_name = "uniform, navyblue (Security)" - path = /obj/item/clothing/under/rank/security/navyblue - cost = 1 - slot = slot_w_uniform - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -//medical scrubs - -/datum/gear/bluescrub - display_name = "medical scrubs, blue" - path = /obj/item/clothing/under/rank/medical/blue - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective",) - -/datum/gear/greenscrub - display_name = "medical scrubs, green" - path = /obj/item/clothing/under/rank/medical/green - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective",) - -/datum/gear/purplescrub - display_name = "medical scrubs, purple" - path = /obj/item/clothing/under/rank/medical/purple - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective",) - -/datum/gear/blackscrub - display_name = "medical scrubs, black" - path = /obj/item/clothing/under/rank/medical/black - slot = slot_w_uniform - cost = 1 - allowed_roles = list("Scientist","Chief Medical Officer","Medical Doctor","Geneticist","Paramedic","Nursing Intern","Xenobiologist","Roboticist","Research Director","Detective",) - -// Attachments -/datum/gear/armband_cargo - display_name = "armband, cargo" - path = /obj/item/clothing/accessory/armband/cargo - slot = slot_tie - cost = 1 - allowed_roles = list("Cargo Technician","Quartermaster","Head of Personnel","Shaft Miner") - -/datum/gear/armband_emt - display_name = "armband, EMT" - path = /obj/item/clothing/accessory/armband/medgreen - slot = slot_tie - cost = 1 - allowed_roles = list("Paramedic","Chief Medical Officer") - -/datum/gear/armband_engineering - display_name = "armband, engineering" - path = /obj/item/clothing/accessory/armband/engine - slot = slot_tie - cost = 1 - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/armband_hydroponics - display_name = "armband, hydroponics" - path = /obj/item/clothing/accessory/armband/hydro - slot = slot_tie - cost = 1 - allowed_roles = list("Head of Personnel","Gardener") - -/datum/gear/armband_medical - display_name = "armband, medical" - path = /obj/item/clothing/accessory/armband/med - slot = slot_tie - cost = 1 - allowed_roles = list("Chief Medical Officer","Medical Doctor","Paramedic","Nursing Intern","Psychiatrist","Chemist",) - -/datum/gear/armband - display_name = "armband, red" - path = /obj/item/clothing/accessory/armband - slot = slot_tie - cost = 1 - -/datum/gear/armband_science - display_name = "armband, science" - path = /obj/item/clothing/accessory/armband/science - slot = slot_tie - cost = 1 - allowed_roles = list("Research Director","Scientist","Xenobiologist","Roboticist","Lab Assistant","Geneticist") - -/datum/gear/armband_movement - display_name = "armband, synthetic intelligence movement" - path = /obj/item/clothing/accessory/armband/movement - slot = slot_tie - cost = 1 - -/datum/gear/atlas - display_name = "armband, ATLAS" - path = /obj/item/clothing/accessory/armband/atlas - slot = slot_tie - cost = 1 - -/datum/gear/armpit - display_name = "holster, armpit" - path = /obj/item/clothing/accessory/holster/armpit - slot = slot_tie - cost = 1 - allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective","Security Cadet") - -/datum/gear/hip - display_name = "holster, hip" - path = /obj/item/clothing/accessory/holster/hip - slot = slot_tie - cost = 1 - allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective","Security Cadet") - -/datum/gear/waist - display_name = "holster, waist" - path = /obj/item/clothing/accessory/holster/waist - slot = slot_tie - cost = 1 - allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective","Security Cadet") - -/datum/gear/thigh - display_name = "holster, thigh" - path = /obj/item/clothing/accessory/holster/thigh - slot = slot_tie - cost = 1 - allowed_roles = list("Captain", "Head of Personnel", "Security Officer", "Warden", "Head of Security","Detective","Security Cadet") - -/datum/gear/tie_blue - display_name = "tie, blue" - path = /obj/item/clothing/accessory/blue - slot = slot_tie - cost = 1 - -/datum/gear/tie_red - display_name = "tie, red" - path = /obj/item/clothing/accessory/red - slot = slot_tie - cost = 1 - -/datum/gear/tie_horrible - display_name = "tie, socially disgraceful" - path = /obj/item/clothing/accessory/horrible - slot = slot_tie - cost = 1 - -/datum/gear/brown_vest - display_name = "webbing, engineering" - path = /obj/item/clothing/accessory/storage/brown_vest - slot = slot_tie - cost = 1 - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/black_vest - display_name = "webbing, security" - path = /obj/item/clothing/accessory/storage/black_vest - slot = slot_tie - cost = 1 - allowed_roles = list("Security Officer","Head of Security","Warden","Security Cadet","Detective") - -/datum/gear/webbing - display_name = "webbing, simple" - path = /obj/item/clothing/accessory/storage/webbing - slot = slot_tie - cost = 2 - -/datum/gear/suspenders - display_name = "suspenders" - path = /obj/item/clothing/accessory/suspenders - cost = 1 - slot = slot_tie - -/datum/gear/wcoat - display_name = "waistcoat" - path = /obj/item/clothing/accessory/wcoat - cost = 1 - slot = slot_tie - -// Suit slot - -/datum/gear/apron - display_name = "apron, blue" - path = /obj/item/clothing/suit/apron - cost = 1 - slot = slot_wear_suit - -/datum/gear/bomber - display_name = "bomber jacket" - path = /obj/item/clothing/suit/storage/toggle/bomber - cost = 2 - slot = slot_wear_suit - -/datum/gear/leather_jacket - display_name = "leather jacket, black" - path = /obj/item/clothing/suit/storage/leather_jacket - cost = 2 - slot = slot_wear_suit - -/datum/gear/leather_jacket_nt - display_name = "leather jacket, corporate, black" - path = /obj/item/clothing/suit/storage/leather_jacket/nanotrasen - cost = 2 - slot = slot_wear_suit - -/datum/gear/brown_jacket - display_name = "leather jacket, brown" - path = /obj/item/clothing/suit/storage/toggle/brown_jacket - cost = 2 - slot = slot_wear_suit - -/datum/gear/brown_jacket_nt - display_name = "leather jacket, corporate, brown" - path = /obj/item/clothing/suit/storage/toggle/brown_jacket/nanotrasen - cost = 2 - slot = slot_wear_suit - -/datum/gear/hazard_vest - display_name = "hazard vest" - path = /obj/item/clothing/suit/storage/hazardvest - cost = 2 - slot = slot_wear_suit - allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/hoodie - display_name = "hoodie, grey" - path = /obj/item/clothing/suit/storage/toggle/hoodie - cost = 2 - slot = slot_wear_suit - -/datum/gear/hoodie/black - display_name = "hoodie, black" - path = /obj/item/clothing/suit/storage/toggle/hoodie/black - cost = 2 - -/datum/gear/unathi_mantle - display_name = "hide mantle (Unathi)" - path = /obj/item/clothing/suit/unathi/mantle - cost = 1 - slot = slot_wear_suit - whitelisted = "Unathi" - -/datum/gear/labcoat - display_name = "labcoat" - path = /obj/item/clothing/suit/storage/toggle/labcoat - cost = 2 - slot = slot_wear_suit - -/datum/gear/bluelabcoat - display_name = "labcoat, blue" - path = /obj/item/clothing/suit/storage/toggle/labcoat/blue - cost = 2 - slot = slot_wear_suit - -/datum/gear/greenlabcoat - display_name = "labcoat, green" - path = /obj/item/clothing/suit/storage/toggle/labcoat/green - cost = 2 - slot = slot_wear_suit - -/datum/gear/orangelabcoat - display_name = "labcoat, orange" - path = /obj/item/clothing/suit/storage/toggle/labcoat/orange - cost = 2 - slot = slot_wear_suit - -/datum/gear/purplelabcoat - display_name = "labcoat, purple" - path = /obj/item/clothing/suit/storage/toggle/labcoat/purple - cost = 2 - slot = slot_wear_suit - -/datum/gear/redlabcoat - display_name = "labcoat, red" - path = /obj/item/clothing/suit/storage/toggle/labcoat/red - cost = 2 - slot = slot_wear_suit - -/datum/gear/overalls - display_name = "overalls" - path = /obj/item/clothing/suit/apron/overalls - cost = 1 - slot = slot_wear_suit - -/datum/gear/bponcho - display_name = "poncho, blue" - path = /obj/item/clothing/suit/poncho/blue - cost = 1 - slot = slot_wear_suit - -/datum/gear/gponcho - display_name = "poncho, green" - path = /obj/item/clothing/suit/poncho/green - cost = 1 - slot = slot_wear_suit - -/datum/gear/pponcho - display_name = "poncho, purple" - path = /obj/item/clothing/suit/poncho/purple - cost = 1 - slot = slot_wear_suit - -/datum/gear/rponcho - display_name = "poncho, red" - path = /obj/item/clothing/suit/poncho/red - cost = 1 - slot = slot_wear_suit - -/datum/gear/poncho - display_name = "poncho, tan" - path = /obj/item/clothing/suit/poncho - cost = 1 - slot = slot_wear_suit - -/datum/gear/unathi_robe - display_name = "roughspun robe (Unathi)" - path = /obj/item/clothing/suit/unathi/robe - cost = 1 - slot = slot_wear_suit - whitelisted = "Unathi" - -/datum/gear/blue_lawyer_jacket - display_name = "suit jacket, blue" - path = /obj/item/clothing/suit/storage/toggle/lawyer/bluejacket - cost = 2 - slot = slot_wear_suit - -/datum/gear/purple_lawyer_jacket - display_name = "suit jacket, purple" - path = /obj/item/clothing/suit/storage/lawyer/purpjacket - cost = 2 - slot = slot_wear_suit - -/datum/gear/zhan_furs - display_name = "zhan-Khazan furs" - path = /obj/item/clothing/suit/tajaran/furs - cost = 1 - slot = slot_wear_suit - whitelisted = "Tajara" - -/datum/gear/track_jacket - display_name = "track jacket" - path = /obj/item/clothing/suit/storage/toggle/tracksuit - cost = 1 - slot = slot_wear_suit - -// Gloves - -/datum/gear/black_gloves - display_name = "gloves, black" - path = /obj/item/clothing/gloves/black - cost = 2 - slot = slot_gloves - -/datum/gear/blue_gloves - display_name = "gloves, blue" - path = /obj/item/clothing/gloves/blue - cost = 2 - slot = slot_gloves - -/datum/gear/brown_gloves - display_name = "gloves, brown" - path = /obj/item/clothing/gloves/brown - cost = 2 - slot = slot_gloves - -/datum/gear/light_brown_gloves - display_name = "gloves, light-brown" - path = /obj/item/clothing/gloves/light_brown - cost = 2 - slot = slot_gloves - -/datum/gear/green_gloves - display_name = "gloves, green" - path = /obj/item/clothing/gloves/green - cost = 2 - slot = slot_gloves - -/datum/gear/grey_gloves - display_name = "gloves, grey" - path = /obj/item/clothing/gloves/grey - cost = 2 - slot = slot_gloves - -/datum/gear/latex_gloves - display_name = "gloves, latex" - path = /obj/item/clothing/gloves/latex - cost = 2 - slot = slot_gloves - - -/datum/gear/orange_gloves - display_name = "gloves, orange" - path = /obj/item/clothing/gloves/orange - cost = 2 - slot = slot_gloves - -/datum/gear/purple_gloves - display_name = "gloves, purple" - path = /obj/item/clothing/gloves/purple - cost = 2 - slot = slot_gloves - -/datum/gear/rainbow_gloves - display_name = "gloves, rainbow" - path = /obj/item/clothing/gloves/rainbow - cost = 2 - slot = slot_gloves - -/datum/gear/red_gloves - display_name = "gloves, red" - path = /obj/item/clothing/gloves/red - cost = 2 - slot = slot_gloves - -/datum/gear/white_gloves - display_name = "gloves, white" - path = /obj/item/clothing/gloves/white - cost = 2 - slot = slot_gloves - -/datum/gear/black_gloves_unathi - display_name = "black gloves, unathi" - path = /obj/item/clothing/gloves/black/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/black_gloves_tajara - display_name = "black gloves, tajaran" - path = /obj/item/clothing/gloves/black/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/red_gloves_unathi - display_name = "red gloves, unathi" - path = /obj/item/clothing/gloves/red/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/red_gloves_tajaran - display_name = "red gloves, tajaran" - path = /obj/item/clothing/gloves/red/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/blue_gloves_unathi - display_name = "blue gloves, unathi" - path = /obj/item/clothing/gloves/blue/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/blue_gloves_tajaran - display_name = "blue gloves, tajaran" - path = /obj/item/clothing/gloves/blue/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/orange_gloves_unathi - display_name = "orange gloves, unathi" - path = /obj/item/clothing/gloves/orange/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/orange_gloves_tajaran - display_name = "orange gloves, tajaran" - path = /obj/item/clothing/gloves/orange/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/purple_gloves_unathi - display_name = "purple gloves, unathi" - path = /obj/item/clothing/gloves/purple/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/purple_gloves_tajaran - display_name = "purple gloves, tajaran" - path = /obj/item/clothing/gloves/purple/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/brown_gloves_unathi - display_name = "brown gloves, unathi" - path = /obj/item/clothing/gloves/brown/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/brown_gloves_tajaran - display_name = "brown gloves, tajaran" - path = /obj/item/clothing/gloves/brown/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/green_gloves_unathi - display_name = "green gloves, unathi" - path = /obj/item/clothing/gloves/green/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/green_gloves_tajaran - display_name = "green gloves, tajaran" - path = /obj/item/clothing/gloves/green/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/white_gloves_unathi - display_name = "white gloves, unathi" - path = /obj/item/clothing/gloves/white/unathi - cost = 2 - slot = slot_gloves - -/datum/gear/white_gloves_tajaran - display_name = "white gloves, tajaran" - path = /obj/item/clothing/gloves/white/tajara - cost = 2 - slot = slot_gloves - -/datum/gear/watch - display_name = "watch" - path = /obj/item/clothing/gloves/watch - cost = 2 - slot = slot_gloves - -// Shoelocker - -/datum/gear/jackboots - display_name = "jackboots" - path = /obj/item/clothing/shoes/jackboots - cost = 1 - slot = slot_shoes -// allowed_roles = list("Security Cadet","Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain") - -/datum/gear/toeless_jackboots - display_name = "toe-less jackboots" - path = /obj/item/clothing/shoes/jackboots/unathi - cost = 1 - slot = slot_shoes -// allowed_roles = list("Security Cadet","Security Officer","Head of Security","Warden","Detective","Internal Affairs Agent","Quartermaster","Head of Personnel","Captain") - -/datum/gear/workboots - display_name = "workboots" - path = /obj/item/clothing/shoes/workboots - cost = 1 - slot = slot_shoes -// allowed_roles = list("Station Engineer","Atmospheric Technician","Chief Engineer","Engineering Apprentice") - -/datum/gear/sandal - display_name = "sandals" - path = /obj/item/clothing/shoes/sandal - cost = 1 - slot = slot_shoes - -/datum/gear/black_shoes - display_name = "shoes, black" - path = /obj/item/clothing/shoes/black - cost = 1 - slot = slot_shoes - -/datum/gear/blue_shoes - display_name = "shoes, blue" - path = /obj/item/clothing/shoes/blue - cost = 1 - slot = slot_shoes - -/datum/gear/brown_shoes - display_name = "shoes, brown" - path = /obj/item/clothing/shoes/brown - cost = 1 - slot = slot_shoes - -/datum/gear/laceyshoes - display_name = "shoes, classy" - path = /obj/item/clothing/shoes/laceup - cost = 1 - slot = slot_shoes - -/datum/gear/dress_shoes - display_name = "shoes, dress" - path = /obj/item/clothing/shoes/laceup - cost = 1 - slot = slot_shoes - -/datum/gear/green_shoes - display_name = "shoes, green" - path = /obj/item/clothing/shoes/green - cost = 1 - slot = slot_shoes - -/datum/gear/leather - display_name = "shoes, leather" - path = /obj/item/clothing/shoes/leather - cost = 1 - slot = slot_shoes - -/datum/gear/orange_shoes - display_name = "shoes, orange" - path = /obj/item/clothing/shoes/orange - cost = 1 - slot = slot_shoes - -/datum/gear/purple_shoes - display_name = "shoes, purple" - path = /obj/item/clothing/shoes/purple - cost = 1 - slot = slot_shoes - -/datum/gear/rainbow_shoes - display_name = "shoes, rainbow" - path = /obj/item/clothing/shoes/rainbow - cost = 1 - slot = slot_shoes - -/datum/gear/red_shoes - display_name = "shoes, red" - path = /obj/item/clothing/shoes/red - cost = 1 - slot = slot_shoes - -/datum/gear/white_shoes - display_name = "shoes, white" - path = /obj/item/clothing/shoes/white - cost = 1 - slot = slot_shoes - -/datum/gear/yellow_shoes - display_name = "shoes, yellow" - path = /obj/item/clothing/shoes/yellow - cost = 1 - slot = slot_shoes - -// "Useful" items - I'm guessing things that might be used at work? - -/datum/gear/briefcase - display_name = "briefcase" - path = /obj/item/weapon/storage/briefcase - sort_category = "utility" - cost = 2 - -/datum/gear/clipboard - display_name = "clipboard" - path = /obj/item/weapon/clipboard - sort_category = "utility" - cost = 1 - -/datum/gear/folder_blue - display_name = "folder, blue" - path = /obj/item/weapon/folder/blue - sort_category = "utility" - cost = 1 - -/datum/gear/folder_grey - display_name = "folder, grey" - path = /obj/item/weapon/folder - sort_category = "utility" - cost = 1 - -/datum/gear/folder_red - display_name = "folder, red" - path = /obj/item/weapon/folder/red - sort_category = "utility" - cost = 1 - -/datum/gear/folder_white - display_name = "folder, white" - path = /obj/item/weapon/folder/white - sort_category = "utility" - cost = 1 - -/datum/gear/folder_yellow - display_name = "folder, yellow" - path = /obj/item/weapon/folder/yellow - sort_category = "utility" - cost = 1 - -/datum/gear/paicard - display_name = "personal AI device" - path = /obj/item/device/paicard - sort_category = "utility" - cost = 2 - -/datum/gear/wallet - display_name = "wallet" - path = /obj/item/weapon/storage/wallet - sort_category = "utility" - cost = 1 - -// Reserved for later use -// /datum/gear/cheaptablet -// display_name = "cheap tablet computer" -// path = /obj/item/modular_computer/tablet/preset/custom_loadout/cheap -// sort_category = "utility" -// cost = 3 -// -// /datum/gear/normaltablet -// display_name = "tablet computer" -// path = /obj/item/modular_computer/tablet/preset/custom_loadout/advanced -// sort_category = "utility" -// cost = 4 - -// The rest of the trash. - -/datum/gear/ashtray - display_name = "ashtray, plastic" - path = /obj/item/weapon/material/ashtray/plastic - sort_category = "misc" - cost = 1 - -/datum/gear/boot_knife - display_name = "boot knife" - path = /obj/item/weapon/material/kitchen/utensil/knife/boot - sort_category = "misc" - cost = 3 - -/datum/gear/cane - display_name = "cane" - path = /obj/item/weapon/cane - sort_category = "misc" - cost = 1 - -/datum/gear/dice - display_name = "d20" - path = /obj/item/weapon/dice/d20 - sort_category = "misc" - cost = 1 - -/datum/gear/cards - display_name = "deck of cards" - path = /obj/item/weapon/deck/cards - sort_category = "misc" - cost = 1 - -/datum/gear/tarot - display_name = "deck of tarot cards" - path = /obj/item/weapon/deck/tarot - sort_category = "misc" - cost = 1 - -/datum/gear/holder - display_name = "card holder" - path = /obj/item/weapon/deck/holder - sort_category = "misc" - cost = 1 - -/datum/gear/cardemon_pack - display_name = "\improper cardemon booster pack" - path = /obj/item/weapon/pack/cardemon - sort_category = "misc" - cost = 1 - -/datum/gear/spaceball_pack - display_name = "\improper spaceball booster pack" - path = /obj/item/weapon/pack/spaceball - sort_category = "misc" - cost = 1 - -/datum/gear/flask - display_name = "flask" - path = /obj/item/weapon/reagent_containers/food/drinks/flask/barflask - sort_category = "misc" - cost = 1 - -/datum/gear/vacflask - display_name = "vacuum-flask" - path = /obj/item/weapon/reagent_containers/food/drinks/flask/vacuumflask - sort_category = "misc" - cost = 1 -/datum/gear/blipstick - display_name = "lipstick, black" - path = /obj/item/weapon/lipstick/black - sort_category = "misc" - cost = 1 - -/datum/gear/jlipstick - display_name = "lipstick, jade" - path = /obj/item/weapon/lipstick/jade - sort_category = "misc" - cost = 1 - -/datum/gear/plipstick - display_name = "lipstick, purple" - path = /obj/item/weapon/lipstick/purple - sort_category = "misc" - cost = 1 - -/datum/gear/rlipstick - display_name = "lipstick, red" - path = /obj/item/weapon/lipstick - sort_category = "misc" - cost = 1 - -/datum/gear/smokingpipe - display_name = "pipe, smoking" - path = /obj/item/clothing/mask/smokable/pipe - sort_category = "misc" - cost = 1 - -/datum/gear/cornpipe - display_name = "pipe, corn" - path = /obj/item/clothing/mask/smokable/pipe/cobpipe - sort_category = "misc" - cost = 1 - -/datum/gear/cigar_case - display_name = "cigar case" - path = /obj/item/weapon/storage/fancy/cigar - sort_category = "misc" - cost = 2 - -/datum/gear/cigarettes - display_name = "pack of DromedaryCo cigarettes" - path = /obj/item/weapon/storage/fancy/cigarettes/dromedaryco - sort_category = "misc" - cost = 2 - -/datum/gear/matchbook - display_name = "matchbook" - path = /obj/item/weapon/storage/box/matches - sort_category = "misc" - cost = 1 - -/datum/gear/comb - display_name = "purple comb" - path = /obj/item/weapon/haircomb - sort_category = "misc" - cost = 1 - -/datum/gear/cape - display_name = "tunnel cloak" - path = /obj/item/weapon/storage/backpack/cloak - sort_category = "misc" - cost = 1 - -/datum/gear/mirror - display_name = "handheld mirror" - path = /obj/item/weapon/mirror - sort_category = "misc" - cost = 1 - -/datum/gear/zippo - display_name = "zippo" - path = /obj/item/weapon/flame/lighter/zippo - sort_category = "misc" - cost = 1 - -/datum/gear/recorder - display_name = "universal recorder" - path = /obj/item/device/taperecorder - sort_category = "misc" - cost = 1 - -// Stuff worn on the ears. Items here go in the "ears" sort_category but they must not use -// the slot_r_ear or slot_l_ear as the slot, or else players will spawn with no headset. -/datum/gear/earmuffs - display_name = "earmuffs" - path = /obj/item/clothing/ears/earmuffs - cost = 1 - sort_category = "ears" - -/datum/gear/skrell_chain - display_name = "skrell headtail-wear, female, chain" - path = /obj/item/clothing/ears/skrell/chain - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/skrell_plate - display_name = "skrell headtail-wear, male, bands" - path = /obj/item/clothing/ears/skrell/band - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/skrell_cloth_male - display_name = "skrell headtail-wear, male, cloth" - path = /obj/item/clothing/ears/skrell/cloth_male - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/skrell_cloth_female - display_name = "skrell headtail-wear, female, cloth" - path = /obj/item/clothing/ears/skrell/cloth_female - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/red_jeweled - display_name = "skrell headtail-wear, female, red-jeweled chain" - path = /obj/item/clothing/ears/skrell/redjewel_chain - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/ebony_chain - display_name = "skrell headtail-wear, female, ebony chain" - path = /obj/item/clothing/ears/skrell/ebony_chain - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/redjeweled_band - display_name = "skrell headtail-wear, male, red-jeweled bands" - path = /obj/item/clothing/ears/skrell/redjeweled_band - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/ebony_band - display_name = "skrell headtail-wear, male, ebony bands" - path = /obj/item/clothing/ears/skrell/ebony_band - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/bluejeweled_chain - display_name = "skrell headtail-wear, female, blue-jeweled chain" - path = /obj/item/clothing/ears/skrell/bluejeweled_chain - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/bluejeweled_band - display_name = "skrell headtail-wear, male, blue-jeweled bands" - path = /obj/item/clothing/ears/skrell/bluejeweled_band - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/silver_chain - display_name = "skrell headtail-wear, female, silver chain" - path = /obj/item/clothing/ears/skrell/silver_chain - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/silver_band - display_name = "skrell headtail-wear, male, silver bands" - path = /obj/item/clothing/ears/skrell/silver_band - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/blue_skrell_cloth_band_male - display_name = "skrell headtail-wear, male, blue cloth" - path = /obj/item/clothing/ears/skrell/blue_skrell_cloth_band_male - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/blue_skrell_cloth_band_female - display_name = "skrell headtail-wear, female, blue cloth" - path = /obj/item/clothing/ears/skrell/blue_skrell_cloth_band_female - cost = 1 - sort_category = "ears" - whitelisted = "Skrell" - -/datum/gear/bandanna_r - display_name = "neck bandanna, red" - path = /obj/item/clothing/ears/bandanna - cost = 1 - sort_category = "ears" - -/datum/gear/bandanna_bl - display_name = "neck bandanna, blue" - path = /obj/item/clothing/ears/bandanna/blue - cost = 1 - sort_category = "ears" - -/datum/gear/bandanna_bk - display_name = "neck bandanna, black" - path = /obj/item/clothing/ears/bandanna/black - cost = 1 - sort_category = "ears" diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index b2d0958dbd5..180fd7c6914 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -145,3 +145,47 @@ src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 1) src << sound(null, repeat = 0, wait = 0, volume = 0, channel = 2) feedback_add_details("admin_verb","TAmbi") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/verb/toggle_space_parallax() + set name = "Show/Hide Space Parallax" + set category = "Preferences" + set desc = "Toggles space parallax effects." + prefs.parallax_togs ^= PARALLAX_SPACE + prefs.save_preferences() + if (prefs.parallax_togs & PARALLAX_SPACE) + src << "You will now see space parallax effects." + else + src << "You will no longer see space parallax effects." + + if (mob.hud_used) + mob.hud_used.update_parallax() + + +/client/verb/toggle_space_dust() + set name = "Show/Hide Space Dust" + set category = "Preferences" + set desc = "Toggles space parallax dust." + prefs.parallax_togs ^= PARALLAX_DUST + prefs.save_preferences() + if (prefs.parallax_togs & PARALLAX_DUST) + src << "You will now see space parallax dust effects." + else + src << "You will no longer see space parallax dust effects." + + if (mob.hud_used) + mob.hud_used.update_parallax() + +/client/verb/set_parallax_speed() + set name = "Set Parallax Speed" + set category = "Preferences" + set desc = "Sets the movement speed of the space parallax effect." + var/choice = input("What speed do you want to use for space parallax? (default 2)", "SPAAACE") as num|null + if (!choice || choice < 0) + src << "Invalid input." + return + + prefs.parallax_speed = choice + prefs.save_preferences() + + if (mob.hud_used) + mob.hud_used.update_parallax() diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 37714286085..77e832c8409 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -268,14 +268,14 @@ BLIND // can't see anything body_parts_covered = HEAD slot_flags = SLOT_HEAD w_class = 2.0 - diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona + //diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona species_restricted = list("exclude","Vaurca Breeder") var/light_overlay = "helmet_light" var/light_applied var/brightness_on var/on = 0 - offset_light = 1 + //offset_light = 1 sprite_sheets = list( "Vox" = 'icons/mob/species/vox/head.dmi', diff --git a/code/modules/detectivework/tools/uvlight.dm b/code/modules/detectivework/tools/uvlight.dm index 922839d098e..d86076c167f 100644 --- a/code/modules/detectivework/tools/uvlight.dm +++ b/code/modules/detectivework/tools/uvlight.dm @@ -7,7 +7,7 @@ item_state = "electronic" matter = list(DEFAULT_WALL_MATERIAL = 150) origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) - offset_light = 1 + //offset_light = 1 var/list/scanned = list() var/list/stored_alpha = list() var/list/reset_objects = list() @@ -19,7 +19,7 @@ /obj/item/device/uv_light/attack_self(var/mob/user) on = !on if(on) - set_light(range, 2, "#007fff") + set_light(range, 2, "#007fff", uv = 100) processing_objects |= src icon_state = "uv_on" else @@ -66,4 +66,4 @@ var/obj/item/O = A if(O.was_bloodied && !(O.blood_overlay in O.overlays)) O.overlays |= O.blood_overlay - reset_objects |= O \ No newline at end of file + reset_objects |= O diff --git a/code/modules/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm index 83d78272b05..adf514d3877 100644 --- a/code/modules/holodeck/HolodeckControl.dm +++ b/code/modules/holodeck/HolodeckControl.dm @@ -3,6 +3,7 @@ desc = "A computer used to control a nearby holodeck." icon_screen = "holocontrol" + light_color = LIGHT_COLOR_CYAN use_power = 1 active_power_usage = 8000 //8kW for the scenery + 500W per holoitem diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 22f3a598f67..ff1107daa8c 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -284,11 +284,11 @@ // Handle light requirements. if(!light_supplied) - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in current_turf - if(L) - light_supplied = max(0,min(10,L.lum_r + L.lum_g + L.lum_b)-5) + if (current_turf.dynamic_lighting) + light_supplied = current_turf.get_lumcount(0, 3) * 10 else - light_supplied = 5 + light_supplied = 5 + if(light_supplied) if(abs(light_supplied - get_trait(TRAIT_IDEAL_LIGHT)) > get_trait(TRAIT_LIGHT_TOLERANCE)) health_change += rand(1,3) * HYDRO_SPEED_MULTIPLIER diff --git a/code/modules/hydroponics/spreading/spreading.dm b/code/modules/hydroponics/spreading/spreading.dm index 14e4741565e..d76cdce7e6b 100644 --- a/code/modules/hydroponics/spreading/spreading.dm +++ b/code/modules/hydroponics/spreading/spreading.dm @@ -62,6 +62,7 @@ var/mature_time //minimum maturation time var/last_tick = 0 var/obj/machinery/portable_atmospherics/hydroponics/soil/invisible/plant + var/last_biolum = null /obj/effect/plant/Destroy() if(plant_controller) @@ -153,10 +154,15 @@ var/clr if(seed.get_trait(TRAIT_BIOLUM_COLOUR)) clr = seed.get_trait(TRAIT_BIOLUM_COLOUR) - set_light(1+round(seed.get_trait(TRAIT_POTENCY)/20), l_color = clr) + var/val = 1+round(seed.get_trait(TRAIT_POTENCY)/20) + if (val != last_biolum) + last_biolum = val + set_light(val, l_color = clr) return else - set_light(0) + if (last_biolum) + set_light(0) + last_biolum = null /obj/effect/plant/proc/refresh_icon() var/growth = min(max_growth,round(health/growth_threshold)) diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 8c37abb6d62..7a025071f95 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -26,6 +26,7 @@ var/harvest = 0 // Is it ready to harvest? var/age = 0 // Current plant age var/sampled = 0 // Have we taken a sample? + var/last_biolum // What was the bioluminescence last tick? // Harvest/mutation mods. var/yield_mod = 0 // Modifier to yield @@ -645,10 +646,9 @@ if(closed_system && mechanical) light_string = "that the internal lights are set to [tray_light] lumens" else - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T var/light_available - if(L) - light_available = max(0,min(10,L.lum_r + L.lum_g + L.lum_b)-5) + if(T.dynamic_lighting) + light_available = T.get_lumcount(0, 3) * 10 else light_available = 5 light_string = "a light level of [light_available] lumens" diff --git a/code/modules/hydroponics/trays/tray_update_icons.dm b/code/modules/hydroponics/trays/tray_update_icons.dm index dc69e5448ee..bcee0352797 100644 --- a/code/modules/hydroponics/trays/tray_update_icons.dm +++ b/code/modules/hydroponics/trays/tray_update_icons.dm @@ -73,13 +73,17 @@ overlays += "over_harvest3" // Update bioluminescence. - if(seed) - if(seed.get_trait(TRAIT_BIOLUM)) - var/clr - if(seed.get_trait(TRAIT_BIOLUM_COLOUR)) - clr = seed.get_trait(TRAIT_BIOLUM_COLOUR) - set_light(round(seed.get_trait(TRAIT_POTENCY)/10), l_color = clr) - return - - set_light(0) + if(seed && seed.get_trait(TRAIT_BIOLUM)) + var/clr + if(seed.get_trait(TRAIT_BIOLUM_COLOUR)) + clr = seed.get_trait(TRAIT_BIOLUM_COLOUR) + var/val = round(seed.get_trait(TRAIT_POTENCY)/10) + if (val != last_biolum) + last_biolum = val + set_light(val, l_color = clr) + return + + if (last_biolum) + set_light(0) + last_biolum = null return diff --git a/code/modules/icon generation/Bluespaced.dm b/code/modules/icon generation/Bluespaced.dm deleted file mode 100644 index db9f88c215c..00000000000 --- a/code/modules/icon generation/Bluespaced.dm +++ /dev/null @@ -1,243 +0,0 @@ -/proc/bsi_cast_ray(icon/I, list/start, list/end) - - if(abs(start[1] - end[1]) > abs(start[2] - end[2])) - var/dist = abs(start[1] - end[1]) * 2 - - for(var/i = 1, i <= dist, i++) - var/x = round((start[1] * i / dist) + (end[1] * (1 - i / dist))) - var/y = round((start[2] * i / dist) + (end[2] * (1 - i / dist))) - - if(I.GetPixel(x, y) != null) - return list(x, y) - - else - var/dist = abs(start[2] - end[2]) * 2 - - for(var/i = 1, i <= dist, i++) - var/x = round((start[1] * i / dist) + (end[1] * (1 - i / dist))) - var/y = round((start[2] * i / dist) + (end[2] * (1 - i / dist))) - - if(I.GetPixel(x, y) != null) - return list(x, y) - - return null - -/proc/bsi_split_colors(color) - if(color == null) - return list(0, 0, 0, 0) - - var/list/colors = list(0, 0, 0, 0) - colors[1] = hex2num(copytext(color, 2, 4)) - colors[2] = hex2num(copytext(color, 4, 6)) - colors[3] = hex2num(copytext(color, 6, 8)) - colors[4] = (length(color) > 7)? hex2num(copytext(color, 8, 10)) : 255 - - return colors - -/proc/bsi_spread(icon/I, list/start_point) - var/list/queue = list() - queue[++queue.len] = start_point - - var/i = 0 - - while(i++ < length(queue)) - var/x = queue[i][1] - var/y = queue[i][2] - - var/list/pixel = bsi_split_colors(I.GetPixel(x, y)) - if(pixel[4] == 0) - continue - - var/list/n = (y < I.Height())? bsi_split_colors(I.GetPixel(x, y + 1)) : list(0, 0, 0, 0) - var/list/s = (y > 1)? bsi_split_colors(I.GetPixel(x, y - 1)) : list(0, 0, 0, 0) - var/list/e = (x < I.Width())? bsi_split_colors(I.GetPixel(x + 1, y)) : list(0, 0, 0, 0) - var/list/w = (x > 1)? bsi_split_colors(I.GetPixel(x - 1, y)) : list(0, 0, 0, 0) - - var/value = (i == 1)? 16 : max(n[1] - 1, e[1] - 1, s[1] - 1, w[1] - 1) - - if(prob(50)) - value = max(0, value - 1) - - if(prob(50)) - value = max(0, value - 1) - - if(prob(50)) - value = max(0, value - 1) - - if(value <= pixel[1]) - continue - - var/v2 = 256 - ((16 - value) * (16 - value)) - - I.DrawBox(rgb(value, v2, pixel[4] - v2, pixel[4]), x, y) - - if(n[4] != 0 && n[1] < value - 1) - queue[++queue.len] = list(x, y + 1) - - if(s[4] != 0 && s[1] < value - 1) - queue[++queue.len] = list(x, y - 1) - - if(e[4] != 0 && e[1] < value - 1) - queue[++queue.len] = list(x + 1, y) - - if(w[4] != 0 && w[1] < value - 1) - queue[++queue.len] = list(x - 1, y) - - - - - -/proc/bsi_generate_mask(icon/source, state) - var/icon/mask = icon(source, state) - - mask.MapColors( - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 1, 1, - 0, 0, 0, 0) - - var/hits = 0 - - for(var/i = 1, i <= 10, i++) - var/point1 - var/point2 - - if(prob(50)) - if(prob(50)) - point1 = list(rand(1, mask.Width()), mask.Height()) - point2 = list(rand(1, mask.Width()), 1) - - else - point2 = list(rand(1, mask.Width()), mask.Height()) - point1 = list(rand(1, mask.Width()), 1) - - else - if(prob(50)) - point1 = list(mask.Width(), rand(1, mask.Height())) - point2 = list(1, rand(1, mask.Height())) - - else - point2 = list(mask.Width(), rand(1, mask.Height())) - point1 = list(1, rand(1, mask.Height())) - - var/hit = bsi_cast_ray(mask, point1, point2) - - if(hit == null) - continue - - hits++ - - bsi_spread(mask, hit) - - if(prob(20 + hits * 20)) - break - - if(hits == 0) - return null - - else - return mask - -/proc/generate_bluespace_icon(icon/source, state) - - var/icon/mask = bsi_generate_mask(source, state) - - if(mask == null) - return source - - var/icon/unaffected = icon(mask) - unaffected.MapColors( - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 1, - 0, 0, 0, 0, - 255, 255, 255, 0) - - var/icon/temp = icon(source, state) //Mask already contains the original alpha values, avoid squaring them - temp.MapColors( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 0, - 0, 0, 0, 255) - - unaffected.Blend(temp, ICON_MULTIPLY) - - var/icon/bluespaced = icon(mask) - bluespaced.MapColors( - 0, 0, 0, 0, - 0, 0, 0, 1, - 0, 0, 0, 0, - 0, 0, 0, 0, - 1, 1, 1, 0) - - bluespaced.Blend(icon(source, state), ICON_MULTIPLY) - - var/list/frames = list( - list(0.000,20), - list(0.020, 5), - list(0.050, 4), - list(0.080, 5), - list(0.100,10), - list(0.080, 5), - list(0.050, 4), - list(0.020, 5), - - list(0.000,20), - list(0.020, 5), - list(0.050, 4), - list(0.080, 5), - list(0.100,10), - list(0.080, 5), - list(0.050, 4), - list(0.020, 5), - - list(0.000,20), - list(0.020, 5), - list(0.050, 4), - list(0.080, 5), - list(0.100,10), - list(0.080, 5), - list(0.050, 4), - list(0.020, 5) - ) - - var/list/colors = list( - list( 75, 75, 75, 0), - list( 25, 25, 25, 0), - list( 75, 75, 75, 0), - list( 25, 25, 75, 0), - list( 75, 75, 300, 0), - list( 25, 25, 300, 0), - list(255, 255, 255, 0), - list( 0, 0, 0, 255), - list( 0, 0, 0, 0), - list( 0, 0, 0, 0) - ) - - for(var/i = 1, i <= rand(1, 5), i++) - var/f = rand(1, length(frames)) - - if(frames[f][2] > 1) - frames[f][2]-- - frames.Insert(f, 0) - - frames[f] = list(0.8, 1) - - var/icon/result = generate_color_animation(bluespaced, colors, frames) - result.Blend(unaffected, ICON_UNDERLAY) - - return result - - - -/atom/verb/test() - set src in view() - src.icon = generate_bluespace_icon(src.icon, src.icon_state) - -/mob/verb/bluespam() - for(var/turf/t in view(5)) - var/obj/s = new /obj/square(t) - s.icon = generate_bluespace_icon(s.icon, s.icon_state) - diff --git a/code/modules/icon generation/Icon_color_animation.dm b/code/modules/icon generation/Icon_color_animation.dm deleted file mode 100644 index 1be1bfa28a9..00000000000 --- a/code/modules/icon generation/Icon_color_animation.dm +++ /dev/null @@ -1,96 +0,0 @@ -//---------------------------------------- -// -// Return a copy of the provided icon, -// after calling MapColors on it. The -// color values are linearily interpolated -// between the pairs provided, based on -// the ratio argument. -// -//---------------------------------------- - -/proc/MapColors_interpolate(icon/input, ratio, - rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, - gr1, gg1, gb1, ga1, gr2, gg2, gb2, ga2, - br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, - ar1, ag1, ab1, aa1, ar2, ag2, ab2, aa2, - zr1, zg1, zb1, za1, zr2, zg2, zb2, za2) - var/r = ratio - var/i = 1 - ratio - var/icon/I = icon(input) - - I.MapColors( - (rr1 * r + rr2 * i) / 255.0, (rg1 * r + rg2 * i) / 255.0, (rb1 * r + rb2 * i) / 255.0, (ra1 * r + ra2 * i) / 255.0, - (gr1 * r + gr2 * i) / 255.0, (gg1 * r + gg2 * i) / 255.0, (gb1 * r + gb2 * i) / 255.0, (ga1 * r + ga2 * i) / 255.0, - (br1 * r + br2 * i) / 255.0, (bg1 * r + bg2 * i) / 255.0, (bb1 * r + bb2 * i) / 255.0, (ba1 * r + ba2 * i) / 255.0, - (ar1 * r + ar2 * i) / 255.0, (ag1 * r + ag2 * i) / 255.0, (ab1 * r + ab2 * i) / 255.0, (aa1 * r + aa2 * i) / 255.0, - (zr1 * r + zr2 * i) / 255.0, (zg1 * r + zg2 * i) / 255.0, (zb1 * r + zb2 * i) / 255.0, (za1 * r + za2 * i) / 255.0) - - return I - - - - -//---------------------------------------- -// -// Extension of the above that takes a -// list of lists of color values, rather -// than a large number of arguments. -// -//---------------------------------------- - -/proc/MapColors_interpolate_list(icon/I, ratio, list/colors) - var/list/c[10] - - //Provide default values for any missing colors (without altering the original list - for(var/i = 1, i <= 10, i++) - c[i] = list(0, 0, 0, (i == 7 || i == 8)? 255 : 0) - - if(istype(colors[i], /list)) - for(var/j = 1, j <= 4, j++) - if(j <= length(colors[i]) && isnum(colors[i][j])) - c[i][j] = colors[i][j] - - return MapColors_interpolate(I, ratio, - colors[ 1][1], colors[ 1][2], colors[ 1][3], colors[ 1][4], // Red 1 - colors[ 2][1], colors[ 2][2], colors[ 2][3], colors[ 2][4], // Red 2 - colors[ 3][1], colors[ 3][2], colors[ 3][3], colors[ 3][4], // Green 1 - colors[ 4][1], colors[ 4][2], colors[ 4][3], colors[ 4][4], // Green 2 - colors[ 5][1], colors[ 5][2], colors[ 5][3], colors[ 5][4], // Blue 1 - colors[ 6][1], colors[ 6][2], colors[ 6][3], colors[ 6][4], // Blue 2 - colors[ 7][1], colors[ 7][2], colors[ 7][3], colors[ 7][4], // Alpha 1 - colors[ 8][1], colors[ 8][2], colors[ 8][3], colors[ 8][4], // Alpha 2 - colors[ 9][1], colors[ 9][2], colors[ 9][3], colors[ 9][4], // Added 1 - colors[10][1], colors[10][2], colors[10][3], colors[10][4]) // Added 2 - - - - - -//---------------------------------------- -// -// Take the source image, and return an animated -// version, that transitions between the provided -// color mappings, according to the provided -// pattern. -// -// Colors should be in a format suitable for -// MapColors_interpolate_list, and frames should -// be a list of 'frames', where each frame is itself -// a list, element 1 being the ratio of the first -// color to the second, and element 2 being how -// long the frame lasts, in tenths of a second. -// -//---------------------------------------- - -/proc/generate_color_animation(icon/icon, list/colors, list/frames) - var/icon/out = icon('icons/effects/uristrunes.dmi', "") - var/frame_num = 1 - - for(var/frame in frames) - var/icon/I = MapColors_interpolate_list(icon, frame[1], colors) - out.Insert(I, "", 2, frame_num++, 0, frame[2]) - - return out - - - diff --git a/code/modules/icon generation/Uristrunes.dm b/code/modules/icon generation/Uristrunes.dm deleted file mode 100644 index 7288bbdde3a..00000000000 --- a/code/modules/icon generation/Uristrunes.dm +++ /dev/null @@ -1,268 +0,0 @@ -//---------------------------------------- -// -// Take a source icon, convert into a mask, -// then create a border around it. -// -// The output then uses the colors and -// alpha values provided. -// -//---------------------------------------- - -/proc/create_border_image(icon/input, border_color = "#000000", fill_color = "#000000", border_alpha = 255, fill_alpha = 255) - var/icon/I = icon('icons/effects/uristrunes.dmi', "blank") - I.Blend(input, ICON_OVERLAY) - - //Discard the image - I.MapColors(0, 0, 0, 0, //-\ Ignore - 0, 0, 0, 0, //--> The - 0, 0, 0, 0, //-/ Colors - 0,255, 0, 1, //Keep alpha channel, any pixel with non-zero alpha gets max green channel - 0, 0, 0, 0) - - //Loop over the image, calculating the border value, and storing it in the red channel - //Store border's alpha in the blue channel - for(var/x = 1, x <= 32, x++) - for(var/y = 1, y <= 32, y++) - var/p = I.GetPixel(x, y) - - if(p == null) - var/n = I.GetPixel(x, y + 1) - var/s = I.GetPixel(x, y - 1) - var/e = I.GetPixel(x + 1, y) - var/w = I.GetPixel(x - 1, y) - var/ne = I.GetPixel(x + 1, y + 1) - var/se = I.GetPixel(x + 1, y - 1) - var/nw = I.GetPixel(x - 1, y + 1) - var/sw = I.GetPixel(x - 1, y - 1) - - var/sum_adj = ((n == "#00ff00"? 1 : 0) \ - + (s == "#00ff00"? 1 : 0) \ - + (e == "#00ff00"? 1 : 0) \ - + (w == "#00ff00"? 1 : 0)) - - var/sum_diag = ((ne == "#00ff00"? 1 : 0) \ - + (se == "#00ff00"? 1 : 0) \ - + (nw == "#00ff00"? 1 : 0) \ - + (sw == "#00ff00"? 1 : 0)) - - - if(sum_adj) - I.DrawBox(rgb(255, 0, 200, 0), x, y) - - else if(sum_diag) - I.DrawBox(rgb(255, 0, 100, 0), x, y) - - else - I.DrawBox(rgb(0, 0, 0, 0), x, y) - - else if(p != "#00ff00") - var/a = 255 - - if(length(p) == 9) // "#rrggbbaa", we want the aa - a = hex2num(copytext(p, 8)) - - I.DrawBox(rgb(255 - a, a, 255 - a, a), x, y) - - //Map the red and green channels to the desired output colors - I.MapColors(border_color, fill_color, rgb(0, 0, 0, border_alpha), rgb(0, 0, 0, fill_alpha), "#00000000") - - return I - - - - -//---------------------------------------- -// -// Take a source icon, convert into a mask, -// and border. Color them according to args, -// and animate. -// -//---------------------------------------- - -/proc/animate_rune_full(icon/input, rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, ar1, ag1, ab1, aa1, ar2, ag2, ab2, aa2, or1, og1, ob1, oa1, or2, og2, ob2, oa2, frames) - - var/list/colors[10] - colors[ 1] = list(rr1, rg1, rb1, ra1) //Rune color 1 - colors[ 2] = list(rr2, rg2, rb2, ra2) //Rune color 2 - colors[ 3] = list(br1, bg1, bb1, ba1) //Border color 1 - colors[ 4] = list(br2, bg2, bb2, ba2) //Border color 2 - colors[ 5] = list( 0, 0, 0, 0) //Unused - colors[ 6] = list( 0, 0, 0, 0) //Unused - colors[ 7] = list(ar1, ag1, ab1, aa1) //Alpha color 1 - colors[ 8] = list(ar2, ag2, ab2, aa2) //Alpha color 2 - colors[ 9] = list(or1, og1, ob1, oa1) //Added color 1 - colors[10] = list(or2, og2, ob2, oa2) //Added color 2 - - var/icon/base = create_border_image(input, "#00ff0000", "#ff000000") - - return generate_color_animation(base, colors, frames) - - - - -//---------------------------------------- -// -// Calls the above, but accepts colors in -// the form of "#RRGGBBAA", and provides -// default values. -// -// Main limit is that it doesn't accept -// negative values, which you probably -// don't need anyway. Also missing a few -// color inputs, which would also be rarely -// used. -// -//---------------------------------------- - - -/proc/animate_rune(icon/input, rune_color = "#00000000", border_color = "#c8000000", rune_color2 = "#00000000", border_color2 = "#d8380000", alpha = 255, alpha2 = 255, frames = rune_animation) - var/rr1 = hex2num(copytext(rune_color, 2, 4)) - var/rg1 = hex2num(copytext(rune_color, 4, 6)) - var/rb1 = hex2num(copytext(rune_color, 6, 8)) - var/ra1 = hex2num(copytext(rune_color, 8, 10)) - var/rr2 = hex2num(copytext(rune_color2, 2, 4)) - var/rg2 = hex2num(copytext(rune_color2, 4, 6)) - var/rb2 = hex2num(copytext(rune_color2, 6, 8)) - var/ra2 = hex2num(copytext(rune_color2, 8, 10)) - var/br1 = hex2num(copytext(border_color, 2, 4)) - var/bg1 = hex2num(copytext(border_color, 4, 6)) - var/bb1 = hex2num(copytext(border_color, 6, 8)) - var/ba1 = hex2num(copytext(border_color, 8, 10)) - var/br2 = hex2num(copytext(border_color2, 2, 4)) - var/bg2 = hex2num(copytext(border_color2, 4, 6)) - var/bb2 = hex2num(copytext(border_color2, 6, 8)) - var/ba2 = hex2num(copytext(border_color2, 8, 10)) - - return animate_rune_full(input, rr1, rg1, rb1, ra1, rr2, rg2, rb2, ra2, br1, bg1, bb1, ba1, br2, bg2, bb2, ba2, 0, 0, 0, alpha, 0, 0, 0, alpha2, 0, 0, 0, 0, 0, 0, 0, 0, frames) - - -/proc/inanimate_rune(icon/input, rune_color = "#00000000", border_color = "#c8000000") - var/icon/base = create_border_image(input, "#00ff0000", "#ff000000") - - base.MapColors(rune_color, border_color, "#00000000", "#000000ff", "#00000000") - - return base - -var/list/rune_animation = list( - list(0.000, 5), - list(0.020, 1), - list(0.050, 1), - list(0.090, 1), - list(0.140, 1), - list(0.200, 1), - list(0.270, 1), - list(0.340, 1), - list(0.420, 1), - list(0.500, 1), - list(0.590, 1), - list(0.675, 1), - list(0.750, 1), - list(0.900, 1), - list(1.000, 6), - list(0.875, 1), - list(0.750, 1), - list(0.625, 1), - list(0.500, 1), - list(0.375, 1), - list(0.250, 1), - list(0.125, 1) - ) - -/var/list/rune_cache = list() - -/proc/get_rune(rune_bits, animated = 0) - var/lookup = "[rune_bits]-[animated]" - - if(lookup in rune_cache) - return rune_cache[lookup] - - var/icon/base = icon('icons/effects/uristrunes.dmi', "") - - for(var/i = 0, i < 10, i++) - if(BITTEST(rune_bits, i)) - base.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) - - var/icon/result - - if(animated == 1) - result = animate_rune(base) - - else - result = inanimate_rune(base) - - rune_cache[lookup] = result - return result - - - - - -// Testing procs and Fun procs - - - - -/mob/verb/create_rune() - var/obj/o = new(locate(x, y, z)) - o.icon = get_rune(rand(1, 1023), 1) - -/mob/verb/runes_15x15() - for(var/turf/t in range(7)) - var/obj/o = new /obj(t) - o.icon = get_rune(rand(1, 1023), 1) - - -/* -/mob/verb/create_rune_custom(rune as num, color1 as color, border1 as color, color2 as color, border2 as color, alpha1 as num, alpha2 as num) - var/icon/I = icon('icons/effects/uristrunes.dmi', "blank") - - for(var/i = 0, i < 10, i++) - if(BITTEST(rune, i)) - I.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) - - var/obj/o = new(locate(x, y, z)) - o.icon = animate_rune(I, color1, border1, color2, border2, alpha1, alpha2) - -/mob/verb/spam() - for(var/turf/t in range(4)) - var/icon/I = icon('icons/effects/uristrunes.dmi', "blank") - - var/rune = rand(1, 1023) - for(var/i = 0, i < 10, i++) - if(BITTEST(rune, i)) - I.Blend(icon('icons/effects/uristrunes.dmi', "rune-[1 << i]"), ICON_OVERLAY) - - var/obj/o = new(t) - o.icon = animate_rune_full(I, rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), - rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), - rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), - rand(0, 255), rand(0, 255), rand(0, 255), rand(-255, 255), - 0, 0, 0, rand(0, 255), - 0, 0, 0, rand(0, 255), - 0, 0, 0, 0, - 0, 0, 0, 0, - list( - list(0.000, 5), - list(0.020, 1), - list(0.050, 1), - list(0.090, 1), - list(0.140, 1), - list(0.200, 1), - list(0.270, 1), - list(0.340, 1), - list(0.420, 1), - list(0.500, 1), - list(0.590, 1), - list(0.675, 1), - list(0.750, 1), - list(0.900, 1), - list(1.000, 6), - list(0.875, 1), - list(0.750, 1), - list(0.625, 1), - list(0.500, 1), - list(0.375, 1), - list(0.250, 1), - list(0.125, 1), - )) -*/ diff --git a/code/modules/lighting/__lighting_docs.dm b/code/modules/lighting/__lighting_docs.dm index 5ac5897eb53..a5ff9450e49 100644 --- a/code/modules/lighting/__lighting_docs.dm +++ b/code/modules/lighting/__lighting_docs.dm @@ -3,9 +3,9 @@ BS12 object based lighting system */ /* -Changes from tg DAL: +Changes from TG DAL: - Lighting is done using objects instead of subareas. - - Animated transitions. (newer tg DAL has this) + - Animated transitions. (newer TG DAL has this) - Full colours with mixing. - Support for lights on shuttles. @@ -25,6 +25,9 @@ Changes from tg DAL: /* Relevant vars/procs: +global: (uh, I placed the only one in lighting_system.dm) + - var/list/all_lighting_overlays; Just a list of ALL of the lighting overlays. + atom: (lighting_atom.dm) - var/light_range; range in tiles of the light, used for calculating falloff - var/light_power; multiplier for the brightness of lights @@ -44,6 +47,8 @@ atom: (lighting_atom.dm) turf: (lighting_turf.dm) - var/list/affecting_lights; list of light sources that are shining onto this turf + - var/list/lighting_overlays; list of lighting overlays in the turf. (only used if higher resolutions + - var/lighting_overlay; ref to the lighting overlay (only used if resolution is 1) - proc/reconsider_lights(): - Force all light sources shining onto this turf to update @@ -51,8 +56,10 @@ turf: (lighting_turf.dm) - proc/lighting_clear_overlays(): - Delete (manual GC) all light overlays on this turf, used when changing turf to space - proc/lighting_build_overlays(): - - Create lighting overlays for this turf. Called by ChangeTurf in case the turf is being changed to use dynamic lighting. - + - Create lighting overlays for this turf + - proc/get_lumcount(var/minlum = 0, var/maxlum = 1) + - Returns a decimal according to the amount of lums on a turf's overlay (also averages them) + - With default arguments (based on the fact that 0 = pitch black and 1 = full bright), it will return .5 for a 50% lit tile. atom/movable/lighting_overlay: (lighting_overlay.dm) - var/lum_r, var/lum_g, var/lum_b; lumcounts of each colour diff --git a/code/modules/lighting/_lighting_defs.dm b/code/modules/lighting/_lighting_defs.dm deleted file mode 100644 index 21fdafdaebf..00000000000 --- a/code/modules/lighting/_lighting_defs.dm +++ /dev/null @@ -1,9 +0,0 @@ -#define LIGHTING_INTERVAL 5 // frequency, in 1/10ths of a second, of the lighting process - -#define LIGHTING_FALLOFF 1 // type of falloff to use for lighting; 1 for circular, 2 for square -#define LIGHTING_LAMBERTIAN 1 // use lambertian shading for light sources -#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone -#define LIGHTING_ROUND_VALUE (1 / 128) //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY. - -#define LIGHTING_LAYER 10 // drawing layer for lighting overlays -#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects diff --git a/code/modules/lighting/light_source.dm b/code/modules/lighting/light_source.dm deleted file mode 100644 index d6c00e435ae..00000000000 --- a/code/modules/lighting/light_source.dm +++ /dev/null @@ -1,447 +0,0 @@ -//So much copypasta in this file, supposedly in the name of performance. If you change anything make sure to consider other places where the code may have been copied. - -/datum/light_source - var/atom/top_atom - var/atom/source_atom - - var/turf/source_turf - var/light_power - var/light_range - var/light_color // string, decomposed by parse_light_color() - - var/lum_r - var/lum_g - var/lum_b - - //hold onto the actual applied lum values so we can undo them when the lighting changes - var/tmp/applied_lum_r - var/tmp/applied_lum_g - var/tmp/applied_lum_b - - var/list/effect_str - var/list/effect_turf - - var/applied - - var/vis_update //Whetever we should smartly recalculate visibility. and then only update tiles that became (in) visible to us - var/needs_update - var/destroyed - var/force_update - -/datum/light_source/New(atom/owner, atom/top) - source_atom = owner - if(!source_atom.light_sources) source_atom.light_sources = list() - source_atom.light_sources += src - top_atom = top - if(top_atom != source_atom) - if(!top.light_sources) top.light_sources = list() - top_atom.light_sources += src - - source_turf = top_atom - light_power = source_atom.light_power - light_range = source_atom.light_range - light_color = source_atom.light_color - - parse_light_color() - - effect_str = list() - effect_turf = list() - - update() - - return ..() - - -//This proc is called manually on a light if you want it to be more responsive. -//It forces an update right now instead of waiting for the controller to get around to it, which can be up to 2.1 seconds -//Update is forced on this light source, and all tiles it effects. -//This can be very expensive and inefficient, use sparingly -/datum/light_source/proc/instant_update() - remove_lum() - if(!destroyed) - apply_lum() - - else if(vis_update) //We smartly update only tiles that became (in) visible to use. - smart_vis_update() - - vis_update = 0 - force_update = 0 - needs_update = 0 - - for (var/turf/T in effect_turf) - if (T.lighting_overlay) - T.lighting_overlay.update_overlay() - T.lighting_overlay.needs_update = 0 - - -/datum/light_source/proc/destroy() - destroyed = 1 - force_update() - if(source_atom && source_atom.light_sources) source_atom.light_sources -= src - if(top_atom && top_atom.light_sources) top_atom.light_sources -= src - -/datum/light_source/proc/update(atom/new_top_atom) - if(new_top_atom && new_top_atom != top_atom) - if(top_atom != source_atom) top_atom.light_sources -= src - top_atom = new_top_atom - if(top_atom != source_atom) - if(!top_atom.light_sources) top_atom.light_sources = list() - top_atom.light_sources += src - - if(!needs_update) //Incase we're already updating either way. - lighting_update_lights += src - needs_update = 1 - -/datum/light_source/proc/force_update() - force_update = 1 - if(!needs_update) //Incase we're already updating either way. - needs_update = 1 - lighting_update_lights += src - -/datum/light_source/proc/vis_update() - if(!needs_update) - needs_update = 1 - lighting_update_lights += src - - vis_update = 1 - -/datum/light_source/proc/check() - if(!source_atom || !light_range || !light_power) - destroy() - return 1 - - if(!top_atom) - top_atom = source_atom - . = 1 - - if(istype(top_atom, /turf)) - if(source_turf != top_atom) - source_turf = top_atom - . = 1 - else if(top_atom.loc != source_turf) - source_turf = top_atom.loc - . = 1 - - if(source_atom.light_power != light_power) - light_power = source_atom.light_power - . = 1 - - if(source_atom.light_range != light_range) - light_range = source_atom.light_range - . = 1 - - if(light_range && light_power && !applied) - . = 1 - - if(source_atom.light_color != light_color) - light_color = source_atom.light_color - parse_light_color() - . = 1 - -/datum/light_source/proc/parse_light_color() - if(light_color) - lum_r = GetRedPart(light_color) / 255 - lum_g = GetGreenPart(light_color) / 255 - lum_b = GetBluePart(light_color) / 255 - else - lum_r = 1 - lum_g = 1 - lum_b = 1 - -#if LIGHTING_FALLOFF == 1 //circular - #define LUM_DISTANCE(swapvar, O, T) swapvar = (O.x - T.x)**2 + (O.y - T.y)**2 + LIGHTING_HEIGHT - #if LIGHTING_LAMBERTIAN == 1 - #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(sqrt(swapvar) / max(1,light_range))) * (1 / sqrt(swapvar + 1))) - #else - #define LUM_ATTENUATION(swapvar) swapvar = 1 - CLAMP01(sqrt(swapvar) / max(1,light_range)) - #endif -#elif LIGHTING_FALLOFF == 2 //square - #define LUM_DISTANCE(swapvar, O, T) swapvar = abs(O.x - T.x) + abs(O.y - T.y) + LIGHTING_HEIGHT - #if LIGHTING_LAMBERTIAN == 1 - #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01((1 - CLAMP01(swapvar / max(1,light_range))) * (1 / sqrt(swapvar**2 + 1))) - #else - #define LUM_ATTENUATION(swapvar) swapvar = CLAMP01(swapvar / max(1,light_range)) - #endif -#endif - -#define LUM_FALLOFF(swapvar, O, T) \ - LUM_DISTANCE(swapvar, O, T); \ - LUM_ATTENUATION(swapvar); - -/datum/light_source/proc/apply_lum() - applied = 1 - - if (istype(source_atom.loc, /mob))//If the light is carried by a mob - var/mob/M = source_atom.loc - if (source_atom.offset_light)//And its an offset light - apply_lum_offset(M)//Then we call the special offset variant and terminate there. - return//This is split off to minimise overhead added to the majority of non-offset lights - - - //Keep track of the last applied lum values so that the lighting can be reversed - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b - - if(istype(source_turf)) - FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) - if(T.lighting_overlay) - var/strength - LUM_FALLOFF(strength, T, source_turf) - strength *= light_power - - if(!strength) //Don't add turfs that aren't affected to the affected turfs. - continue - - strength = round(strength, LIGHTING_ROUND_VALUE) //Screw sinking points. - - effect_str += strength - - T.lighting_overlay.update_lumcount( - applied_lum_r * strength, - applied_lum_g * strength, - applied_lum_b * strength - ) - - else - effect_str += 0 - - if(!T.affecting_lights) - T.affecting_lights = list() - - T.affecting_lights += src - effect_turf += T - END_FOR_DVIEW - - -//Duplicated code for speed. This is a variant of apply_lum for directional/offset lights carried by a mob -/datum/light_source/proc/apply_lum_offset(var/mob/M)//M is passed in for speed since we already fetched it - var/turf/lightfrom = get_step(M, M.dir)//Light source is offset infront of the user, simulates a directional light - var/list/dview = list() - - //We run a special DVIEW call to fetch the list of tiles viewable from the MOB's position - //This is cross referenced with the below DVIEW loop which runs through tiles viewable from the lightfrom position - //This is used to prevent offset lights shining through walls - DVIEW(dview, light_range, source_turf, INVISIBILITY_LIGHTING) - - - applied = 1 - - //Keep track of the last applied lum values so that the lighting can be reversed - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b - - if(istype(lightfrom)) - FOR_DVIEW(var/turf/T, light_range, lightfrom, INVISIBILITY_LIGHTING)//List of turfs visible from the light centre - if(T.lighting_overlay) - - if (!(T in dview))//If the turf is not also visible from the mob, then it's obscured and invalid - continue//Don't light this tile. This prevents offset lights from shining through walls - - var/strength - LUM_FALLOFF(strength, T, lightfrom) - - if (M && T == get_turf(M))//The light applied to the tile the holder is on is reduced, simulates directional light - strength *= light_power * (source_atom.owner_light_mult) - else - strength *= light_power - - if(!strength) //Don't add turfs that aren't affected to the affected turfs. - continue - - strength = round(strength, LIGHTING_ROUND_VALUE) //Screw sinking points. - - effect_str += strength - - T.lighting_overlay.update_lumcount( - applied_lum_r * strength, - applied_lum_g * strength, - applied_lum_b * strength - ) - - else - effect_str += 0 - - if(!T.affecting_lights) - T.affecting_lights = list() - - T.affecting_lights += src - effect_turf += T - END_FOR_DVIEW - - -/datum/light_source/proc/remove_lum() - applied = 0 - var/i = 1 - for(var/turf/T in effect_turf) - if(T.affecting_lights) - T.affecting_lights -= src - - if(T.lighting_overlay) - var/str = effect_str[i] - T.lighting_overlay.update_lumcount( - -str * applied_lum_r, - -str * applied_lum_g, - -str * applied_lum_b - ) - - i++ - - effect_str.Cut() - effect_turf.Cut() - -//Smartly updates the lighting, only removes lum from and adds lum to turfs that actually got changed. -//This is for lights that need to reconsider due to nearby opacity changes. -//Stupid dumb copy pasta because BYOND and speed. -/datum/light_source/proc/smart_vis_update() - var/list/view[0] - FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) - view += T //Filter out turfs. - END_FOR_DVIEW - //This is the part where we calculate new turfs (if any) - var/list/new_turfs = view - effect_turf //This will result with all the tiles that are added. - for(var/turf/T in new_turfs) - if(T.lighting_overlay) - LUM_FALLOFF(., T, source_turf) - . *= light_power - - if(!.) //Don't add turfs that aren't affected to the affected turfs. - continue - - . = round(., LIGHTING_ROUND_VALUE) - - effect_str += . - - T.lighting_overlay.update_lumcount( - applied_lum_r * ., - applied_lum_g * ., - applied_lum_b * . - ) - - else - effect_str += 0 - - if(!T.affecting_lights) - T.affecting_lights = list() - - T.affecting_lights += src - effect_turf += T - - var/list/old_turfs = effect_turf - view - for(var/turf/T in old_turfs) - //Insert not-so-huge copy paste from remove_lum(). - var/idx = effect_turf.Find(T) //Get the index, luckily Find() is cheap in small lists like this. (with small I mean under a couple thousand len) - if(T.affecting_lights) - T.affecting_lights -= src - - if(T.lighting_overlay) - var/str = effect_str[idx] - T.lighting_overlay.update_lumcount(-str * applied_lum_r, -str * applied_lum_g, -str * applied_lum_b) - - effect_turf.Cut(idx, idx + 1) - effect_str.Cut(idx, idx + 1) - -//Whoop yet not another copy pasta because speed ~~~~BYOND. -//Calculates and applies lighting for a single turf. This is intended for when a turf switches to -//using dynamic lighting when it was not doing so previously (when constructing a floor on space, for example). -//Assumes the turf is visible and such. -//For the love of god don't call this proc when it's not needed! Lighting artifacts WILL happen! -/datum/light_source/proc/calc_turf(var/turf/T) - var/idx = effect_turf.Find(T) - if(!idx) - return //WHY. - - if(T.lighting_overlay) - #if LIGHTING_FALLOFF == 1 // circular - . = (T.lighting_overlay.x - source_turf.x)**2 + (T.lighting_overlay.y - source_turf.y)**2 + LIGHTING_HEIGHT - #if LIGHTING_LAMBERTIAN == 1 - . = CLAMP01((1 - CLAMP01(sqrt(.) / light_range)) * (1 / (sqrt(. + 1)))) - #else - . = 1 - CLAMP01(sqrt(.) / light_range) - #endif - - #elif LIGHTING_FALLOFF == 2 // square - . = abs(T.lighting_overlay.x - source_turf.x) + abs(T.lighting_overlay.y - source_turf.y) + LIGHTING_HEIGHT - #if LIGHTING_LAMBERTIAN == 1 - . = CLAMP01((1 - CLAMP01(. / light_range)) * (1 / (sqrt(.)**2 + ))) - #else - . = 1 - CLAMP01(. / light_range) - #endif - #endif - . *= light_power - - . = round(., LIGHTING_ROUND_VALUE) - - effect_str[idx] = . - - //Since the applied_lum values are what are (later) removed by remove_lum. - //Anything we apply to the lighting overlays HAS to match what remove_lum uses. - T.lighting_overlay.update_lumcount( - applied_lum_r * ., - applied_lum_g * ., - applied_lum_b * . - ) - - - -//This function returns the illumination it would/did apply to the specified turf. -//It is useful for gathering information on a particular source's contribution to a turf's light -/datum/light_source/proc/get_lum(var/turf/T) - var/turf/lightfrom = source_turf - var/mob/M = null - var/list/dview = list() - var/list/castview = list() - - - if (istype(source_atom.loc, /mob)) - M = source_atom.loc - if (source_atom.offset_light) - DVIEW(dview, light_range, source_turf, INVISIBILITY_LIGHTING) - lightfrom = get_step(M, M.dir)//Light source is offset infront of the user, simulates a directional light - - applied = 1 - - //Keep track of the last applied lum values so that the lighting can be reversed - applied_lum_r = lum_r - applied_lum_g = lum_g - applied_lum_b = lum_b - - if(istype(lightfrom)) - - //Castview is a list of tiles seen from the light centre. - //If the desired turf isn't in it, then we couldn't contribute anything to that tile, return a zero list - DVIEW(castview, light_range, lightfrom, INVISIBILITY_LIGHTING) - if (!(T in castview)) - return list(0,0,0) - - if(T.lighting_overlay) - //Check for offset lights shining through walls - if (source_atom.offset_light) - if (!(T in dview)) - return list(0,0,0) - - var/strength - LUM_FALLOFF(strength, T, lightfrom) - - if (M && T == get_turf(M))//The light applied to the tile the holder is on is reduced, simulates directional light - strength *= light_power * (source_atom.owner_light_mult) - else - strength *= light_power - - if(!strength) //If no strength, then we contributed nothing. - return list(0,0,0) - - strength = round(strength, LIGHTING_ROUND_VALUE) - - //If we're here, then we've confirmed this light does affect the passed tile, and how much. - //Return the values we've applied to it. - return list( - applied_lum_r * strength, - applied_lum_g * strength, - applied_lum_b * strength) - - -#undef LUM_FALLOFF -#undef LUM_DISTANCE -#undef LUM_ATTENUATION diff --git a/code/modules/lighting/lighting_area.dm b/code/modules/lighting/lighting_area.dm new file mode 100644 index 00000000000..837070bb4b4 --- /dev/null +++ b/code/modules/lighting/lighting_area.dm @@ -0,0 +1,29 @@ +/area + luminosity = TRUE + var/dynamic_lighting = TRUE + +/area/New() + . = ..() + + if (dynamic_lighting) + luminosity = FALSE + +/area/proc/set_dynamic_lighting(var/new_dynamic_lighting = TRUE) + lprof_write(src, "area_sdl") + + if (new_dynamic_lighting == dynamic_lighting) + return FALSE + + dynamic_lighting = new_dynamic_lighting + + if (new_dynamic_lighting) + for (var/turf/T in turfs) + if (T.dynamic_lighting) + T.lighting_build_overlay() + + else + for (var/turf/T in turfs) + if (T.lighting_overlay) + T.lighting_clear_overlay() + + return TRUE diff --git a/code/modules/lighting/lighting_atom.dm b/code/modules/lighting/lighting_atom.dm index 6e5d858efca..17d2eb7868d 100644 --- a/code/modules/lighting/lighting_atom.dm +++ b/code/modules/lighting/lighting_atom.dm @@ -1,100 +1,153 @@ +#define MINIMUM_USEFUL_LIGHT_RANGE 1.4 + /atom - var/light_power = 1 // intensity of the light - var/light_range = 0 // range in tiles of the light - var/light_color // RGB string representing the colour of the light + var/light_power = 1 // Intensity of the light. + var/light_range = 0 // Range in tiles of the light. + var/light_color // Hexadecimal RGB string representing the colour of the light. + var/uv_intensity // How much UV light is being emitted by this object. Valid range: 0-255. - var/datum/light_source/light - var/list/light_sources + var/tmp/datum/light_source/light // Our light source. Don't fuck with this directly unless you have a good reason! + var/tmp/list/light_sources // Any light sources that are "inside" of us, for example, if src here was a mob that's carrying a flashlight, that flashlight's light source would be part of this list. - //If this var is set, and this object casts light, and the object is worn/held on a mob - //Then the light source will be offset this many tiles in the mob's facing direction - //To make this work, must make sure this object is set as the source atom of any lightsource it creates - //For now, this will only offset one tile, regardless of the value set, but this can be expanded in future - var/offset_light = 0 +// Nonesensical value for l_color default, so we can detect if it gets set to null. +#define NONSENSICAL_VALUE -99999 - //If this object emits light and is worn/held on a mob - //The light applied to the owner's tile is multiplied by this value - //This is a means to simulate directional light and is only used with offset_light - var/owner_light_mult = 0.5 +#define SET_LIGHT set_light(l_range,l_power,l_color,uv,update_type);return; +// Same as set_light(), but only does something if there's actually a change in state. +/atom/proc/diff_light(/var/l_range, var/l_power, var/l_color = NONSENSICAL_VALUE, var/uv = NONSENSICAL_VALUE, var/update_type = UPDATE_SCHEDULE) + if (l_range != light_range) + SET_LIGHT + if (l_power && l_power != light_power) + SET_LIGHT + if (l_color != NONSENSICAL_VALUE && l_color != light_color) + SET_LIGHT + if (uv != NONSENSICAL_VALUE) + SET_LIGHT + if (update_type != UPDATE_SCHEDULE) + SET_LIGHT - //If 1, this light has reduced effect on diona - //It won't stack with other restricted light sources - var/diona_restricted_light = 0 +#undef SET_LIGHT +// The proc you should always use to set the light of this atom. +/atom/proc/set_light(var/l_range, var/l_power, var/l_color = NONSENSICAL_VALUE, var/uv = NONSENSICAL_VALUE, var/update_type = UPDATE_SCHEDULE) + lprof_write(src, "atom_setlight") -/atom/proc/set_light(l_range, l_power, l_color) - . = 0 //make it less costly if nothing's changed - - if(l_power != null && l_power != light_power) + if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE) + l_range = MINIMUM_USEFUL_LIGHT_RANGE //Brings the range up to 1.4, which is just barely brighter than the soft lighting that surrounds players. + if (l_power != null) light_power = l_power - . = 1 - if(l_range != null && l_range != light_range) + + if (l_range != null) light_range = l_range - . = 1 - if(l_color != null && l_color != light_color) + + if (l_color != NONSENSICAL_VALUE) light_color = l_color - . = 1 - if(.) update_light() + if (uv != NONSENSICAL_VALUE) + set_uv(uv, update_type = UPDATE_NONE) -/atom/proc/copy_light(atom/A) - set_light(A.light_range, A.light_power, A.light_color) + switch (update_type) + if (UPDATE_SCHEDULE) + update_light() + if (UPDATE_NOW) + update_light(TRUE) -/atom/proc/update_light() - if(!light_power || !light_range) +#undef NONSENSICAL_VALUE + +/atom/proc/set_uv(var/intensity, var/update_type = UPDATE_SCHEDULE) + if (intensity < 0 || intensity > 255) + intensity = min(max(intensity, 255), 0) + + uv_intensity = intensity + + if (update_type != UPDATE_NONE) + update_light(update_type) + +// Will update the light (duh). +// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf... +/atom/proc/update_light(var/update_type = UPDATE_SCHEDULE) + set waitfor = FALSE + if (gcDestroyed) + return + + lprof_write(src, "atom_update") + + if (!light_power || !light_range) // We won't emit light anyways, destroy the light source. if(light) light.destroy() light = null else - if(!istype(loc, /atom/movable)) + if (!istype(loc, /atom/movable)) // We choose what atom should be the top atom of the light here. . = src else . = loc - if(light) - light.update(.) + if (light) // Update the light or create it if it does not exist. + light.update(., update_type) else - light = new /datum/light_source(src, .) + light = new/datum/light_source(src, .) +// Incase any lighting vars are on in the typepath we turn the light on in New(). /atom/New() . = ..() - if(light_power && light_range) + + if (light_power && light_range) update_light() + if (opacity && isturf(loc)) + var/turf/T = loc + T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways. + +// Destroy our light source so we GC correctly. /atom/Destroy() - if(light) + if (light) light.destroy() light = null - return ..() + . = ..() +// If we have opacity, make sure to tell (potentially) affected light sources. /atom/movable/Destroy() var/turf/T = loc - if(opacity && istype(T)) + if (opacity && istype(T)) T.reconsider_lights() - return ..() -/atom/Entered(atom/movable/obj, atom/prev_loc) . = ..() - if(obj && prev_loc != src) - for(var/datum/light_source/L in obj.light_sources) - L.source_atom.update_light() +// Should always be used to change the opacity of an atom. +// It notifies (potentially) affected light sources so they can update (if needed). +/atom/proc/set_opacity(var/new_opacity) + if (new_opacity == opacity) + return + + lprof_write(src, "atom_setopacity") -/atom/proc/set_opacity(new_opacity) - var/old_opacity = opacity opacity = new_opacity var/turf/T = loc - if(old_opacity != new_opacity && istype(T)) + if (!isturf(T)) + return + + if (new_opacity == TRUE) + T.has_opaque_atom = TRUE T.reconsider_lights() + else + var/old_has_opaque_atom = T.has_opaque_atom + T.recalc_atom_opacity() + if (old_has_opaque_atom != T.has_opaque_atom) + T.reconsider_lights() -/obj/item/equipped() - . = ..() - update_light() -/obj/item/pickup() +// This code makes the light be queued for update when it is moved. +// Entered() should handle it, however Exited() can do it if it is being moved to nullspace (as there would be no Entered() call in that situation). +/atom/Entered(var/atom/movable/Obj, var/atom/OldLoc) //Implemented here because forceMove() doesn't call Move() . = ..() - update_light() -/obj/item/dropped() + if (Obj && OldLoc != src) + for (var/datum/light_source/L in Obj.light_sources) // Cycle through the light sources on this atom and tell them to update. + L.source_atom.update_light(update_type = UPDATE_NOW) + +/atom/Exited(var/atom/movable/Obj, var/atom/newloc) . = ..() - update_light() + + if (!newloc && Obj && newloc != src) // Incase the atom is being moved to nullspace, we handle queuing for a lighting update here. + for (var/datum/light_source/L in Obj.light_sources) // Cycle through the light sources on this atom and tell them to update. + L.source_atom.update_light(update_type = UPDATE_NOW) diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm new file mode 100644 index 00000000000..05ba71d9af1 --- /dev/null +++ b/code/modules/lighting/lighting_corner.dm @@ -0,0 +1,134 @@ +/var/list/datum/lighting_corner/all_lighting_corners = list() +/var/datum/lighting_corner/dummy/dummy_lighting_corner = new +// Because we can control each corner of every lighting overlay. +// And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). +// For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. + +// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. +/var/list/LIGHTING_CORNER_DIAGONAL = list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST) + +/datum/lighting_corner + var/list/turf/masters = list() + var/list/datum/light_source/affecting = list() // Light sources affecting us. + var/active = FALSE // TRUE if one of our masters has dynamic lighting. + + var/x = 0 + var/y = 0 + var/z = 0 + + var/lum_r = 0 + var/lum_g = 0 + var/lum_b = 0 + var/lum_u = 0 // UV Radiation, not visible. + + var/needs_update = FALSE + + var/cache_r = 0 + var/cache_g = 0 + var/cache_b = 0 + var/cache_u = 0 + var/cache_mx = 0 + + var/update_gen = 0 + +/datum/lighting_corner/New(var/turf/new_turf, var/diagonal) + . = ..() + + all_lighting_corners += src + + masters[new_turf] = turn(diagonal, 180) + z = new_turf.z + + var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. + var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one. + + x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5) + y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5) + + // My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal). + // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. + // So we'll have this hardcode instead. + var/turf/T + var/i + + // Diagonal one is easy. + T = get_step(new_turf, diagonal) + if (T) // In case we're on the map's border. + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = diagonal + i = LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) + T.corners[i] = src + + // Now the horizontal one. + T = get_step(new_turf, horizontal) + if (T) // Ditto. + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. + i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) + T.corners[i] = src + + // And finally the vertical one. + T = get_step(new_turf, vertical) + if (T) + if (!T.corners) + T.corners = list(null, null, null, null) + + masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. + i = LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) + T.corners[i] = src + + update_active() + +/datum/lighting_corner/proc/update_active() + active = FALSE + for (var/turf/T in masters) + if (T.lighting_overlay) + active = TRUE + +// God that was a mess, now to do the rest of the corner code! Hooray! +/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b, var/delta_u, var/update_type = UPDATE_SCHEDULE) + lum_r += delta_r + lum_g += delta_g + lum_b += delta_b + lum_u += delta_u + + if (update_type == UPDATE_SCHEDULE && !needs_update) + needs_update = TRUE + update_overlays(update_type) + lighting_update_corners += src + else if (!needs_update) + update_overlays(UPDATE_NOW) + +/datum/lighting_corner/proc/update_overlays(var/update_type = UPDATE_SCHEDULE) + + // Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually. + var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1. + . = 1 // factor + if (mx > 1) + . = 1 / mx + + else if (mx < LIGHTING_SOFT_THRESHOLD) + . = 0 // 0 means soft lighting. + + cache_r = lum_r * . || LIGHTING_SOFT_THRESHOLD + cache_g = lum_g * . || LIGHTING_SOFT_THRESHOLD + cache_b = lum_b * . || LIGHTING_SOFT_THRESHOLD + cache_u = lum_u * . || LIGHTING_SOFT_THRESHOLD + cache_mx = mx + + for (var/TT in masters) + var/turf/T = TT + if (T.lighting_overlay) + if (update_type == UPDATE_NOW) // UPDATE_NONE is meaningless here. + T.lighting_overlay.update_overlay() + + else if (!T.lighting_overlay.needs_update) + T.lighting_overlay.needs_update = TRUE + lighting_update_overlays += T.lighting_overlay + +/datum/lighting_corner/dummy/New() + return diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 2dd3889e4e9..5ca3776bab8 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -1,102 +1,111 @@ +/var/list/all_lighting_overlays = list() // Global list of lighting overlays. + /atom/movable/lighting_overlay - name = "" + name = "" + anchored = TRUE + icon = LIGHTING_ICON + color = LIGHTING_BASE_MATRIX mouse_opacity = 0 - simulated = 0 - anchored = 1 + layer = LIGHTING_LAYER + invisibility = INVISIBILITY_LIGHTING + simulated = 0 + blend_mode = BLEND_MULTIPLY - icon = LIGHTING_ICON - icon_state = "light1" - layer = LIGHTING_LAYER - invisibility = INVISIBILITY_LIGHTING - color = "#000000" + var/needs_update = FALSE - var/lum_r - var/lum_g - var/lum_b + #if WORLD_ICON_SIZE != 32 + transform = matrix(WORLD_ICON_SIZE / 32, 0, (WORLD_ICON_SIZE - 32) / 2, 0, WORLD_ICON_SIZE / 32, (WORLD_ICON_SIZE - 32) / 2) + #endif - var/needs_update - -/atom/movable/lighting_overlay/New() +/atom/movable/lighting_overlay/New(var/atom/loc, var/no_update = FALSE) . = ..() verbs.Cut() + global.all_lighting_overlays += src - var/turf/T = loc //If this runtimes atleast we'll know what's creating overlays in things that aren't turfs. - T.luminosity = 0 + var/turf/T = loc // If this runtimes atleast we'll know what's creating overlays in things that aren't turfs. + T.lighting_overlay = src + T.luminosity = 0 -/atom/movable/lighting_overlay/proc/update_lumcount(delta_r, delta_g, delta_b) - if(!delta_r && !delta_g && !delta_b) //Nothing is being changed all together. + if (no_update) return - var/should_update = 0 + update_overlay() - if(!needs_update) //If this isn't true, we're already updating anyways. - if(max(lum_r, lum_g, lum_b) < 1) //Any change that could happen WILL change appearance. - should_update = 1 +/atom/movable/lighting_overlay/Destroy() + global.all_lighting_overlays -= src + global.lighting_update_overlays -= src + lighting_process.curr_overlays -= src - else if(max(lum_r + delta_r, lum_g + delta_g, lum_b + delta_b) < 1) //The change would bring us under 1 max lum, again, guaranteed to change appearance. - should_update = 1 + var/turf/T = loc + if (istype(T)) + T.lighting_overlay = null + T.luminosity = 1 - else //We need to make sure that the colour ratios won't change in this code block. - var/mx1 = max(lum_r, lum_g, lum_b) - var/mx2 = max(lum_r + delta_r, lum_g + delta_g, lum_b + delta_b) - - if(lum_r / mx1 != (lum_r + delta_r) / mx2 || lum_g / mx1 != (lum_g + delta_g) / mx2 || lum_b / mx1 != (lum_b + delta_b) / mx2) //Stuff would change. - should_update = 1 - - lum_r += delta_r - lum_g += delta_g - lum_b += delta_b - - if(!needs_update && should_update) - needs_update = 1 - lighting_update_overlays += src + ..() /atom/movable/lighting_overlay/proc/update_overlay() var/turf/T = loc + if (!istype(T)) // Erm... + if (loc) + warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc], [loc.type]) in update_overlay() and got pooled!") - if(istype(T)) //Incase we're not on a turf, pool ourselves, something happened. - if(lum_r == lum_g && lum_r == lum_b) //greyscale - blend_mode = BLEND_OVERLAY - if(lum_r <= 0) - T.luminosity = 0 - color = "#000000" - alpha = 255 - else - T.luminosity = 1 - color = "#000000" - alpha = (1 - min(lum_r, 1)) * 255 else - alpha = 255 - var/mx = max(lum_r, lum_g, lum_b) - . = 1 // factor - if(mx > 1) - . = 1/mx - blend_mode = BLEND_MULTIPLY - color = rgb(lum_r * 255 * ., lum_g * 255 * ., lum_b * 255 * .) - if(color != "#000000") - T.luminosity = 1 - else //No light, set the turf's luminosity to 0 to remove it from view() - T.luminosity = 0 - else - warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc][loc ? ", " + loc.type : ""]) in update_overlay() and got pooled!") - qdel(src) + warning("A lighting overlay realised it was in nullspace in update_overlay() and got pooled!") -/atom/movable/lighting_overlay/ResetVars() - loc = null + returnToPool(src) + return - lum_r = 0 - lum_g = 0 - lum_b = 0 + if (T.is_space()) + warning("A lighting overlay realised it was attached to a space tile and got pooled!") + returnToPool(src) + return - color = "#000000" + // To the future coder who sees this and thinks + // "Why didn't he just use a loop?" + // Well my man, it's because the loop performed like shit. + // And there's no way to improve it because + // without a loop you can make the list all at once which is the fastest you're gonna get. + // Oh it's also shorter line wise. + // Including with these comments. - needs_update = 0 + // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. + // No I seriously cannot think of a more efficient method, fuck off Comic. + var/datum/lighting_corner/cr = T.corners[3] || dummy_lighting_corner + var/datum/lighting_corner/cg = T.corners[2] || dummy_lighting_corner + var/datum/lighting_corner/cb = T.corners[4] || dummy_lighting_corner + var/datum/lighting_corner/ca = T.corners[1] || dummy_lighting_corner -/atom/movable/lighting_overlay/Destroy() - lighting_update_overlays -= src + var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) - var/turf/T = loc - if(istype(T)) - T.lighting_overlay = null - - ..() + color = list( + cr.cache_r, cr.cache_g, cr.cache_b, 0, + cg.cache_r, cg.cache_g, cg.cache_b, 0, + cb.cache_r, cb.cache_g, cb.cache_b, 0, + ca.cache_r, ca.cache_g, ca.cache_b, 0, + 0, 0, 0, 1 + ) + luminosity = max > LIGHTING_SOFT_THRESHOLD + +// Variety of overrides so the overlays don't get affected by weird things. + +/atom/movable/lighting_overlay/ex_act(severity) + return 0 + +/atom/movable/lighting_overlay/singularity_act() + return + +/atom/movable/lighting_overlay/singularity_pull() + return + +/atom/movable/lighting_overlay/singuloCanEat() + return FALSE + +// Override here to prevent things accidentally moving around overlays. +/atom/movable/lighting_overlay/forceMove(atom/destination, var/no_tp=FALSE, var/harderforce = FALSE) + if(harderforce) + . = ..() + +/atom/movable/lighting_overlay/resetVariables(...) + color = LIGHTING_BASE_MATRIX + + return ..("color") diff --git a/code/modules/lighting/lighting_process.dm b/code/modules/lighting/lighting_process.dm deleted file mode 100644 index 562fd1aea6f..00000000000 --- a/code/modules/lighting/lighting_process.dm +++ /dev/null @@ -1,43 +0,0 @@ -var/datum/controller/process/lighting/lighting_process - -/datum/controller/process/lighting - var/last_light_count = 0 - var/last_overlay_count = 0 - -/datum/controller/process/lighting/setup() - name = "lighting" - schedule_interval = LIGHTING_INTERVAL - create_lighting_overlays() - lighting_process = src - -/datum/controller/process/lighting/doWork() - var/list/lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from SCHECK don't cause things to be cut from the list without being updated. - last_light_count = lighting_update_lights.len - lighting_update_lights = null //Nulling it first because of http://www.byond.com/forum/?post=1854520 - lighting_update_lights = list() - - for(var/datum/light_source/L in lighting_update_lights_old) - if(L.destroyed || L.check() || L.force_update) - L.remove_lum() - if(!L.destroyed) - L.apply_lum() - - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() - - L.vis_update = 0 - L.force_update = 0 - L.needs_update = 0 - - SCHECK - - var/list/lighting_update_overlays_old = lighting_update_overlays //Same as above. - last_overlay_count = lighting_update_overlays.len - lighting_update_overlays = null //Same as above - lighting_update_overlays = list() - - for(var/atom/movable/lighting_overlay/O in lighting_update_overlays_old) - O.update_overlay() - O.needs_update = 0 - - SCHECK diff --git a/code/modules/lighting/lighting_profiler.dm b/code/modules/lighting/lighting_profiler.dm new file mode 100644 index 00000000000..484aa224977 --- /dev/null +++ b/code/modules/lighting/lighting_profiler.dm @@ -0,0 +1,40 @@ +// Writes lighting updates to the database. +// FOR DEBUGGING ONLY! + +/proc/lprof_write(var/atom/movable/obj, var/type = "UNKNOWN") + if (!lighting_profiling || !obj || !establish_db_connection(dbcon)) + return + + var/x = null + var/y = null + var/z = null + + var/name = null + var/locname = null + if (istype(obj, /obj)) + name = obj.name + locname = obj.loc.name + x = obj.loc.x + y = obj.loc.y + z = obj.loc.z + + var/static/DBQuery/lprof_q + if (!lprof_q) + lprof_q = dbcon.NewQuery({"INSERT INTO ss13dbg_lighting (time,type,name,loc_name,x,y,z) + VALUES (:time,:type,:name,:loc_name,:x,:y,:z);"}) + + lprof_q.Execute( + list( + ":time" = world.time, + ":type" = type, + ":name" = name, + ":loc_name" = locname, + ":x" = x, + ":y" = y, + ":z" = z)) + + var/err = lprof_q.ErrorMsg() + if (err) + log_debug("lprof_write: SQL Error: [err]") + message_admins(span("danger", "SQL Error during lighting profiling; disabling!")) + lighting_profiling = FALSE diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm new file mode 100644 index 00000000000..439feb81f27 --- /dev/null +++ b/code/modules/lighting/lighting_setup.dm @@ -0,0 +1,84 @@ +/proc/create_lighting_overlays_zlevel(var/zlevel) + ASSERT(zlevel) + + for (var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))) + if (!T.dynamic_lighting) + continue + + var/area/A = T.loc + if (!A.dynamic_lighting) + continue + + getFromPool(/atom/movable/lighting_overlay, T, TRUE) + +// This repeats a bit of code from the lighting process. +/proc/initialize_lighting() + admin_notice(span("danger", "Generating lighting overlays (1/4)...")) + for (var/zlevel = 1 to world.maxz) + create_lighting_overlays_zlevel(zlevel) + CHECK_TICK + + admin_notice(span("danger", "Initializing light sources (2/4)...")) + var/num_lights = 0 + var/list/lights = lighting_update_lights + lighting_update_lights = list() + + while (lights.len) + var/datum/light_source/L = lights[lights.len] + lights.len-- + + if (!L) continue + + if (L.check() || L.destroyed || L.force_update) + L.remove_lum() + if(!L.destroyed) + L.apply_lum() + + else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. + L.smart_vis_update() + + L.vis_update = FALSE + L.force_update = FALSE + L.needs_update = FALSE + num_lights++ + CHECK_TICK + + admin_notice(span("danger", "Processed [num_lights] light sources.")) + + admin_notice(span("danger", "Initializing lighting corners (3/4)...")) + var/num_corners = 0 + var/list/corners = lighting_update_corners + lighting_update_corners = list() + + while (corners.len) + var/datum/lighting_corner/C = corners[corners.len] + corners.len-- + + if (!C) continue + + C.update_overlays() + + C.needs_update = FALSE + num_corners++ + + CHECK_TICK + + admin_notice(span("danger", "Processed [num_corners] light corners.")) + admin_notice(span("danger", "Initializing lighting overlays (4/4)...")) + var/num_overlays = 0 + var/list/overlays = lighting_update_overlays + lighting_update_overlays = list() + + while (overlays.len) + var/atom/movable/lighting_overlay/O = overlays[overlays.len] + overlays.len-- + + if (!O) continue + + O.update_overlay() + O.needs_update = FALSE + + num_overlays++ + CHECK_TICK + + admin_notice(span("danger", "Processed [num_overlays] light overlays.")) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm new file mode 100644 index 00000000000..f3e13daaf77 --- /dev/null +++ b/code/modules/lighting/lighting_source.dm @@ -0,0 +1,320 @@ +// This is where the fun begins. +// These are the main datums that emit light. + +/datum/light_source + var/atom/top_atom // The atom we're emitting light from (for example a mob if we're from a flashlight that's being held). + var/atom/source_atom // The atom that we belong to. + + var/turf/source_turf // The turf under the above. + var/light_power // Intensity of the emitter light. + var/light_range // The range of the emitted light. + var/light_color // The colour of the light, string, decomposed by parse_light_color() + var/light_uv // The intensity of UV light, between 0 and 255. + + // Variables for keeping track of the colour. + var/lum_r + var/lum_g + var/lum_b + var/lum_u + + // The lumcount values used to apply the light. + var/tmp/applied_lum_r + var/tmp/applied_lum_g + var/tmp/applied_lum_b + var/tmp/applied_lum_u + + var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. + var/list/turf/affecting_turfs + + var/applied = FALSE // Whether we have applied our light yet or not. + + var/vis_update // Whether we should smartly recalculate visibility. and then only update tiles that became (in)visible to us. + var/needs_update // Whether we are queued for an update. + var/destroyed // Whether we are destroyed and need to stop emitting light. + var/force_update + +/datum/light_source/New(var/atom/owner, var/atom/top, var/update_t = UPDATE_SCHEDULE) + source_atom = owner // Set our new owner. + if (!source_atom.light_sources) + source_atom.light_sources = list() + + source_atom.light_sources += src // Add us to the lights of our owner. + top_atom = top + if (top_atom != source_atom) + if (!top.light_sources) + top.light_sources = list() + + top_atom.light_sources += src + + source_turf = top_atom + light_power = source_atom.light_power + light_range = source_atom.light_range + light_color = source_atom.light_color + light_uv = source_atom.uv_intensity + + parse_light_color() + + effect_str = list() + affecting_turfs = list() + + update(update_type = update_t) + + lprof_write(src, "source_new") + + return ..() + +// Kill ourselves. +/datum/light_source/proc/destroy() + destroyed = TRUE + force_update() + if (source_atom && source_atom.light_sources) + source_atom.light_sources -= src + + if (top_atom && top_atom.light_sources) + top_atom.light_sources -= src + +/datum/light_source/proc/effect_update_now() + lprof_write(src, "source_updatenow") + if (check() || destroyed || force_update) + remove_lum(TRUE) + if (!destroyed) + apply_lum(update_type = UPDATE_NOW) + + else if (vis_update) // We smartly update only tiles that became (in) visible to use. + smart_vis_update(update_type = UPDATE_NOW) + + vis_update = FALSE + force_update = FALSE + needs_update = FALSE + +// Call it dirty, I don't care. +// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates. +// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a () macro that has no arguments :|. +#define effect_update(BYOND) \ + if (!needs_update) \ + { \ + lighting_update_lights += src; \ + needs_update = TRUE; \ + } + +// This proc will cause the light source to update the top atom, and add itself to the update queue. +/datum/light_source/proc/update(var/atom/new_top_atom, var/update_type = UPDATE_SCHEDULE) + // This top atom is different. + if (new_top_atom && new_top_atom != top_atom) + if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom. + top_atom.light_sources -= src + + top_atom = new_top_atom + + if (top_atom != source_atom) + if(!top_atom.light_sources) + top_atom.light_sources = list() + + top_atom.light_sources += src // Add ourselves to the light sources of our new top atom. + + lprof_write(src, "source_update") + + if (update_type == UPDATE_NOW) + effect_update_now() + else if (update_type == UPDATE_SCHEDULE) // I don't know why you would call this with UPDATE_NONE, but hey. + effect_update(null) + +// Will force an update without checking if it's actually needed. +/datum/light_source/proc/force_update() + lprof_write(src, "source_forceupdate") + force_update = 1 + + effect_update(null) + +// Will cause the light source to recalculate turfs that were removed or added to visibility only. +/datum/light_source/proc/vis_update() + vis_update = 1 + + effect_update(null) + +// Will check if we actually need to update, and update any variables that may need to be updated. +/datum/light_source/proc/check() + if (!source_atom || !light_range || !light_power) + destroy() + return 1 + + if (!top_atom) + top_atom = source_atom + . = 1 + + if (istype(top_atom, /turf)) + if (source_turf != top_atom) + source_turf = top_atom + . = 1 + else if (top_atom.loc != source_turf) + source_turf = top_atom.loc + . = 1 + + if (source_atom.light_power != light_power) + light_power = source_atom.light_power + . = 1 + + if (source_atom.light_range != light_range) + light_range = source_atom.light_range + . = 1 + + if (light_range && light_power && !applied) + . = 1 + + if (source_atom.light_color != light_color) + light_color = source_atom.light_color + parse_light_color() + . = 1 + +// Decompile the hexadecimal colour into lumcounts of each perspective. +/datum/light_source/proc/parse_light_color() + if (light_color) + lum_r = GetRedPart (light_color) / 255 + lum_g = GetGreenPart (light_color) / 255 + lum_b = GetBluePart (light_color) / 255 + else + lum_r = 1 + lum_g = 1 + lum_b = 1 + + if (light_uv) + lum_u = light_uv / 255 + else + lum_u = 0 + +// Macro that applies light to a new corner. +// It is a macro in the interest of speed, yet not having to copy paste it. +// If you're wondering what's with the backslashes, the backslashes cause BYOND to not automatically end the line. +// As such this all gets counted as a single line. +// The braces and semicolons are there to be able to do this on a single line. + +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, source_turf); \ + \ + . *= light_power; \ + \ + effect_str[C] = .; \ + \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b, \ + . * applied_lum_u, \ + update_type \ + ); + +// I don't need to explain what this does, do I? +#define REMOVE_CORNER(C) \ + . = -effect_str[C]; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b, \ + . * applied_lum_u, \ + update_type \ + ); + +// This is the define used to calculate falloff. +#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) + +/datum/light_source/proc/apply_lum(var/update_type = UPDATE_SCHEDULE) + var/static/update_gen = 1 + applied = 1 + + // Keep track of the last applied lum values so that the lighting can be reversed + applied_lum_r = lum_r + applied_lum_g = lum_g + applied_lum_b = lum_b + applied_lum_u = lum_u + + FOR_DVIEW(var/turf/T, light_range, source_turf, INVISIBILITY_LIGHTING) + if (!T.lighting_corners_initialised) + T.generate_missing_corners() + + for (var/datum/lighting_corner/C in T.get_corners()) + if (C.update_gen == update_gen) + continue + + C.update_gen = update_gen + C.affecting += src + + if (!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + if (!T.affecting_lights) + T.affecting_lights = list() + + T.affecting_lights += src + affecting_turfs += T + + update_gen++ + +/datum/light_source/proc/remove_lum(var/update_type = UPDATE_SCHEDULE) + applied = FALSE + + for (var/turf/T in affecting_turfs) + if (!T.affecting_lights) + T.affecting_lights = list() + else + T.affecting_lights -= src + + affecting_turfs.Cut() + + for (var/datum/lighting_corner/C in effect_str) + REMOVE_CORNER(C) + + C.affecting -= src + + effect_str.Cut() + +/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C) + var/update_type = UPDATE_SCHEDULE // for (APPLY|REMOVE)_CORNER. + if (effect_str.Find(C)) // Already have one. + REMOVE_CORNER(C) + + APPLY_CORNER(C) + +/datum/light_source/proc/smart_vis_update(var/update_type = UPDATE_SCHEDULE) + var/list/datum/lighting_corner/corners = list() + var/list/turf/turfs = list() + FOR_DVIEW(var/turf/T, light_range, source_turf, 0) + if (!T.lighting_corners_initialised) + T.generate_missing_corners() + corners |= T.get_corners() + turfs += T + + var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. + affecting_turfs += L + for (var/turf/T in L) + if (!T.affecting_lights) + T.affecting_lights = list(src) + else + T.affecting_lights += src + + L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. + affecting_turfs -= L + for (var/turf/T in L) + T.affecting_lights -= src + + for (var/datum/lighting_corner/C in corners - effect_str) // New corners + C.affecting += src + if (!C.active) + effect_str[C] = 0 + continue + + APPLY_CORNER(C) + + for (var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners. + REMOVE_CORNER(C) + C.affecting -= src + effect_str -= C + +#undef effect_update +#undef LUM_FALLOFF +#undef REMOVE_CORNER +#undef APPLY_CORNER diff --git a/code/modules/lighting/lighting_system.dm b/code/modules/lighting/lighting_system.dm deleted file mode 100644 index 0c84294f35e..00000000000 --- a/code/modules/lighting/lighting_system.dm +++ /dev/null @@ -1,25 +0,0 @@ -/var/list/lighting_update_lights = list() -/var/list/lighting_update_overlays = list() - -/area/var/lighting_use_dynamic = 1 - -// duplicates lots of code, but this proc needs to be as fast as possible. -/proc/create_lighting_overlays(zlevel = 0) - var/area/A - if(zlevel == 0) // populate all zlevels - for(var/turf/T in world) - if(T.dynamic_lighting) - A = T.loc - if(A.lighting_use_dynamic) - var/atom/movable/lighting_overlay/O = PoolOrNew(/atom/movable/lighting_overlay, T) - T.lighting_overlay = O - - else - for(var/x = 1; x <= world.maxx; x++) - for(var/y = 1; y <= world.maxy; y++) - var/turf/T = locate(x, y, zlevel) - if(T.dynamic_lighting) - A = T.loc - if(A.lighting_use_dynamic) - var/atom/movable/lighting_overlay/O = PoolOrNew(/atom/movable/lighting_overlay, T) - T.lighting_overlay = O diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index f8f0a5ab102..0d2887699be 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -1,32 +1,137 @@ /turf - var/list/affecting_lights - var/atom/movable/lighting_overlay/lighting_overlay + var/dynamic_lighting = TRUE + luminosity = 1 + var/tmp/lighting_corners_initialised = FALSE + + var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf. + var/tmp/atom/movable/lighting_overlay/lighting_overlay // Our lighting overlay. + var/tmp/list/datum/lighting_corner/corners + var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile. + +/turf/New() + . = ..() + + if (opacity) + has_opaque_atom = TRUE + +// Causes any affecting light sources to be queued for a visibility update, for example a door got opened. /turf/proc/reconsider_lights() - for(var/datum/light_source/L in affecting_lights) + lprof_write(src, "turf_reconsider") + for (var/datum/light_source/L in affecting_lights) L.vis_update() -/turf/proc/lighting_clear_overlays() - if(lighting_overlay) - qdel(lighting_overlay) +// Avoid calling this if you can, bypasses the lighting scheduler (potentially creating lag). +/turf/proc/update_lights_now() + lprof_write(src, "turf_updatenow") + for (var/datum/light_source/L in affecting_lights) + L.update(update_type = UPDATE_NOW) -/turf/proc/lighting_build_overlays() - if(!lighting_overlay) - var/area/A = loc - if(A.lighting_use_dynamic) - var/atom/movable/lighting_overlay/O = PoolOrNew(/atom/movable/lighting_overlay, src) - lighting_overlay = O +/turf/proc/lighting_clear_overlay() + if (lighting_overlay) + returnToPool(lighting_overlay) - //Make the light sources recalculate us so the lighting overlay updates immediately - for(var/datum/light_source/L in affecting_lights) - L.calc_turf(src) + for (var/datum/lighting_corner/C in corners) + C.update_active() -/turf/Entered(atom/movable/obj) +// Builds a lighting overlay for us, but only if our area is dynamic. +/turf/proc/lighting_build_overlay() + if (lighting_overlay) + return + + var/area/A = loc + if (A.dynamic_lighting && dynamic_lighting) + if (!lighting_corners_initialised) + generate_missing_corners() + + getFromPool(/atom/movable/lighting_overlay, src) + + for (var/datum/lighting_corner/C in corners) + if (!C.active) // We would activate the corner, calculate the lighting for it. + for (var/L in C.affecting) + var/datum/light_source/S = L + S.recalc_corner(C) + + C.active = TRUE + +#define SCALE(targ,min,max) (targ - min) / (max - min) + +// Used to get a scaled lumcount. +/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1) + if (!lighting_overlay) + return 0.5 + + var/totallums = 0 + for (var/datum/lighting_corner/L in corners) + totallums += L.lum_r + L.lum_b + L.lum_g + + totallums /= 12 // 4 corners, each with 3 channels, get the average. + + totallums = SCALE(totallums, minlum, maxlum) + + return CLAMP01(totallums) + +// Gets the current UV illumination of the turf. Always 100% for space. +/turf/proc/get_uv_lumcount(var/minlum = 0, var/maxlum = 1) + if (!lighting_overlay) + return 1 + + var/totallums = 0 + for (var/datum/lighting_corner/L in corners) + totallums += L.lum_u + + totallums /= 4 // average of four corners. + + totallums = SCALE(totallums, minlum, maxlum) + + return CLAMP01(totallums) + +#undef SCALE + +// Can't think of a good name, this proc will recalculate the has_opaque_atom variable. +/turf/proc/recalc_atom_opacity() + has_opaque_atom = FALSE + for (var/atom/A in src.contents + src) // Loop through every movable atom on our tile PLUS ourselves (we matter too...) + if (A.opacity) + has_opaque_atom = TRUE + return // No need to continue if we find something opaque. + +// If an opaque movable atom moves around we need to potentially update visibility. +/turf/Entered(var/atom/movable/Obj, var/atom/OldLoc) . = ..() - if(obj && obj.opacity) + + if (Obj && Obj.opacity) + has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. reconsider_lights() -/turf/Exited(atom/movable/obj) +/turf/Exited(var/atom/movable/Obj, var/atom/newloc) . = ..() - if(obj && obj.opacity) + + if (Obj && Obj.opacity) + recalc_atom_opacity() // Make sure to do this before reconsider_lights(), incase we're on instant updates. reconsider_lights() + +/turf/change_area(var/area/old_area, var/area/new_area) + if (new_area.dynamic_lighting != old_area.dynamic_lighting) + if (new_area.dynamic_lighting) + lighting_build_overlay() + + else + lighting_clear_overlay() + +/turf/proc/get_corners() + if (has_opaque_atom) + return null // Since this proc gets used in a for loop, null won't be looped though. + + return corners + +/turf/proc/generate_missing_corners() + lighting_corners_initialised = TRUE + if (!corners) + corners = list(null, null, null, null) + + for (var/i = 1 to 4) + if (corners[i]) // Already have a corner on this direction. + continue + + corners[i] = new/datum/lighting_corner(src, LIGHTING_CORNER_DIAGONAL[i]) diff --git a/code/modules/lighting/~lighting_undefs.dm b/code/modules/lighting/~lighting_undefs.dm index 772f70557a1..46406a70d70 100644 --- a/code/modules/lighting/~lighting_undefs.dm +++ b/code/modules/lighting/~lighting_undefs.dm @@ -1,9 +1,5 @@ -#undef LIGHTING_INTERVAL - -#undef LIGHTING_FALLOFF -#undef LIGHTING_LAMBERTIAN #undef LIGHTING_HEIGHT -#undef LIGHTING_RESOLUTION -#undef LIGHTING_LAYER #undef LIGHTING_ICON + +#undef LIGHTING_BASE_MATRIX diff --git a/code/modules/maps/reader.dm b/code/modules/maps/reader.dm index daf34508f5b..fe0bbfe6a4f 100644 --- a/code/modules/maps/reader.dm +++ b/code/modules/maps/reader.dm @@ -299,7 +299,7 @@ var/global/dmm_suite/preloader/_preloader = null if(underturf.density) placed.density = 1 if(underturf.opacity) - placed.opacity = 1 + placed.set_opacity(1) placed.underlays += turfs_underlays //atom creation method that preloads variables at creation @@ -329,4 +329,4 @@ var/global/dmm_suite/preloader/_preloader = null /dmm_suite/preloader/proc/load(atom/what) for(var/attribute in attributes) what.vars[attribute] = attributes[attribute] - Del() \ No newline at end of file + Del() diff --git a/code/modules/mob/dview.dm b/code/modules/mob/dview.dm new file mode 100644 index 00000000000..febf05d34b8 --- /dev/null +++ b/code/modules/mob/dview.dm @@ -0,0 +1,22 @@ +//DVIEW is a hack that uses a mob with darksight in order to find lists of viewable stuff while ignoring darkness +// Defines for dview are elsewhere. + +var/mob/dview/dview_mob = new + +/mob/dview + invisibility = 101 + density = 0 + + anchored = 1 + simulated = 0 + + see_in_dark = 1e6 + +/mob/dview/New() + ..() + // We don't want to be in any mob lists; we're a dummy not a mob. + mob_list -= src + if(stat == DEAD) + dead_mob_list -= src + else + living_mob_list -= src diff --git a/code/modules/mob/freelook/ai/eye.dm b/code/modules/mob/freelook/ai/eye.dm index aa7e4d46191..59cd795f363 100644 --- a/code/modules/mob/freelook/ai/eye.dm +++ b/code/modules/mob/freelook/ai/eye.dm @@ -42,7 +42,7 @@ /mob/living/silicon/ai/proc/create_eyeobj(var/newloc) if(eyeobj) destroy_eyeobj() if(!newloc) newloc = src.loc - eyeobj = PoolOrNew(/mob/eye/aiEye, newloc) + eyeobj = getFromPool(/mob/eye/aiEye, newloc) eyeobj.owner = src eyeobj.name = "[src.name] (AI Eye)" // Give it a name if(client) client.eye = eyeobj diff --git a/code/modules/mob/living/bot/floorbot.dm b/code/modules/mob/living/bot/floorbot.dm index 21a4a6c619c..0d0981febf8 100644 --- a/code/modules/mob/living/bot/floorbot.dm +++ b/code/modules/mob/living/bot/floorbot.dm @@ -229,7 +229,7 @@ if(building == 1) I = new /obj/item/stack/tile/floor(src) else - I = PoolOrNew(/obj/item/stack/rods, src) + I = getFromPool(/obj/item/stack/rods, src) A.attackby(I, src) target = null repairing = 0 diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index 40684be20c7..6b776ebeaa7 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -71,7 +71,7 @@ icon_state = "secbot[on]" if(on) - set_light(2, 1, "#FF6A00") + set_light(1.4, 1, "#FF6A00") else set_light(0) diff --git a/code/modules/mob/living/carbon/alien/diona/diona_powers.dm b/code/modules/mob/living/carbon/alien/diona/diona_powers.dm index d156fc5da5d..7959093c81e 100644 --- a/code/modules/mob/living/carbon/alien/diona/diona_powers.dm +++ b/code/modules/mob/living/carbon/alien/diona/diona_powers.dm @@ -211,7 +211,7 @@ var/types = donor.find_type() if (types & TYPE_SYNTHETIC) - src.visible_message("[src] attempts to bite into [donor.name] but leaps back in surprise as its fangs hit metal.", "You attempt to sink your fangs into [donor.name] and get a faceful of unyielding steel as the force breaks several fine protrusions.in your mouth") + src.visible_message("[src] attempts to bite into [donor.name] but leaps back in surprise as its fangs hit metal.", "You attempt to sink your fangs into [donor.name] and get a faceful of unyielding steel as the force breaks several fine protrusions in your mouth.") donor.adjustBruteLoss(2) src.adjustBruteLoss(15)//biting metal hurts! return @@ -231,7 +231,7 @@ else if (istype(donor, /mob/living/carbon)) //If we get here, it's -probably- valid - src.visible_message("[src] is trying to bite [donor.name]", "\red You start biting [donor.name], you and them must stay still!") + src.visible_message("[src] is trying to bite [donor.name]", span("danger", "You start biting [donor.name], you both must stay still!")) face_atom(get_turf(donor)) if (do_mob(src, donor, 40, needhand = 0)) @@ -296,5 +296,5 @@ for (var/i in language_progress) if (language_progress[i] >= LANGUAGE_POINTS_TO_LEARN) add_language(i) - src << "You have mastered the [i] language!!" + src << "You have mastered the [i] language!" language_progress.Remove(i) diff --git a/code/modules/mob/living/carbon/diona_base.dm b/code/modules/mob/living/carbon/diona_base.dm index 051884793ce..1ba8662b0b5 100644 --- a/code/modules/mob/living/carbon/diona_base.dm +++ b/code/modules/mob/living/carbon/diona_base.dm @@ -1,7 +1,5 @@ //This function is for code that is shared by diona nymphs and gestalt -#define DIONA_MAX_LIGHT 5.5//Light from any tile is capped to prevent refilling too fast - #define TEMP_REGEN_STOP 223//Regen rate scales down linearly from normal to this temperature, stops completely below this value #define TEMP_REGEN_NORMAL 288//normal body temperature #define TEMP_INCREASE_REGEN_DOUBLE 700//Health regen is increased by 100% (additive) for every increment of this value we are above normal @@ -198,7 +196,6 @@ var/list/diona_banned_languages = list( weakened -= value DS.stored_energy -= value - //Genetic damage and toxins are relatively rare. We'll process them less often to reduce on computations if (life_tick % LIFETICK_INTERVAL_LESS == 0) CL = getToxLoss() @@ -214,8 +211,6 @@ var/list/diona_banned_languages = list( adjustToxLoss(value*-1) DS.stored_energy -= value - - CL = getCloneLoss() if (CL > 0) if (radiation > 0) @@ -228,9 +223,6 @@ var/list/diona_banned_languages = list( adjustCloneLoss(value/-5) DS.stored_energy -= value - - - var/mob/living/carbon/human/H if (src.is_diona() == DIONA_WORKER) H = src @@ -328,7 +320,6 @@ var/list/diona_banned_languages = list( else path = null - if (path) if (DS.stored_energy < REGROW_ENERGY_REQ) src << "You try to regrow a lost organ, but you lack the energy. Find more light!" @@ -350,8 +341,6 @@ var/list/diona_banned_languages = list( updatehealth() return - - if (DS.stored_energy < REGROW_ENERGY_REQ || H.nutrition < REGROW_FOOD_REQ) return @@ -370,16 +359,8 @@ var/list/diona_banned_languages = list( H.nutrition -= REGROW_FOOD_REQ src << "You feel a stirring inside you as a new nymph is born within your trunk!" - updatehealth() - - - - - - - //MESSAGE FUNCTIONS /mob/living/carbon/proc/diona_handle_lightmessages(var/datum/dionastats/DS) //This function handles the RP messages that inform the diona player about their light/withering state @@ -395,7 +376,7 @@ var/list/diona_banned_languages = list( if (DS.LMS == 1)//If we're full if (DS.EP <= 0.8 && DS.last_lightlevel <= 0)//But at <=80% energy DS.LMS = 2 - src << "The darkness makes you uncomfortable" + src << "The darkness makes you uncomfortable." else if (DS.LMS == 2) if (DS.EP >= 0.99) @@ -408,50 +389,36 @@ var/list/diona_banned_languages = list( else if (DS.LMS == 3) if (DS.EP >= 0.5) DS.LMS = 2 - src << "You feel a little more energised as you return to the light. Stay awhile" + src << "You feel a little more energised as you return to the light. Stay awhile." else if (DS.EP <= 0.0 && DS.last_lightlevel <= 0) DS.LMS = 4 - src << " You feel sensory distress as your tendrils start to wither in the darkness. You will die soon without light" + src << " You feel sensory distress as your tendrils start to wither in the darkness. You will die soon without light." //From here down, we immediately return to state 3 if we get any light else if (DS.EP > 0.0)//If there's any light at all, we can be saved - src << "At long last, light! Treasure it, savour it, hold onto it" + src << "At long last, light! Treasure it, savour it, hold onto it." DS.LMS = 3 else if(DS.last_lightlevel <= 0) - var/HP = diona_get_health(DS) / DS.max_health//HP = health-percentage + var/HP = 1 //diona_get_health(DS) / DS.max_health//HP = health-percentage if (DS.LMS == 4) if (HP < 0.6) - src << " The darkness burns. Your nymphs decay and wilt You are in mortal danger" + src << " The darkness burns. Your nymphs decay and wilt You are in mortal danger!" DS.LMS = 5 else if (DS.LMS == 5) if (paralysis > 0) - src << " Your body has reached critical integrity, it can no longer move. The end comes soon" + src << " Your body has reached critical integrity, it can no longer move. The end comes soon." DS.LMS = 6 else if (DS.LMS == 6) return - - - - - - -/* -if (flashlight_active) - light_amount -= DS.flashlight_reduction * FLASHLIGHT_STRENGTH - if (pdalight_active) - light_amount -= DS.pdalight_reduction * PDALIGHT_STRENGTH - -*/ //GETTER FUNCTIONS /mob/living/carbon/proc/get_lightlevel_diona(var/datum/dionastats/DS) - var/light_amount = DIONA_MAX_LIGHT //how much light there is in the place, affects receiving nutrition and healing - var/light_factor = 1//used for if a gestalt's response node is damaged. it will feed more slowly - + var/light_factor = 1 + var/turf/T = get_turf(src) if (is_ventcrawling) - return -1.5//no light inside pipes + return -1.5 //no light inside pipes if (DS.light_organ) if (DS.light_organ.is_broken()) @@ -459,43 +426,11 @@ if (flashlight_active) else if (DS.light_organ.is_bruised()) light_factor = 0.8 else if (DS.dionatype == 2) - light_factor = 0.55 - - var/turf/T = get_turf(src) - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T - if(L) - //First we check if the tile has any flashlights or PDA lights - var/gathertype = 0//Simple checking of the turf - for (var/datum/light_source/LS in T.affecting_lights) - if (LS.source_atom.diona_restricted_light) - gathertype = 1//if restricted lights involved in lighting, then we need a more complex calculation. - break - - if (gathertype == 0)//Simple, fast gather amount - light_amount = L.lum_r + L.lum_g + L.lum_b - - else//If flashlights are involved, then we get a little more complex - var/best_restrictedlight = 0//We track any restricted lights, and only the single strongest of them to the diona - light_amount = 0 - var/turf/ourturf = get_turf(src) - for (var/datum/light_source/LS in T.affecting_lights)//Cycle through the lights affecting the tile - - var/n = Sum(LS.get_lum(ourturf))//Manually calculate each one's contribution. Get lum function is kind of expensive - if (LS.source_atom.diona_restricted_light) - n *= DS.restrictedlight_factor - if (n > best_restrictedlight) - best_restrictedlight = n - else - light_amount += n - - - light_amount += best_restrictedlight//apply only the single best of the restricted lightsources - light_amount = min(DIONA_MAX_LIGHT,light_amount) //hardcapped to DIONA_MAX_LIGHT so it's not abused by being in massively bright areas - light_amount = max(light_amount*light_factor,0)//Make sure light amount is >=0 and apply light factor - light_amount -= 1.5//Light values > 1.5 will increase energy, <1.5 will decrease it - return light_amount - + light_factor = 0.8 + if (T) + var/raw = T.get_uv_lumcount(0, 2) * light_factor * 5.5 + return raw - 1.5 /mob/living/carbon/proc/diona_get_health(var/datum/dionastats/DS) if (DS.dionatype == 0) @@ -503,7 +438,6 @@ if (flashlight_active) else return health+(maxHealth*0.5) - /mob/living/carbon/proc/get_dionastats() if (istype(src, /mob/living/carbon/alien/diona)) var/mob/living/carbon/alien/diona/T = src @@ -515,7 +449,6 @@ if (flashlight_active) return T.DS return null - //Called on a nymph when it merges with a gestalt //The nymph and gestalt get the combined total of both of their languages //Note that the nymphs only have all languages while they're inside the gestalt. @@ -549,19 +482,7 @@ if (flashlight_active) if (prob(chance)) add_language(L.name) else - src << "You have forgotten the [L.name] language!" - - - - - - - - - - - - + src << "You have forgotten the [L.name] language!" //DIONASTATS DEFINES diff --git a/code/modules/mob/living/carbon/human/human_species.dm b/code/modules/mob/living/carbon/human/human_species.dm index e6a8d8d703b..a65027aca39 100644 --- a/code/modules/mob/living/carbon/human/human_species.dm +++ b/code/modules/mob/living/carbon/human/human_species.dm @@ -115,4 +115,5 @@ src.gender = NEUTER /mob/living/carbon/human/terminator - offset_light = 1 + mob_size = 30 + //offset_light = 1 diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 2bb9df049d3..aa26a0710d2 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -288,6 +288,7 @@ //var/obj/item/organ/diona/nutrients/rad_organ = locate() in internal_organs if(src.is_diona()) diona_handle_regeneration(get_dionastats()) + return else var/damage = 0 total_radiation -= 1 * RADIATION_SPEED_COEFFICIENT @@ -974,12 +975,12 @@ fake_attack(src) if(!handling_hal) spawn handle_hallucinations() //The not boring kind! - if(client && prob(5)) + /*if(client && prob(5)) client.dir = pick(2,4,8) var/client/C = client spawn(rand(20,50)) if(C) - C.dir = 1 + C.dir = 1*/ // This breaks the lighting system. if(hallucination<=2) hallucination = 0 @@ -1251,8 +1252,7 @@ //0.1% chance of playing a scary sound to someone who's in complete darkness if(isturf(loc) && rand(1,1000) == 1) var/turf/T = loc - var/atom/movable/lighting_overlay/L = locate(/atom/movable/lighting_overlay) in T - if(L && L.lum_r + L.lum_g + L.lum_b == 0) + if(T.dynamic_lighting && T.get_lumcount() < 0.01) // give a little bit of tolerance for near-dark areas. playsound_local(src,pick(scarySounds),50, 1, -1) /mob/living/carbon/human/handle_stomach() diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm index fa3345b39a0..a2fa7c29d1e 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -2,6 +2,7 @@ name = "Maintenance Drone Control" desc = "Used to monitor the station's drone population and the assembler that services them." icon = 'icons/obj/computer.dmi' + light_color = LIGHT_COLOR_ORANGE icon_screen = "power" req_access = list(access_engine_equip) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm index c074b5efdc4..5fccf5d7bcd 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm @@ -79,7 +79,7 @@ time_last_drone = world.time if(player.mob && player.mob.mind) player.mob.mind.reset() - var/mob/living/silicon/robot/drone/new_drone = PoolOrNew(drone_type, get_turf(src)) + var/mob/living/silicon/robot/drone/new_drone = getFromPool(drone_type, get_turf(src)) new_drone.transfer_personality(player) new_drone.master_fabricator = src diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 16f6778271d..3488bd13675 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -1,7 +1,7 @@ /mob/living/silicon gender = NEUTER voice_name = "synthesized voice" - diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona + //diona_restricted_light = 1//Light emitted by this object or creature has limited interaction with diona var/syndicate = 0 var/const/MAIN_CHANNEL = "Main Frequency" var/lawchannel = MAIN_CHANNEL // Default channel on which to state laws diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm deleted file mode 100644 index fa5afea0cfc..00000000000 --- a/code/modules/mob/living/silicon/subsystems.dm +++ /dev/null @@ -1,105 +0,0 @@ -/mob/living/silicon - var/list/silicon_subsystems_by_name = list() - var/list/silicon_subsystems = list( - /datum/nano_module/alarm_monitor/all, - /datum/nano_module/law_manager - ) - -/mob/living/silicon/ai/New() - silicon_subsystems.Cut() - for(var/subtype in subtypesof(/datum/nano_module)) - var/datum/nano_module/NM = subtype - if(initial(NM.available_to_ai)) - silicon_subsystems += NM - ..() - -/mob/living/silicon/robot/syndicate - silicon_subsystems = list( - /datum/nano_module/law_manager - ) - -/mob/living/silicon/Destroy() - for(var/subsystem in silicon_subsystems) - remove_subsystem(subsystem) - silicon_subsystems.Cut() - . = ..() - -/mob/living/silicon/proc/init_subsystems() - for(var/subsystem_type in silicon_subsystems) - init_subsystem(subsystem_type) - - if(/datum/nano_module/alarm_monitor/all in silicon_subsystems) - for(var/datum/alarm_handler/AH in alarm_manager.all_handlers) - AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm) - queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order - -/mob/living/silicon/proc/init_subsystem(var/subsystem_type) - var/existing_entry = silicon_subsystems[subsystem_type] - if(existing_entry && !ispath(existing_entry)) - return FALSE - - var/ui_state = subsystem_type == /datum/nano_module/law_manager ? conscious_state : self_state - var/stat_silicon_subsystem/SSS = new(src, subsystem_type, ui_state) - silicon_subsystems[subsystem_type] = SSS - silicon_subsystems_by_name[SSS.name] = SSS - return TRUE - -/mob/living/silicon/proc/remove_subsystem(var/subsystem_type) - var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] - if(!istype(SSS)) - return FALSE - - silicon_subsystems_by_name -= SSS.name - silicon_subsystems -= subsystem_type - qdel(SSS) - return TRUE - -/mob/living/silicon/proc/open_subsystem(var/subsystem_type) - var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] - if(!istype(SSS)) - return FALSE - SSS.Click() - return TRUE - -/mob/living/silicon/verb/activate_subsystem(var/datum/silicon_subsystem_name in silicon_subsystems_by_name) - set name = "Subsystems" - set desc = "Activates the given subsystem" - set category = "Silicon Commands" - - var/stat_silicon_subsystem/SSS = silicon_subsystems_by_name[silicon_subsystem_name] - if(istype(SSS)) - SSS.Click() - -/mob/living/silicon/Stat() - . = ..() - if(!.) - return - if(!silicon_subsystems.len) - return - if(!statpanel("Subsystems")) - return - for(var/subsystem_type in silicon_subsystems) - var/stat_silicon_subsystem/SSS = silicon_subsystems[subsystem_type] - stat(SSS) - -/stat_silicon_subsystem - parent_type = /atom/movable - simulated = 0 - var/ui_state - var/datum/nano_module/subsystem - -/stat_silicon_subsystem/New(var/mob/living/silicon/loc, var/subsystem_type, var/ui_state) - if(!istype(loc)) - CRASH("Unexpected location. Expected /mob/living/silicon, was [loc.type].") - src.ui_state = ui_state - subsystem = new subsystem_type(loc) - name = subsystem.name - ..() - -/stat_silicon_subsystem/Destroy() - qdel(subsystem) - subsystem = null - . = ..() - -/stat_silicon_subsystem/Click() - subsystem.ui_interact(usr, state = ui_state) diff --git a/code/modules/mob/living/simple_animal/head.dm b/code/modules/mob/living/simple_animal/head.dm deleted file mode 100644 index 227d2bcf04a..00000000000 --- a/code/modules/mob/living/simple_animal/head.dm +++ /dev/null @@ -1,60 +0,0 @@ -//Look Sir, free head! -/mob/living/simple_animal/head - name = "CommandBattle AI" - desc = "A standard borg shell on its chest crude marking saying CommandBattle AI MK4 : Head." - icon_state = "crab" - icon_living = "crab" - icon_dead = "crab_dead" - speak_emote = list("clicks") - emote_hear = list("clicks") - emote_see = list("clacks") - universal_speak = 1 - speak_chance = 1 - turns_per_move = 5 - meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "punches" - var/list/insults = list( - "Man you suck", - "You look like the most retarded douche around", - "What's up?, oh wait nevermind you are a fucking asshat", - "you are just overly retarded", - "Whiteman said what?!",) - var/list/comments = list("Man have you seen those furry cats?,I mean who in the right mind would like something like that?", - "They call me abusive,I just like the truth", - "Beeboop, im a robit", - "Gooogooooll, break ya bones", - "Crab say what?", - "Man they say we have space lizards now, man this shit is getting more wack every minute", - "The so called \"improved\" station AI is just bullshit, that thing aint fun for noone", - "The Captain is a traitor, he took my power core.", - "Say \"what\" again. Say \"what\" again. I dare you. I double-dare you, motherfucker. Say \"what\" one more goddamn time.", - "Ezekiel 25:17 ,The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who in the name of charity and good will shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children. And I will strike down upon thee with great vengeance and furious anger those who attempt to poison and destroy my brothers. And you will know my name is the Lord... when I lay my vengeance upon thee.", - "Did you notice a sign out in front of my house that said \"Dead Nigger Storage\"?") - stop_automated_movement = 1 - -/mob/living/simple_animal/head/Life() - if(stat == DEAD) - if(health > 0) - icon_state = icon_living - stat = CONSCIOUS - density = 1 - return - else if(health < 1) - Die() - else if(health > maxHealth) - health = maxHealth - for(var/mob/A in viewers(world.view,src)) - if(A.ckey) - say_something(A) -/mob/living/simple_animal/head/proc/say_something(mob/A) - if(prob(85)) - return - if(prob(30)) - var/msg = pick(insults) - msg = "Hey, [A.name].. [msg]" - src.say(msg) - else - var/msg = pick(comments) - src.say(msg) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index 26c503fc60b..043b912a588 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -151,7 +151,7 @@ if(busy == LAYING_EGGS) E = locate() in get_turf(src) if(!E) - PoolOrNew(/obj/effect/spider/eggcluster, list(loc, src)) + getFromPool(/obj/effect/spider/eggcluster, list(loc, src)) fed-- busy = 0 stop_automated_movement = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm index 24fb12633fc..b8e4bb63bc6 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm @@ -183,16 +183,16 @@ step_to(O, get_turf(pick(view(7, src)))) //rods - O = PoolOrNew(/obj/item/stack/rods, src.loc) + O = getFromPool(/obj/item/stack/rods, src.loc) step_to(O, get_turf(pick(view(7, src)))) if(prob(75)) - O = PoolOrNew(/obj/item/stack/rods, src.loc) + O = getFromPool(/obj/item/stack/rods, src.loc) step_to(O, get_turf(pick(view(7, src)))) if(prob(50)) - O = PoolOrNew(/obj/item/stack/rods, src.loc) + O = getFromPool(/obj/item/stack/rods, src.loc) step_to(O, get_turf(pick(view(7, src)))) if(prob(25)) - O = PoolOrNew(/obj/item/stack/rods, src.loc) + O = getFromPool(/obj/item/stack/rods, src.loc) step_to(O, get_turf(pick(view(7, src)))) //plasteel diff --git a/code/modules/mob/living/simple_animal/kobold.dm b/code/modules/mob/living/simple_animal/kobold.dm deleted file mode 100644 index 3e52a408747..00000000000 --- a/code/modules/mob/living/simple_animal/kobold.dm +++ /dev/null @@ -1,33 +0,0 @@ -//kobold -/mob/living/simple_animal/kobold - name = "kobold" - desc = "A small, rat-like creature." - icon = 'icons/mob/mob.dmi' - icon_state = "kobold_idle" - icon_living = "kobold_idle" - icon_dead = "kobold_dead" - //speak = list("You no take candle!","Ooh, pretty shiny.","Me take?","Where gold here...","Me likey.") - speak_emote = list("mutters","hisses","grumbles") - emote_hear = list("mutters under it's breath.","grumbles.", "yips!") - emote_see = list("looks around suspiciously.", "scratches it's arm.","putters around a bit.") - speak_chance = 15 - turns_per_move = 5 - see_in_dark = 6 - meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/monkey - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "kicks" - minbodytemp = 250 - min_oxy = 16 //Require atleast 16kPA oxygen - minbodytemp = 223 //Below -50 Degrees Celcius - maxbodytemp = 323 //Above 50 Degrees Celcius - -/mob/living/simple_animal/kobold/Life() - ..() - if(prob(15) && turns_since_move && !stat) - flick("kobold_act",src) - -/mob/living/simple_animal/kobold/Move(var/dir) - ..() - if(!stat) - flick("kobold_walk",src) diff --git a/code/modules/nano/JSON Reader.dm b/code/modules/nano/JSON Reader.dm deleted file mode 100644 index 12edf1dd5c0..00000000000 --- a/code/modules/nano/JSON Reader.dm +++ /dev/null @@ -1,205 +0,0 @@ -json_token - var - value - New(v) - src.value = v - text - number - word - symbol - eof - -json_reader - var - list - string = list("'", "\"") - symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",") - sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13) - tokens - json - i = 1 - - - proc - // scanner - ScanJson(json) - src.json = json - . = new/list() - src.i = 1 - while(src.i <= lentext(json)) - var/char = get_char() - if(is_whitespace(char)) - i++ - continue - if(string.Find(char)) - . += read_string(char) - else if(symbols.Find(char)) - . += new/json_token/symbol(char) - else if(is_digit(char)) - . += read_number() - else - . += read_word() - i++ - . += new/json_token/eof() - - read_word() - var/val = "" - while(i <= lentext(json)) - var/char = get_char() - if(is_whitespace(char) || symbols.Find(char)) - i-- // let scanner handle this character - return new/json_token/word(val) - val += char - i++ - - read_string(delim) - var - escape = FALSE - val = "" - while(++i <= lentext(json)) - var/char = get_char() - if(escape) - switch(char) - if("\\", "'", "\"", "/", "u") - val += char - else - // TODO: support octal, hex, unicode sequences - ASSERT(sequences.Find(char)) - val += ascii2text(sequences[char]) - else - if(char == delim) - return new/json_token/text(val) - else if(char == "\\") - escape = TRUE - else - val += char - CRASH("Unterminated string.") - - read_number() - var/val = "" - var/char = get_char() - while(is_digit(char) || char == "." || lowertext(char) == "e") - val += char - i++ - char = get_char() - i-- // allow scanner to read the first non-number character - return new/json_token/number(text2num(val)) - - check_char() - ASSERT(args.Find(get_char())) - - get_char() - return copytext(json, i, i+1) - - is_whitespace(char) - return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13 - - is_digit(char) - var/c = text2ascii(char) - return 48 <= c && c <= 57 || char == "+" || char == "-" - - - // parser - ReadObject(list/tokens) - src.tokens = tokens - . = new/list() - i = 1 - read_token("{", /json_token/symbol) - while(i <= tokens.len) - var/json_token/K = get_token() - check_type(/json_token/word, /json_token/text) - next_token() - read_token(":", /json_token/symbol) - - .[K.value] = read_value() - - var/json_token/S = get_token() - check_type(/json_token/symbol) - switch(S.value) - if(",") - next_token() - continue - if("}") - next_token() - return - else - die() - - get_token() - return tokens[i] - - next_token() - return tokens[++i] - - read_token(val, type) - var/json_token/T = get_token() - if(!(T.value == val && istype(T, type))) - CRASH("Expected '[val]', found '[T.value]'.") - next_token() - return T - - check_type(...) - var/json_token/T = get_token() - for(var/type in args) - if(istype(T, type)) - return - CRASH("Bad token type: [T.type].") - - check_value(...) - var/json_token/T = get_token() - ASSERT(args.Find(T.value)) - - read_key() - var/char = get_char() - if(char == "\"" || char == "'") - return read_string(char) - - read_value() - var/json_token/T = get_token() - switch(T.type) - if(/json_token/text, /json_token/number) - next_token() - return T.value - if(/json_token/word) - next_token() - switch(T.value) - if("true") - return TRUE - if("false") - return FALSE - if("null") - return null - if(/json_token/symbol) - switch(T.value) - if("\[") - return read_array() - if("{") - return ReadObject(tokens.Copy(i)) - die() - - read_array() - read_token("\[", /json_token/symbol) - . = new/list() - var/list/L = . - while(i <= tokens.len) - // Avoid using Add() or += in case a list is returned. - L.len++ - L[L.len] = read_value() - var/json_token/T = get_token() - check_type(/json_token/symbol) - switch(T.value) - if(",") - next_token() - continue - if("]") - next_token() - return - else - die() - next_token() - CRASH("Unterminated array.") - - - die(json_token/T) - if(!T) T = get_token() - CRASH("Unexpected token: [T.value].") \ No newline at end of file diff --git a/code/modules/nano/JSON Writer.dm b/code/modules/nano/JSON Writer.dm deleted file mode 100644 index 97acc0b2ccb..00000000000 --- a/code/modules/nano/JSON Writer.dm +++ /dev/null @@ -1,58 +0,0 @@ -json_writer - var - use_cache = 0 - - proc - WriteObject(list/L) - if(use_cache && L["__json_cache"]) - return L["__json_cache"] - - . = "{" - var/i = 1 - for(var/k in L) - var/val = L[k] - . += {"\"[k]\":[write(val)]"} - if(i++ < L.len) - . += "," - . += "}" - - write(val) - if(isnum(val)) - return num2text(val) - else if(isnull(val)) - return "null" - else if(istype(val, /list)) - if(is_associative(val)) - return WriteObject(val) - else - return write_array(val) - else - . += write_string("[val]") - - write_array(list/L) - . = "\[" - for(var/i = 1 to L.len) - . += write(L[i]) - if(i < L.len) - . += "," - . += "]" - - write_string(txt) - var/static/list/json_escape = list("\\" = "\\\\", "\"" = "\\\"", "\n" = "\\n") - for(var/targ in json_escape) - var/start = 1 - while(start <= lentext(txt)) - var/i = findtext(txt, targ, start) - if(!i) - break - var/lrep = length(json_escape[targ]) - txt = copytext(txt, 1, i) + json_escape[targ] + copytext(txt, i + length(targ)) - start = i + lrep - - return {""[txt]""} - - is_associative(list/L) - for(var/key in L) - // if the key is a list that means it's actually an array of lists (stupid Byond...) - if(!isnum(key) && !isnull(L[key]) && !istype(key, /list)) - return TRUE diff --git a/code/modules/nano/_JSON.dm b/code/modules/nano/_JSON.dm deleted file mode 100644 index 95791899817..00000000000 --- a/code/modules/nano/_JSON.dm +++ /dev/null @@ -1,17 +0,0 @@ -/* -n_Json v11.3.21 -*/ - -proc - json2list(json) - var/static/json_reader/_jsonr = new() - return _jsonr.ReadObject(_jsonr.ScanJson(json)) - - list2json(list/L) - var/static/json_writer/_jsonw = new() - return _jsonw.write(L) - - list2json_usecache(list/L) - var/static/json_writer/_jsonw = new() - _jsonw.use_cache = 1 - return _jsonw.write(L) diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index a7147ed1189..b1dffe62962 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -467,7 +467,7 @@ nanoui is used to open and update nano browser uis var/list/send_data = get_send_data(data) //user << list2json(data) // used for debugging - user << output(list2params(list(list2json_usecache(send_data))),"[window_id].browser:receiveUpdateData") + user << output(list2params(list(json_encode(send_data))),"[window_id].browser:receiveUpdateData") /** * This Topic() proc is called whenever a user clicks on a link within a Nano UI diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 75bab36d70a..9ea20407159 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -30,6 +30,7 @@ var/list/offset_y[0] //usage by the photocopier var/rigged = 0 var/spam_flag = 0 + var/old_name // The name of the paper before it was folded into a plane. var/const/deffont = "Verdana" var/const/signfont = "Times New Roman" @@ -84,6 +85,9 @@ /obj/item/weapon/paper/examine(mob/user) ..() + if (old_name && icon_state == "paper_plane") + user << span("notice", "You're going to have to unfold it before you can read it.") + return if(name != "sheet of paper") user << "It's titled '[name]'." if(in_range(user, src) || isobserver(user)) @@ -122,9 +126,31 @@ return //crumple dat paper info = stars(info,85) - user.visible_message("\The [user] crumples \the [src] into a ball!") + user.visible_message("\The [user] crumples \the [src] into a ball!", "You crumple \the [src] into a ball.", "You hear crinkling.") icon_state = "scrap" return + + if (user.a_intent == I_GRAB && icon_state != "scrap" && !istype(src, /obj/item/weapon/paper/carbon)) + if (icon_state == "paper_plane") + user.show_message(span("alert", "The paper is already folded into a plane.")) + return + user.visible_message(span("notice", "\The [user] carefully folds \the [src] into a plane."), + span("notice", "You carefully fold \the [src] into a plane."), "You hear paper rustling.") + icon_state = "paper_plane" + throw_range = 8 + old_name = name + name = "paper plane" + return + + if (user.a_intent == I_HELP && old_name && icon_state == "paper_plane") + user.visible_message(span("notice", "the [src] unfolds \the [src]."), span("notice", "You unfold \the [src]."), "You hear paper rustling.") + icon_state = initial(icon_state) + throw_range = initial(throw_range) + name = old_name + old_name = null + update_icon() + return + user.examinate(src) if(rigged && (Holiday == "April Fool's Day")) if(spam_flag == 0) diff --git a/code/modules/paperwork/papershredder.dm b/code/modules/paperwork/papershredder.dm index f68e3e4719d..32e47e299e0 100644 --- a/code/modules/paperwork/papershredder.dm +++ b/code/modules/paperwork/papershredder.dm @@ -90,7 +90,7 @@ if(!paperamount) return paperamount-- - return PoolOrNew(/obj/item/weapon/shreddedp, get_turf(src)) + return getFromPool(/obj/item/weapon/shreddedp, get_turf(src)) /obj/machinery/papershredder/update_icon() icon_state = "papershredder[max(0,min(5,Floor(paperamount/2)))]" @@ -120,7 +120,7 @@ var/mob/living/M = loc if(istype(M)) M.drop_from_inventory(src) - PoolOrNew(/obj/effect/decal/cleanable/ash,get_turf(src)) + getFromPool(/obj/effect/decal/cleanable/ash,get_turf(src)) qdel(src) /obj/item/weapon/shreddedp diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 97388cf6610..8216fa772a2 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -337,7 +337,7 @@ if(update & 3) if(update_state & UPDATE_BLUESCREEN) - set_light(l_range = 2, l_power = 0.5, l_color = "#0000FF") + set_light(l_range = L_WALLMOUNT_RANGE, l_power = L_WALLMOUNT_POWER, l_color = "#0000FF") else if(!(stat & (BROKEN|MAINT)) && update_state & UPDATE_ALLGOOD) var/color switch(charging) @@ -347,7 +347,7 @@ color = "#A8B0F8" if(2) color = "#82FF4C" - set_light(l_range = 2, l_power = 0.5, l_color = color) + set_light(l_range = L_WALLMOUNT_RANGE, l_power = L_WALLMOUNT_POWER, l_color = color) else set_light(0) @@ -1303,18 +1303,11 @@ obj/machinery/power/apc/proc/autoset(var/val, var/on) sleep(1) /obj/machinery/power/apc/proc/toggle_nightlight(var/force = null) - // this defines what the list level arguments are when night mode is turned on - var/list/night_light_args = list( - /obj/machinery/light = list(6, 1), - /obj/machinery/light/small = list(4, 1) - ) for (var/obj/machinery/light/L in area.contents) - if (!listgetindex(night_light_args, L.type)) // if L's type isn't defined in our args list - continue if (force == "on") - L.set_light_source(arglist(night_light_args[L.type])) + L.nightmode = TRUE else if (force == "off") - L.set_light_source() + L.nightmode = FALSE L.update() switch (force) if ("on") diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index b3ab2264be8..57ad192b58e 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -143,8 +143,13 @@ var/on = 0 // 1 if on, 0 if off var/on_gs = 0 var/brightness_range = 8 // luminosity when on, also used in power calculation - var/brightness_power = 3 - var/brightness_color = null + var/brightness_power = 0.8 + var/night_brightness_range = 6 + var/night_brightness_power = 0.6 + var/supports_nightmode = TRUE + var/nightmode = FALSE + var/brightness_color = LIGHT_COLOR_HALOGEN + var/brightness_uv = 200 var/status = LIGHT_OK // LIGHT_OK, _EMPTY, _BURNED or _BROKEN var/flickering = 0 var/light_type = /obj/item/weapon/light/tube // the type of light item @@ -160,21 +165,22 @@ icon_state = "bulb1" base_state = "bulb" fitting = "bulb" - brightness_range = 4 - brightness_power = 2 - brightness_color = "#a0a080" + brightness_range = 5 + brightness_power = 0.75 + brightness_color = LIGHT_COLOR_TUNGSTEN desc = "A small lighting fixture." light_type = /obj/item/weapon/light/bulb + supports_nightmode = FALSE /obj/machinery/light/small/emergency brightness_range = 6 - brightness_power = 2 - brightness_color = "#da0205" + brightness_power = 1 + brightness_color = "#FF0000" /obj/machinery/light/small/red - brightness_range = 5 + brightness_range = 2.5 brightness_power = 1 - brightness_color = "#da0205" + brightness_color = LIGHT_COLOR_RED /obj/machinery/light/spot name = "spotlight" @@ -182,6 +188,7 @@ light_type = /obj/item/weapon/light/tube/large brightness_range = 12 brightness_power = 4 + supports_nightmode = FALSE /obj/machinery/light/built/New() status = LIGHT_EMPTY @@ -238,7 +245,7 @@ update_icon() if(on) - if(light_range != brightness_range || light_power != brightness_power || light_color != brightness_color) + if (check_update()) switchcount++ if(rigged) if(status == LIGHT_OK && trigger) @@ -255,15 +262,24 @@ set_light(0) else use_power = 2 - set_light(brightness_range, brightness_power, brightness_color) + if (supports_nightmode && nightmode) + set_light(night_brightness_range, night_brightness_power, brightness_color, uv = brightness_uv) + else + set_light(brightness_range, brightness_power, brightness_color, uv = brightness_uv) else use_power = 1 set_light(0) - active_power_usage = ((light_range + light_power) * 10) + active_power_usage = ((light_range * light_power) * 10) if(on != on_gs) on_gs = on +/obj/machinery/light/proc/check_update() + if (supports_nightmode && nightmode) + return light_range != night_brightness_range || light_power != night_brightness_power || light_color != brightness_color + else + return light_range != brightness_range || light_power != brightness_power || light_color != brightness_color + /obj/machinery/light/attack_generic(var/mob/user, var/damage) if(!damage) return @@ -557,7 +573,7 @@ // timed process // use power -#define LIGHTING_POWER_FACTOR 20 //20W per unit luminosity +#define LIGHTING_POWER_FACTOR 40 //20W per unit luminosity /obj/machinery/light/process() @@ -631,13 +647,13 @@ item_state = "c_tube" matter = list("glass" = 100) brightness_range = 8 - brightness_power = 3 + brightness_power = 0.8 /obj/item/weapon/light/tube/large w_class = 2 name = "large light tube" brightness_range = 15 - brightness_power = 4 + brightness_power = 6 /obj/item/weapon/light/bulb name = "light bulb" @@ -647,7 +663,7 @@ item_state = "contvapour" matter = list("glass" = 100) brightness_range = 5 - brightness_power = 2 + brightness_power = 0.75 brightness_color = "#a0a080" /obj/item/weapon/light/throw_impact(atom/hit_atom) @@ -661,8 +677,8 @@ base_state = "fbulb" item_state = "egg4" matter = list("glass" = 100) - brightness_range = 5 - brightness_power = 2 + brightness_range = 8 + brightness_power = 0.8 // update the icon state and description of the light diff --git a/code/modules/random_map/automata/diona.dm b/code/modules/random_map/automata/diona.dm index 523f6880385..fc0bbb034b8 100644 --- a/code/modules/random_map/automata/diona.dm +++ b/code/modules/random_map/automata/diona.dm @@ -38,7 +38,7 @@ if(1) new_growth = 2 var/obj/structure/diona/vines/existing = locate() in T - if(!istype(existing)) existing = PoolOrNew(/obj/structure/diona/vines, T) + if(!istype(existing)) existing = getFromPool(/obj/structure/diona/vines, T) if(existing.growth < new_growth) existing.growth = new_growth existing.update_icon() @@ -161,11 +161,11 @@ switch(value) if(ARTIFACT_CHAR) - PoolOrNew(/obj/structure/diona/bulb,T) + getFromPool(/obj/structure/diona/bulb,T) if(MONSTER_CHAR) spawn_diona_nymph(T) if(DOOR_CHAR) - var/obj/structure/diona/vines/V = PoolOrNew(/obj/structure/diona/vines,T) + var/obj/structure/diona/vines/V = getFromPool(/obj/structure/diona/vines,T) V.growth = 3 V.update_icon() spawn(1) diff --git a/code/modules/random_map/drop/droppod_doors.dm b/code/modules/random_map/drop/droppod_doors.dm index eb5b7c3e17f..9df8ecb258e 100644 --- a/code/modules/random_map/drop/droppod_doors.dm +++ b/code/modules/random_map/drop/droppod_doors.dm @@ -47,10 +47,10 @@ // Overwrite turfs. var/turf/origin = get_turf(src) origin.ChangeTurf(/turf/simulated/floor/reinforced) - origin.set_light(0) // Forcing updates + origin.reconsider_lights() // Forcing updates var/turf/T = get_step(origin, src.dir) T.ChangeTurf(/turf/simulated/floor/reinforced) - T.set_light(0) // Forcing updates + T.reconsider_lights() // Forcing updates // Destroy turf contents. for(var/obj/O in origin) diff --git a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm index cca513dc4e8..87f88c8e8e1 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/bottle.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/bottle.dm @@ -116,9 +116,6 @@ if(rag) var/underlay_image = image(icon='icons/obj/drinks.dmi', icon_state=rag.on_fire? "[rag_underlay]_lit" : rag_underlay) underlays += underlay_image - copy_light(rag) - else - set_light(0) /obj/item/weapon/reagent_containers/food/drinks/bottle/attack(mob/living/target, mob/living/user, var/hit_zone) var/blocked = ..() diff --git a/code/modules/reagents/reagent_containers/food/lunch.dm b/code/modules/reagents/reagent_containers/food/lunch.dm new file mode 100644 index 00000000000..6392213adae --- /dev/null +++ b/code/modules/reagents/reagent_containers/food/lunch.dm @@ -0,0 +1,123 @@ +var/list/lunchables_lunches_ = list(/obj/item/weapon/reagent_containers/food/snacks/sandwich, + /obj/item/weapon/reagent_containers/food/snacks/meatbreadslice, + /obj/item/weapon/reagent_containers/food/snacks/tofubreadslice, + /obj/item/weapon/reagent_containers/food/snacks/creamcheesebreadslice, + /obj/item/weapon/reagent_containers/food/snacks/margheritaslice, + /obj/item/weapon/reagent_containers/food/snacks/meatpizzaslice, + /obj/item/weapon/reagent_containers/food/snacks/mushroompizzaslice, + /obj/item/weapon/reagent_containers/food/snacks/vegetablepizzaslice, + /obj/item/weapon/reagent_containers/food/snacks/tastybread, + /obj/item/weapon/reagent_containers/food/snacks/liquidfood, + /obj/item/weapon/reagent_containers/food/snacks/jellysandwich/cherry, + /obj/item/weapon/reagent_containers/food/snacks/tossedsalad, + /obj/item/weapon/reagent_containers/food/snacks/koiswaffles) + +var/list/lunchables_snacks_ = list(/obj/item/weapon/reagent_containers/food/snacks/donut/jelly, + /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly, + /obj/item/weapon/reagent_containers/food/snacks/muffin, + /obj/item/weapon/reagent_containers/food/snacks/popcorn, + /obj/item/weapon/reagent_containers/food/snacks/sosjerky, + /obj/item/weapon/reagent_containers/food/snacks/no_raisin, + /obj/item/weapon/reagent_containers/food/snacks/spacetwinkie, + /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers, + /obj/item/weapon/reagent_containers/food/snacks/poppypretzel, + /obj/item/weapon/reagent_containers/food/snacks/carrotfries, + /obj/item/weapon/reagent_containers/food/snacks/candiedapple, + /obj/item/weapon/reagent_containers/food/snacks/applepie, + /obj/item/weapon/reagent_containers/food/snacks/cherrypie, + /obj/item/weapon/reagent_containers/food/snacks/plumphelmetbiscuit, + /obj/item/weapon/reagent_containers/food/snacks/appletart, + /obj/item/weapon/reagent_containers/food/snacks/carrotcakeslice, + /obj/item/weapon/reagent_containers/food/snacks/cheesecakeslice, + /obj/item/weapon/reagent_containers/food/snacks/plaincakeslice, + /obj/item/weapon/reagent_containers/food/snacks/orangecakeslice, + /obj/item/weapon/reagent_containers/food/snacks/limecakeslice, + /obj/item/weapon/reagent_containers/food/snacks/lemoncakeslice, + /obj/item/weapon/reagent_containers/food/snacks/chocolatecakeslice, + /obj/item/weapon/reagent_containers/food/snacks/birthdaycakeslice, + /obj/item/weapon/reagent_containers/food/snacks/watermelonslice, + /obj/item/weapon/reagent_containers/food/snacks/applecakeslice, + /obj/item/weapon/reagent_containers/food/snacks/pumpkinpieslice, + /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks, + /obj/item/weapon/reagent_containers/food/snacks/friedkois, + /obj/item/weapon/reagent_containers/food/snacks/meatsnack, + /obj/item/weapon/reagent_containers/food/snacks/maps, + /obj/item/weapon/reagent_containers/food/snacks/nathisnack) + +var/list/lunchables_drinks_ = list(/obj/item/weapon/reagent_containers/food/drinks/cans/cola, + /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle, + /obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind, + /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb, + /obj/item/weapon/reagent_containers/food/drinks/cans/starkist, + /obj/item/weapon/reagent_containers/food/drinks/cans/space_up, + /obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime, + /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea, + /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice, + /obj/item/weapon/reagent_containers/food/drinks/cans/tonic, + /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater) + +// This default list is a bit different, it contains items we don't want +var/list/lunchables_drink_reagents_ = list(/datum/reagent/drink/nothing, + /datum/reagent/drink/doctor_delight, + /datum/reagent/drink/dry_ramen, + /datum/reagent/drink/hell_ramen, + /datum/reagent/drink/hot_ramen, + /datum/reagent/drink/nuka_cola, + /datum/reagent/drink/black_coffee, + /datum/reagent/drink/white_coffee, + /datum/reagent/drink/cafe_melange) + +// This default list is a bit different, it contains items we don't want +var/list/lunchables_ethanol_reagents_ = list(/datum/reagent/ethanol/acid_spit, + /datum/reagent/ethanol/atomicbomb, + /datum/reagent/ethanol/beepsky_smash, + /datum/reagent/ethanol/coffee, + /datum/reagent/ethanol/hippies_delight, + /datum/reagent/ethanol/hooch, + /datum/reagent/ethanol/thirteenloko, + /datum/reagent/ethanol/manhattan_proj, + /datum/reagent/ethanol/neurotoxin, + /datum/reagent/ethanol/pwine, + /datum/reagent/ethanol/threemileisland, + /datum/reagent/ethanol/toxins_special) + +/proc/lunchables_lunches() + if(!(lunchables_lunches_[lunchables_lunches_[1]])) + lunchables_lunches_ = init_lunchable_list(lunchables_lunches_) + return lunchables_lunches_ + +/proc/lunchables_snacks() + if(!(lunchables_snacks_[lunchables_snacks_[1]])) + lunchables_snacks_ = init_lunchable_list(lunchables_snacks_) + return lunchables_snacks_ + +/proc/lunchables_drinks() + if(!(lunchables_drinks_[lunchables_drinks_[1]])) + lunchables_drinks_ = init_lunchable_list(lunchables_drinks_) + return lunchables_drinks_ + +/proc/lunchables_drink_reagents() + if(!(lunchables_drink_reagents_[lunchables_drink_reagents_[1]])) + lunchables_drink_reagents_ = init_lunchable_reagent_list(lunchables_drink_reagents_, /datum/reagent/drink) + return lunchables_drink_reagents_ + +/proc/lunchables_ethanol_reagents() + if(!(lunchables_ethanol_reagents_[lunchables_ethanol_reagents_[1]])) + lunchables_ethanol_reagents_ = init_lunchable_reagent_list(lunchables_ethanol_reagents_, /datum/reagent/ethanol) + return lunchables_ethanol_reagents_ + +/proc/init_lunchable_list(var/list/lunches) + . = list() + for(var/lunch in lunches) + var/obj/O = lunch + .[initial(O.name)] = lunch + return sortAssoc(.) + +/proc/init_lunchable_reagent_list(var/list/banned_reagents, var/reagent_types) + . = list() + for(var/reagent_type in subtypesof(reagent_types)) + if(reagent_type in banned_reagents) + continue + var/datum/reagent/reagent = reagent_type + .[initial(reagent.name)] = initial(reagent.id) + return sortAssoc(.) diff --git a/code/modules/research/xenoarchaeology/finds/finds.dm b/code/modules/research/xenoarchaeology/finds/finds.dm index 8b78d75aea3..0a709dbf833 100644 --- a/code/modules/research/xenoarchaeology/finds/finds.dm +++ b/code/modules/research/xenoarchaeology/finds/finds.dm @@ -323,7 +323,7 @@ apply_material_decorations = 0 if(23) apply_prefix = 0 - new_item = PoolOrNew(/obj/item/stack/rods, src.loc) + new_item = getFromPool(/obj/item/stack/rods, src.loc) apply_image_decorations = 0 apply_material_decorations = 0 if(24) diff --git a/code/modules/shuttles/antagonist.dm b/code/modules/shuttles/antagonist.dm index 1e95093edd7..6a791777156 100644 --- a/code/modules/shuttles/antagonist.dm +++ b/code/modules/shuttles/antagonist.dm @@ -2,8 +2,10 @@ name = "skipjack control console" req_access = list(access_syndicate) shuttle_tag = "Skipjack" + light_color = LIGHT_COLOR_RED /obj/machinery/computer/shuttle_control/multi/syndicate name = "mercenary shuttle control console" req_access = list(access_syndicate) shuttle_tag = "Mercenary" + light_color = LIGHT_COLOR_RED diff --git a/code/modules/shuttles/shuttle_console.dm b/code/modules/shuttles/shuttle_console.dm index 6c0d72efb3d..ebe6eeb4643 100644 --- a/code/modules/shuttles/shuttle_console.dm +++ b/code/modules/shuttles/shuttle_console.dm @@ -2,6 +2,7 @@ name = "shuttle control console" icon = 'icons/obj/computer.dmi' + light_color = LIGHT_COLOR_CYAN icon_screen = "shuttle" circuit = null diff --git a/code/modules/spells/spell_projectile.dm b/code/modules/spells/spell_projectile.dm index c94131b252c..6afc7b5afdc 100644 --- a/code/modules/spells/spell_projectile.dm +++ b/code/modules/spells/spell_projectile.dm @@ -26,7 +26,7 @@ /obj/item/projectile/spell_projectile/before_move() if(proj_trail && src && src.loc) //pretty trails - var/obj/effect/overlay/trail = PoolOrNew(/obj/effect/overlay, src.loc) + var/obj/effect/overlay/trail = getFromPool(/obj/effect/overlay, src.loc) trails += trail trail.icon = proj_trail_icon trail.icon_state = proj_trail_icon_state diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm index b8413da63f9..d6603fca92f 100644 --- a/code/modules/supermatter/supermatter.dm +++ b/code/modules/supermatter/supermatter.dm @@ -55,6 +55,8 @@ var/explosion_point = 1000 light_color = "#8A8A00" + uv_intensity = 255 + var/last_power = 0 var/warning_color = "#B8B800" var/emergency_color = "#D9D900" @@ -120,6 +122,12 @@ /obj/machinery/power/supermatter/proc/shift_light(var/lum, var/clr) if(lum != light_range || clr != light_color) set_light(lum, l_color = clr) + update_uv() + +/obj/machinery/power/supermatter/proc/update_uv() + if (last_power + 20 < power || last_power - 20 > power) + set_uv(CLAMP01(power / 500) * 255) + last_power = power /obj/machinery/power/supermatter/proc/get_integrity() var/integrity = damage / explosion_point @@ -395,7 +403,8 @@ //following is adapted from singulo code // Let's just make this one loop. for(var/atom/X in orange(pull_radius,src)) - spawn() X.singularity_pull(src, STAGE_FIVE) + X.singularity_pull(src, STAGE_FIVE) + CHECK_TICK return diff --git a/code/modules/telesci/bscrystal.dm b/code/modules/telesci/bscrystal.dm index a8c089e1e40..3f54a63e222 100644 --- a/code/modules/telesci/bscrystal.dm +++ b/code/modules/telesci/bscrystal.dm @@ -18,7 +18,7 @@ /obj/item/bluespace_crystal/attack_self(mob/user) user.visible_message("[user] crushes [src]!", "You crush [src]!") - PoolOrNew(/obj/effect/sparks, loc) + getFromPool(/obj/effect/sparks, loc) playsound(src.loc, "sparks", 50, 1) blink_mob(user) user.unEquip(src) @@ -31,7 +31,7 @@ if(!..()) // not caught in mid-air visible_message("[src] fizzles and disappears upon impact!") var/turf/T = get_turf(hit_atom) - PoolOrNew(/obj/effect/sparks, T) + getFromPool(/obj/effect/sparks, T) playsound(src.loc, "sparks", 50, 1) if(isliving(hit_atom)) blink_mob(hit_atom) diff --git a/code/modules/telesci/telesci_computer.dm b/code/modules/telesci/telesci_computer.dm index bb71e7582eb..6655980f07b 100644 --- a/code/modules/telesci/telesci_computer.dm +++ b/code/modules/telesci/telesci_computer.dm @@ -2,6 +2,7 @@ name = "\improper Telepad Control Console" desc = "Used to teleport objects to and from the telescience telepad." icon_screen = "teleport" + light_color = LIGHT_COLOR_BLUE circuit = /obj/item/weapon/circuitboard/telesci_console var/sending = 1 var/obj/machinery/telepad/telepad = null diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index b44b27582fe..b0907d19aad 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -144,7 +144,7 @@ /obj/vehicle/emp_act(severity) var/was_on = on stat |= EMPED - var/obj/effect/overlay/pulse2 = PoolOrNew(/obj/effect/overlay, src.loc) + var/obj/effect/overlay/pulse2 = getFromPool(/obj/effect/overlay, src.loc) pulse2.icon = 'icons/effects/effects.dmi' pulse2.icon_state = "empdisable" pulse2.name = "emp sparks" @@ -197,8 +197,8 @@ src.visible_message("\red [src] blows apart!", 1) var/turf/Tsec = get_turf(src) - PoolOrNew(/obj/item/stack/rods, Tsec) - PoolOrNew(/obj/item/stack/rods, Tsec) + getFromPool(/obj/item/stack/rods, Tsec) + getFromPool(/obj/item/stack/rods, Tsec) new /obj/item/stack/cable_coil/cut(Tsec) if(cell) diff --git a/code/world.dm b/code/world.dm index 855ebf17557..1cc3dfb50db 100644 --- a/code/world.dm +++ b/code/world.dm @@ -1,3 +1,5 @@ +#define WORLD_ICON_SIZE 32 +#define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 /* The initialization of the game happens roughly like this: diff --git a/config/example/tips.txt b/config/example/tips.txt new file mode 100644 index 00000000000..1291e1d4240 --- /dev/null +++ b/config/example/tips.txt @@ -0,0 +1,171 @@ +You can catch thrown items by toggling on your throw mode with an empty hand active. +To crack the safe in the vault, use a stethoscope on it. +You can climb onto a table by dragging yourself onto one. +You can drag other players onto yourself to open the strip menu, letting you remove their equipment or force them to wear something. +Clicking on a windoor rather then bumping into it will keep it open, you can click it again to close it. +You can spray a fire extinguisher or fire a gun while floating through space to change your direction. Simply fire opposite to where you want to go. +You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this. +All vending machines can be hacked to obtain some contraband items from them, and some can be fed with coins to gain access to premium items. +Glass shards can be welded to make glass, and metal rods can be welded to make metal. +If you need to drag multiple people either to safety or to space, bring a locker over and stuff them all in before hauling them off. +You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on the grab button in your active hand. An aggressive grab will allow you to place someone on a table by clicking on it, or throw them by toggling on throwing. +Holding alt and left clicking a tile will allow you to see its contents in the top right window pane, which is much faster than right clicking. +The resist button will allow you to resist out of handcuffs, being buckled to a chair or bed, out of locked lockers and more. Whenever you're stuck, try resisting! +You can move an item out of the way by dragging it and then clicking on an adjacent tile with an empty hand. +Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using.There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more! +As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your unique lasgun or your life are things to worry about. +As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban. +As the Chief Medical Officer, your hypospray is like an instant injection syringe that can hold 30 units as opposed to the standard 15. +As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and EMTs during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting. +As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, it was caused by something unnatural. +As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva. +As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone. +As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment! +As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently. +As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, and then from there into an AI system integrity restorer computer to revive and/or repair them. +As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled. +As a Xenoscientist, you can inject yourself with the mutation toxin extracted from green slimes to become a slime person, who will never be attacked by slimes! +As a Xenoscientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract. +As a Scientist, researchable machine parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions. +As a Scientist, the teleporter in Misc research can be set-up to teleport across the whole station! All you need to do is crack the formula. +As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil. +As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them. +As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt. +As the AI, you can take pictures with your camera and upload them to newscasters. +As a Cyborg, choose your module carefully, as only a roboticist can let you repick it. Remember that you don't need to choose immediately after you spawn! +As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes can easily stunlock you and you cannot do any precision work as you lack hands. +As a Cyborg, you are impervious to fires and heat. If you are rogue, you can release plasma fires everywhere and walk through them without a care in the world! +As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds. +As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints. +As the Research Director, you can spy on and even forge PDA communications with the message monitor console! The key is in your office. +As an Engineer, the supermatter shard is an extremely dangerous piece of equipment: touching it will disintegrate you. +As an Engineer, you can electrify grilles by placing wire "nodes" beneath them: the big seemingly unconnected bulges from a half completed wiring job. +As an Engineer, you can power the station solely with the solar arrays. While uninteresting, it is a much safer alternative to most other engines. +As an Engineer, you can repair windows by using a welding tool on them while on any intent other than harm. +As an Engineer, you can lock emitters using your ID card to prevent others from disabling them. +As an Atmospheric Technician, you can't unwrench a pipe if the pressure within is too high. +As the Head of Security, you are expected to coordinate your security force to handle any threat that comes to the station. Sometimes it means making use of the armory to handle a blob, sometimes it means being ruthless during a revolution or cult. +As the Head of Security, you can call for forced cyborgization, but may require the Captain's approval. +As the Head of Security, don't let the power go to your head. You may have high access, great equipment, and a miniature army at your side, but being a terrible person without a good reason is grounds for banning. +As the Warden, your duty is to be the watchdog of the brig and handler of prisoners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes. +As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors. +As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig. Make sure to check on them once in a while! +As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. +As the Warden, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes, forcing prisoners to walk and potentially thwarting an escape. +As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion. +As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are loyalty implanted. Use this to your advantage in a revolution to definitively tell who is on your side! +As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them. +As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department. +As the Head of Personnel, you are just as large a target as the Captain because of the potential power your ID and computer can hand out. +As the Chaplain, your null rod has a lot of functions: it can convert water into holy water, which if spread on the ground prevents wizards from jaunting away, can destroy cultist runes by hitting them, and is a very powerful weapon to boot! +As the Chaplain, your bible is also a container that can store small items. Depending on your god, your starting bible may come with a surprise! +As the Chaplain, you are much more likely to get a response by praying to the gods than most people. To boost your chances, make altars with colorful crayon runes, lit candles, and wire art. +As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo. +As a Botanist, you can mutate the plants growing in your hydroponics trays with unstable mutagen or, as an alternative, crude radioactives from chemistry to get special variations. +As a Botanist, you should look into increasing the potency of your plants. This increases the size, amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist. +As a Cook, any food you make will be much healthier than the junk food found in vendors. Having the crew routinely eating from you will provide minor buffs. +As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in! +As the Bartender, you can use a circular saw on your shotgun to make it easier to store. +As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer or order another from Cargo. +As a Janitor, mousetraps can be used to create bombs or booby-trap containers. +As the Librarian, be sure to keep the shelves stocked and the library clean for crew. +As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them! +As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it. +As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more! +As the Quartermaster, be sure to check the manifests on crates you receive to make sure all the info is correct. If there's a mistake, stamp the manifest DENIED and send it back in a crate with the items untouched for a refund! +As a Shaft Miner, always have a GPS on you, so a fellow miner or cyborg can come to save you if you die. +As a Traitor, the cryptographic sequencer (emag) can not only open doors, but also lockers, crates, APCs and more. It can hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even order more traitor gear or contact the Syndicate. Experiment! +As a Traitor, subverting the AI to serve you can make it an extremely powerful ally. However, be careful of the wording in the laws you give it, as it may use your poorly written laws against you! +As a Traitor, the Captain and the Head of Security are two of the most difficult to kill targets on the station. Plan carefully if either are present. +As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool. +As a Traitor, you may sometimes hunt other traitors, and in turn be hunted by them. +As a Traitor, the syndicate encryption key is very useful for coordinating plans with your fellow traitors -- or, of course, betraying them. +As a Nuclear Operative, communication is key! Use your radio to speak to your fellow operatives and coordinate an attack plan. +As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, are immune to conventional stuns, and can easily take down the AI. +As a Nuclear Operative, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire. +As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life. +As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however. +As a Monkey, you can still wear a few human items, such as backpacks, gas masks and hats, and still have two free hands. +As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them. Make sure to hunt down all those laptops too! +As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation! +As an Alien, you take additional damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage! +As an Alien, resin floors not only regenerate your plasma supply, but also passively heal you. Fight on resin floors to gain a home turf advantage! +As an Alien, the facehugger is by far your most powerful weapon because of its ability to instantly win a fight. Remember however that certain helmets, such as biohoods or space helmets will completely block facehugger attacks. +As an Alien, you are unable to use many human items and machines. Instead, you should focus on sabotaging APCs, computers, cameras and either stowing, spacing, or melting any weapons you find. +As a Revolutionary, you cannot convert a head of staff or someone who has a loyalty implant. Implants can however be surgically removed, and do not carry over with cloning. Take control of medbay to keep control of conversions! +As a Revolutionary, cargo can be your best friend or your worst nightmare. In the best case scenario you will be able to order a limitless amount of guns and armor, in the worst case scenario security will take control and order a limitless number of loyalty implants to turn your fellow revolutionaries against you. +As a Revolutionary, your main power comes from how quickly you spread. Convert people as fast as you can and overwhelm the heads of staff before security can arm up. +As a Changeling, the Extract DNA sting grants you more people to change into, but does not let you choose more powers. +As a Changeling, you can absorb someone by strangling them and using the Absorb verb; this gives you the ability to choose more powers, the DNA of whoever you absorbed, and the memory of the absorbed. +As a Cultist, invest in taking over xenobio, an adamantine golem army can quickly be converted into cultists and constructs. +As a Cultist, your team starts off very weak, but if necessary can quickly convert everything they have into raw power. Make sure you have the numbers and equipment to support going loud, or the cult will fall flat on its face. +As a Cultist, the Blood Boil rune will deal massive amounts of brute damage to non-cultists and some damage to fellow cultists of Nar-Sie nearby. +As a Cultist, you can create an army of manifested goons using a combination of the Manifest rune, which creates homunculi from ghosts, and the Blood Drain rune, which drains life from anyone standing on any blood drain rune. +As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways. +As a Wizard, most spells become unusable if you are not wearing your robe, hat, and sandals. +As a Ghost, you can double click on people, bots, or the singularity to follow them. +Occasionally the tip of the round might lie to you. Don't panic, this is normal. +To defeat your enemy, shoot at them until they die. +Sometimes you won't be able to avoid dying no matter how good you are at the game. Try not to stress too much about it. +When a round ends nearly everything about it is lost forever, leave your salt behind with it. +Killing the entire station isn't fun except when it is. +You can win a pulse rifle from the arcade machine. Honest. +Just like real life the entropy of the game can only increase with time. If things aren't on fire yet, just wait. +Completing your objectives is good practice, but the best antagonists will strive to do more than the bare minimum to really leave an impression. +The more obscure and underused a game mechanic is, the less likely your victims are to be able to deal with it. +Cleanbot. +Some antagonists are supposed to be extremely strong in one on one combat, stop getting mad about it. +Sometimes a round will just be a bust. C'est la vie. +This is a game that is constantly being developed for. Expect things to be added, removed, fixed, and broken on a daily basis. +It's fun to try and predict the round type from the tip of the round message. +The quartermaster is not a head of staff and will never be one. +Your sprite represents your hitbox, so that floor length braid makes you easier to kill. The sacrifices we make for snowflake points. +Spacemen can't move diagonally but most animals can. Blame the slow decline of the numpad. +Sometimes admins will just do stuff. Roll with it. +The remake will never come out. +Plenty of things that aren't traditionally considered weapons can still be used to slowly brutalize someone to death, get creative! +DEATH IS IMMINENT! +This game is older than many of the people playing it. +Do not go gentle into that good night. +Just the tip? +Some people are unable to read text on a game where half of it is based on text. +Phoron check. +Remember the cheesy line! +Toolboxes do more damage if they are full of things, but their contents will spill when you use them as a weapon. +Heads of Staff will be more willing to help you if you bring paperwork that's already filled out. +See no evil, hear no evil, speak no evil. +Auto-Hiss, despite the name, can be used for Unathi, Tajara, and Vaurca. +Service borgs can use the special maidborg sprite if they pray hard enough. +Chainswords and energy weapons can slice walls and people. +If you see this message something has gone seriously wrong. +If you're having trouble as an antagonist, consider a Dionaea whitelist. +As a Medical Doctor, you can attach limbs from one species to the torso of another species. You too can make your own Frankenstein monster! +The second antag contest is still running, you know. +Killing mice on sight is not and never will be gank, no matter how much people complain. +As an Unathi, you are the only species capable of wearing the rare Breacher hardsuits. +As an Unathi, you can devour small mobs after some time. +As a Tajaran, you move pretty fast. Zoom zoom, kitty. +As a Tajaran, your resistance to cold probably doesn't actually help you in space. Feel free to try, though. +As a Skrell you can look pretty and...uhh...not slip? +As a Skrell you have free reign to validhunt synthetics. (Not really, please don't do this oh God what have I done). +As a Human you are the best. Why do you care about your mechanics? +As a Human you are really very great. +As an IPC you are immune to most chemicals and gasses. +As an IPC you can survive longer than most species in space, despite your supposed "weakness". +As a Dionaea you can survive pretty much anything except a tiny little bottle of weedkiller. +As a Dionaea you will die in darkness. Find the light at the end of the tunnel, and quick. +As a Vaurca you can remotely speak to any other Vaurca on board. Not that there are any. +As a Vaurca you can wade freely through phoron gas. Avoid phoron fires though. Somehow a species that breathes phoron gas is really weak to fire. +As an ERT trooper, your most powerful weapons are your team mates. Your second most powerful weapon is your bigass gun. +As an ERT trooper you're still expected to roleplay and progress the round. +As a Ninja, you should learn the difference between invisibility and invulnerability. +As a Ninja, you have a pretty badass sword. Use it. +As a Cortical Borer, you a limp feather can kill you if you're outside of a host. +As a NanoTrasen Actor you can't do anything. Thank Bay. +As a Syndicate Commando you are a Nuke Operative with bigger and better guns. Use them. +As a Death Commando you have only one course of action: RIP AND TEAR. +As a Highlander, there can be only one. +As a Loyalist, remember that you are an antagonist too! +As a Renegade, consider playing a better gamemode. +As a Vampire, you can create new vampires out of willing and less than willing crew. Mind that new vampires may decide to turn their powers against you. +As a Vampire, if you start going hungry for blood don't expect to stay hidden for long. \ No newline at end of file diff --git a/flyway.conf b/flyway.conf new file mode 100644 index 00000000000..e09fa4b59c7 --- /dev/null +++ b/flyway.conf @@ -0,0 +1,6 @@ +flyway.locations=filesystem:sql/migrate + +# copy these into another file and use the -configFile switch on flyway +# flyway.url=jdbc:mysql://localhost/bs12 +# flyway.user= +# flyway.password= diff --git a/html/changelogs/VikingPingvin-PR-1626.yml b/html/changelogs/VikingPingvin-PR-1626.yml new file mode 100644 index 00000000000..d8d3ef1dccc --- /dev/null +++ b/html/changelogs/VikingPingvin-PR-1626.yml @@ -0,0 +1,37 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: VikingPingvin + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added a filter function for departments in the PDA messenger screen." + diff --git a/html/changelogs/alberky-PR-1648.yml b/html/changelogs/alberky-PR-1648.yml new file mode 100644 index 00000000000..f4044d08745 --- /dev/null +++ b/html/changelogs/alberky-PR-1648.yml @@ -0,0 +1,9 @@ +author: Alberyk + +delete-after: True + +changes: + - rscadd: "Ported the newest custom loadout from baystation12." + - rscadd: "Loadout flask and vacuum-flask can now be prefilled." + - rscadd: "Added lunchboxes." + - rscadd: "Added more options to the custom loadout, like winter coats." diff --git a/html/changelogs/lohikar-lighting.yml b/html/changelogs/lohikar-lighting.yml new file mode 100644 index 00000000000..e0eb8658e7c --- /dev/null +++ b/html/changelogs/lohikar-lighting.yml @@ -0,0 +1,21 @@ +author: Lohikar +delete-after: True +changes: + - rscadd: "Ported over /vg/'s smooth lighting system." + - rscadd: "Tweaked the emission color of station lighting." + - rscadd: "Glowing slime cores now emit colored light instead of white light." + - rscadd: "Space tiles are now darker." + - rscadd: "Space tiles now have a parallax effect." + - rscadd: "Added color to the light of many consoles that did not have one set." + - rscdel: "You can no longer rotate your view with Rotate-View verbs, as it was breaking lighting." + - rscdel: "Hallucinations no longer rotate your view for the same reason as above." + - tweak: "Colored lighting should mix better now." + - tweak: "Rebalanced light emission of most light sources to better fit new lighting system." + - tweak: "Diona now gain energy from 'UV' light, emitted by station lighting as well as one or two portable light sources." + - rscdel: "Diona no longer gain any energy from flashlights & other portable light sources." + - experiment: "Lighting now updates immediately when you open an airlock." + - experiment: "Completely rewrote lighting system." + - experiment: "The game's mob processor should be more robust." + - experiment: "Tweaked several of the game's core processes in an effort to reduce lag." + - bugfix: "Fire alarms should no longer cause lag." + - bugfix: "Hydroponics trays should no longer cause lag." diff --git a/html/changelogs/lohikar-paper-planes.yml b/html/changelogs/lohikar-paper-planes.yml new file mode 100644 index 00000000000..a22cb8440c1 --- /dev/null +++ b/html/changelogs/lohikar-paper-planes.yml @@ -0,0 +1,4 @@ +author: Lohikar +delete-after: True +changes: + - rscadd: "You can now fold pieces of paper into paper airplanes, which can be thrown farther than unfolded sheets of paper." diff --git a/html/changelogs/lordfowl - 1885.yml b/html/changelogs/lordfowl - 1885.yml new file mode 100644 index 00000000000..4a94ff679d6 --- /dev/null +++ b/html/changelogs/lordfowl - 1885.yml @@ -0,0 +1,36 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: LordFowl + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added 'Tip of the round' to the lobby. Based off of /tg/'s, it comes with its own Aurora tips too." diff --git a/icons/effects/lighting_overlay.dmi b/icons/effects/lighting_overlay.dmi deleted file mode 100644 index 1ff16d2b78b..00000000000 Binary files a/icons/effects/lighting_overlay.dmi and /dev/null differ diff --git a/icons/effects/lighting_overlay.png b/icons/effects/lighting_overlay.png new file mode 100644 index 00000000000..c7f308204fb Binary files /dev/null and b/icons/effects/lighting_overlay.png differ diff --git a/icons/obj/lunchbox.dmi b/icons/obj/lunchbox.dmi new file mode 100644 index 00000000000..f75c3873721 Binary files /dev/null and b/icons/obj/lunchbox.dmi differ diff --git a/icons/turf/space.dmi b/icons/turf/space.dmi index 30d0d1428a5..ee59a450bed 100644 Binary files a/icons/turf/space.dmi and b/icons/turf/space.dmi differ diff --git a/icons/turf/space_parallax1.dmi b/icons/turf/space_parallax1.dmi new file mode 100644 index 00000000000..8328b3dba9b Binary files /dev/null and b/icons/turf/space_parallax1.dmi differ diff --git a/icons/turf/space_parallax2.dmi b/icons/turf/space_parallax2.dmi new file mode 100644 index 00000000000..8f33b6fc9b1 Binary files /dev/null and b/icons/turf/space_parallax2.dmi differ diff --git a/icons/turf/space_parallax3.dmi b/icons/turf/space_parallax3.dmi new file mode 100644 index 00000000000..0c9d95b6388 Binary files /dev/null and b/icons/turf/space_parallax3.dmi differ diff --git a/icons/turf/space_parallax4.dmi b/icons/turf/space_parallax4.dmi new file mode 100644 index 00000000000..2dbbb39e46b Binary files /dev/null and b/icons/turf/space_parallax4.dmi differ diff --git a/maps/exodus-1.dmm b/maps/exodus-1.dmm index 8a47dc5e6cc..8f9001babbe 100644 --- a/maps/exodus-1.dmm +++ b/maps/exodus-1.dmm @@ -271,7 +271,7 @@ "afk" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/tiled,/area/security/main) "afl" = (/turf/simulated/shuttle/wall{tag = "icon-swall_straight (EAST)"; icon_state = "swall_straight"; dir = 4},/area/shuttle/escape_pod3/station) "afm" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable/green,/obj/structure/cable/green{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/security/main) -"afn" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/escape_pod3/station) +"afn" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/escape_pod3/station) "afo" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled,/area/security/warden) "afp" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable/green{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/tiled,/area/security/warden) "afq" = (/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/security/warden) @@ -326,7 +326,7 @@ "agn" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/table/standard,/obj/structure/reagent_dispensers/peppertank{pixel_x = 30},/obj/item/device/radio,/obj/item/device/radio,/obj/item/device/radio,/obj/item/weapon/crowbar,/obj/item/weapon/crowbar,/obj/item/weapon/crowbar,/obj/item/device/flashlight/maglight,/obj/item/device/flashlight/maglight,/obj/item/device/flashlight/maglight,/obj/effect/floor_decal/corner/blue,/turf/simulated/floor/tiled,/area/security/main) "ago" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/security/main) "agp" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/door/firedoor/border_only{dir = 2},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/command{id_tag = "HoSdoor"; name = "Head of Security"; req_access = list(58)},/turf/simulated/floor/tiled/dark,/area/crew_quarters/heads/hos) -"agq" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (WEST)"; icon_state = "swall_s"; dir = 8},/area/shuttle/escape_pod3/station) +"agq" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (WEST)"; icon_state = "swall_c"; dir = 8},/area/shuttle/escape_pod3/station) "agr" = (/obj/machinery/door/firedoor/border_only{dir = 2},/obj/machinery/door/airlock/glass_security{name = "Warden's Office"; req_access = list(3)},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/green{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled/dark,/area/security/warden) "ags" = (/obj/structure/closet/secure_closet/security,/obj/item/device/flashlight/flare,/obj/structure/window/reinforced,/obj/effect/floor_decal/industrial/outline/yellow,/turf/simulated/floor/tiled,/area/security/main) "agt" = (/obj/structure/closet/wardrobe/red,/obj/structure/window/reinforced,/obj/item/clothing/accessory/holster/waist,/obj/item/clothing/accessory/holster/waist,/obj/item/clothing/accessory/holster/waist,/turf/simulated/floor/tiled,/area/security/main) @@ -984,10 +984,10 @@ "asV" = (/obj/structure/disposalpipe/segment,/mob/living/bot/secbot/beepsky,/turf/simulated/floor/tiled,/area/hallway/primary/fore) "asW" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/corner/blue{tag = "icon-corner_white (WEST)"; icon_state = "corner_white"; dir = 8},/turf/simulated/floor/tiled,/area/hallway/primary/fore) "asX" = (/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/floor_decal/corner/blue,/turf/simulated/floor/tiled,/area/hallway/primary/fore) -"asY" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/escape_pod1/station) -"asZ" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/escape_pod1/station) -"ata" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/escape_pod2/station) -"atb" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/escape_pod2/station) +"asY" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/escape_pod1/station) +"asZ" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/escape_pod1/station) +"ata" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/escape_pod2/station) +"atb" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/escape_pod2/station) "atc" = (/obj/effect/floor_decal/industrial/warning{tag = "icon-warning (NORTH)"; icon_state = "warning"; dir = 1},/turf/simulated/floor/plating,/area/maintenance/arrivals) "atd" = (/obj/machinery/washing_machine,/obj/effect/floor_decal/corner/white/diagonal,/obj/effect/floor_decal/corner/blue/diagonal{dir = 4},/turf/simulated/floor/tiled,/area/security/prison) "ate" = (/obj/machinery/portable_atmospherics/hydroponics,/obj/machinery/light{icon_state = "tube1"; dir = 4},/turf/simulated/floor/tiled,/area/security/prison) @@ -1501,8 +1501,8 @@ "aCS" = (/obj/machinery/atmospherics/binary/passive_gate{dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/maintenance/bar) "aCT" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/maintenance/bar) "aCU" = (/turf/simulated/shuttle/wall{tag = "icon-swall_straight (WEST)"; icon_state = "swall_straight"; dir = 8},/area/shuttle/arrival/station) -"aCV" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/arrival/station) -"aCW" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/arrival/station) +"aCV" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/arrival/station) +"aCW" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/arrival/station) "aCX" = (/turf/simulated/shuttle/wall{tag = "icon-swall_t (NORTH)"; icon_state = "swall_t"; dir = 1},/area/shuttle/arrival/station) "aCY" = (/obj/effect/floor_decal/industrial/warning{tag = "icon-warning (WEST)"; icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/port) "aCZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/camera/network/exodus{c_tag = "Arrivals East"; dir = 8},/obj/effect/floor_decal/corner/white{tag = "icon-corner_white (EAST)"; icon_state = "corner_white"; dir = 4},/obj/effect/floor_decal/corner/blue,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/port) @@ -1900,7 +1900,7 @@ "aKB" = (/obj/structure/closet/coffin,/obj/machinery/door/blast/shutters{density = 0; dir = 2; icon_state = "shutter0"; id = "chapel"; name = "Privacy Shutters"; opacity = 0},/obj/machinery/door/window/westleft{name = "Coffin Storage"},/turf/simulated/floor/tiled/dark,/area/chapel/office) "aKC" = (/obj/structure/table/standard,/obj/effect/floor_decal/chapel{tag = "icon-chapel (EAST)"; icon_state = "chapel"; dir = 4},/turf/simulated/floor/tiled/dark,/area/chapel/main) "aKD" = (/obj/structure/bed/chair{dir = 4},/obj/effect/floor_decal/chapel{tag = "icon-chapel (NORTH)"; icon_state = "chapel"; dir = 1},/turf/simulated/floor/tiled/dark,/area/chapel/main) -"aKE" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (NORTH)"; icon_state = "swall_s"; dir = 1},/area/shuttle/arrival/station) +"aKE" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (NORTH)"; icon_state = "swall_c"; dir = 1},/area/shuttle/arrival/station) "aKF" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/machinery/door/firedoor/border_only{dir = 2},/turf/simulated/floor/plating,/area/hallway/primary/central_one) "aKG" = (/turf/simulated/shuttle/wall{tag = "icon-swall_t"; icon_state = "swall_t"},/area/shuttle/arrival/station) "aKH" = (/obj/machinery/door/firedoor/border_only{dir = 8; name = "Firelock West"},/obj/machinery/light,/turf/simulated/floor/tiled,/area/hallway/secondary/entry/starboard) @@ -1990,7 +1990,7 @@ "aMn" = (/obj/machinery/light{dir = 8},/obj/machinery/camera/network/civilian_east{c_tag = "Chapel North"; dir = 4},/turf/simulated/floor/tiled/dark,/area/chapel/main) "aMo" = (/obj/structure/table/standard,/obj/machinery/light/small,/obj/effect/floor_decal/chapel,/turf/simulated/floor/tiled/dark,/area/chapel/main) "aMp" = (/obj/structure/bed/chair{dir = 4},/obj/effect/floor_decal/chapel{tag = "icon-chapel (WEST)"; icon_state = "chapel"; dir = 8},/turf/simulated/floor/tiled/dark,/area/chapel/main) -"aMq" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (WEST)"; icon_state = "swall_s"; dir = 8},/area/shuttle/arrival/station) +"aMq" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (WEST)"; icon_state = "swall_c"; dir = 8},/area/shuttle/arrival/station) "aMr" = (/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/effect/floor_decal/industrial/warning{tag = "icon-warning (WEST)"; icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/hallway/secondary/entry/port) "aMs" = (/obj/structure/bed/chair/comfy/beige,/turf/simulated/floor/lino,/area/hallway/secondary/entry/starboard) "aMt" = (/turf/simulated/floor/lino,/area/hallway/secondary/entry/starboard) @@ -3829,13 +3829,13 @@ "bvG" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/tiled/white,/area/rnd/lab) "bvH" = (/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/obj/effect/floor_decal/industrial/warning/corner{tag = "icon-warningcorner (NORTH)"; icon_state = "warningcorner"; dir = 1},/turf/simulated/floor/tiled/white,/area/rnd/lab) "bvI" = (/obj/item/weapon/stock_parts/console_screen,/obj/structure/table/standard,/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/console_screen,/obj/item/weapon/stock_parts/matter_bin,/obj/item/weapon/stock_parts/matter_bin,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled/white,/area/rnd/lab) -"bvJ" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/research/station) +"bvJ" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/research/station) "bvK" = (/turf/simulated/wall/r_wall,/area/crew_quarters/heads/hop) "bvL" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only{dir = 2},/obj/structure/cable/cyan,/turf/simulated/floor/plating,/area/turret_protected/ai_upload) "bvM" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/tiled/dark{name = "cooled dark floor"; temperature = 278},/area/turret_protected/ai_upload) "bvN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/bluegrid{name = "cooled mainframe floor"; temperature = 278},/area/turret_protected/ai_upload) "bvO" = (/turf/simulated/shuttle/wall{tag = "icon-swall_straight (EAST)"; icon_state = "swall_straight"; dir = 4},/area/shuttle/research/station) -"bvP" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/research/station) +"bvP" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/research/station) "bvQ" = (/obj/machinery/conveyor_switch/oneway{id = "QMLoad2"},/obj/effect/floor_decal/industrial/warning{tag = "icon-warning (SOUTHWEST)"; icon_state = "warning"; dir = 10},/turf/simulated/floor/tiled,/area/quartermaster/loading) "bvR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/dark{name = "cooled dark floor"; temperature = 278},/area/turret_protected/ai_upload) "bvS" = (/obj/structure/table/standard,/obj/item/weapon/aiModule/freeform,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/item/weapon/aiModule/protectStation,/turf/simulated/floor/bluegrid{name = "cooled mainframe floor"; temperature = 278},/area/turret_protected/ai_upload) @@ -4172,8 +4172,8 @@ "bCl" = (/obj/structure/closet/crate{name = "Camera Assembly Crate"},/obj/item/weapon/camera_assembly,/obj/item/weapon/camera_assembly,/obj/item/weapon/camera_assembly,/obj/item/weapon/camera_assembly,/turf/simulated/floor/bluegrid,/area/turret_protected/ai_cyborg_station) "bCm" = (/obj/machinery/requests_console{announcementConsole = 1; department = "Research Director's Desk"; departmentType = 5; name = "Research Director RC"; pixel_x = -2; pixel_y = 30},/obj/structure/window/reinforced{dir = 4},/obj/effect/floor_decal/corner/white/diagonal{tag = "icon-corner_white_diagonal (EAST)"; icon_state = "corner_white_diagonal"; dir = 4},/obj/item/modular_computer/console/preset/research,/turf/simulated/floor/tiled,/area/crew_quarters/heads/hor) "bCn" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled/dark,/area/turret_protected/ai_server_room) -"bCo" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (NORTH)"; icon_state = "swall_s"; dir = 1},/area/shuttle/research/station) -"bCp" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (WEST)"; icon_state = "swall_s"; dir = 8},/area/shuttle/research/station) +"bCo" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (NORTH)"; icon_state = "swall_c"; dir = 1},/area/shuttle/research/station) +"bCp" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (WEST)"; icon_state = "swall_c"; dir = 8},/area/shuttle/research/station) "bCq" = (/obj/machinery/conveyor_switch/oneway{convdir = -1; id = "QMLoad"},/turf/simulated/floor/tiled,/area/quartermaster/loading) "bCr" = (/obj/effect/floor_decal/industrial/warning{tag = "icon-warning (WEST)"; icon_state = "warning"; dir = 8},/turf/simulated/floor/tiled,/area/quartermaster/loading) "bCs" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 1},/turf/simulated/floor/tiled,/area/quartermaster/loading) @@ -4568,8 +4568,8 @@ "bJR" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/airless,/area/rnd/test_area) "bJS" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/airless,/area/rnd/test_area) "bJT" = (/turf/simulated/shuttle/wall{tag = "icon-swall_straight (EAST)"; icon_state = "swall_straight"; dir = 4},/area/shuttle/mining/station) -"bJU" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/mining/station) -"bJV" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/mining/station) +"bJU" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/mining/station) +"bJV" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/mining/station) "bJW" = (/turf/simulated/floor/tiled,/area/quartermaster/miningdock) "bJX" = (/obj/machinery/computer/security/mining,/obj/item/device/radio/intercom{dir = 0; name = "Station Intercom (General)"; pixel_x = -27},/obj/machinery/camera/network/civilian_west{c_tag = "Cargo Mining Dock"; dir = 4},/turf/simulated/floor/tiled,/area/quartermaster/miningdock) "bJY" = (/obj/machinery/vending/medical,/turf/simulated/wall,/area/medical/medbay) @@ -5021,14 +5021,14 @@ "bSC" = (/obj/machinery/door/airlock/engineering{name = "Tech Storage"; req_access = list(23)},/obj/structure/cable/green{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/hallway/primary/aft) "bSD" = (/obj/structure/bed/chair{dir = 4},/obj/machinery/computer/security/telescreen{desc = "Used for watching the test chamber."; layer = 4; name = "Test Chamber Telescreen"; network = list("Toxins Test Area"); pixel_x = 32; pixel_y = 0},/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/obj/effect/floor_decal/industrial/warning/corner{dir = 8},/turf/simulated/floor/tiled,/area/rnd/mixing) "bSE" = (/obj/effect/floor_decal/industrial/warning{dir = 4},/turf/simulated/floor/tiled/airless,/area/rnd/test_area) -"bSF" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (NORTH)"; icon_state = "swall_s"; dir = 1},/area/shuttle/mining/station) +"bSF" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (NORTH)"; icon_state = "swall_c"; dir = 1},/area/shuttle/mining/station) "bSG" = (/obj/machinery/door/airlock/maintenance{name = "Custodial Maintenance"; req_access = list(26)},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/janitor) "bSH" = (/obj/machinery/power/apc{dir = 8; name = "west bump"; pixel_x = -24},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/turf/simulated/floor/plating,/area/maintenance/engineering) "bSI" = (/obj/structure/grille/broken,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/plating,/area/maintenance/engineering) "bSJ" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/maintenance/engineering) "bSK" = (/obj/machinery/space_heater,/turf/simulated/floor/plating,/area/maintenance/engineering) "bSL" = (/obj/structure/closet/crate,/obj/random/coin,/turf/simulated/floor/plating,/area/storage/emergency) -"bSM" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (WEST)"; icon_state = "swall_s"; dir = 8},/area/shuttle/mining/station) +"bSM" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (WEST)"; icon_state = "swall_c"; dir = 8},/area/shuttle/mining/station) "bSN" = (/turf/simulated/floor/tiled,/area/storage/tech) "bSO" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/circuitboard/robotics{pixel_x = -2; pixel_y = 2},/obj/item/weapon/circuitboard/mecha_control{pixel_x = 1; pixel_y = -1},/turf/simulated/floor/tiled,/area/storage/tech) "bSP" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/circuitboard/powermonitor{pixel_x = -2; pixel_y = 2},/obj/item/weapon/circuitboard/stationalert{pixel_x = 1; pixel_y = -1},/obj/item/weapon/circuitboard/security/engineering,/obj/item/weapon/circuitboard/atmos_alert{pixel_x = 3; pixel_y = -3},/turf/simulated/floor/plating,/area/storage/tech) @@ -5169,7 +5169,7 @@ "bVu" = (/obj/item/device/radio/beacon,/obj/effect/landmark{name = "blobstart"},/obj/effect/floor_decal/industrial/warning/full,/turf/simulated/floor/tiled,/area/rnd/test_area) "bVv" = (/obj/machinery/light{dir = 4},/obj/machinery/camera/network/research{c_tag = "Research Toxins Test Chamber East"; dir = 8; network = list("Research","Toxins Test Area")},/turf/simulated/floor/tiled/airless,/area/rnd/test_area) "bVw" = (/turf/simulated/shuttle/wall{tag = "icon-swall_straight (EAST)"; icon_state = "swall_straight"; dir = 4},/area/shuttle/escape_pod5/station) -"bVx" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/escape_pod5/station) +"bVx" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/escape_pod5/station) "bVy" = (/obj/machinery/door/airlock/glass{name = "Central Access"},/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/hallway/primary/aft) "bVz" = (/obj/machinery/door/airlock/glass{name = "Central Access"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/effect/floor_decal/corner/yellow{tag = "icon-corner_white (WEST)"; icon_state = "corner_white"; dir = 8},/turf/simulated/floor/tiled,/area/hallway/primary/aft) "bVA" = (/obj/machinery/door/window/eastleft{name = "Medical Delivery"; req_access = list(5)},/obj/machinery/door/firedoor,/turf/simulated/floor/plating,/area/medical/sleeper) @@ -5324,7 +5324,7 @@ "bYt" = (/obj/machinery/atmospherics/pipe/simple/hidden/cyan{dir = 6; icon_state = "intact"; tag = "icon-intact-f (SOUTHEAST)"},/obj/effect/floor_decal/industrial/warning{dir = 9},/turf/simulated/floor/plating,/area/maintenance/research_starboard) "bYu" = (/obj/machinery/atmospherics/pipe/tank/air{dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/plating,/area/maintenance/research_starboard) "bYv" = (/obj/machinery/atmospherics/pipe/manifold/hidden/cyan{tag = "icon-map (NORTH)"; icon_state = "map"; dir = 1},/obj/machinery/light/small{dir = 1},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/plating,/area/maintenance/research_starboard) -"bYw" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (NORTH)"; icon_state = "swall_s"; dir = 1},/area/shuttle/escape_pod5/station) +"bYw" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (NORTH)"; icon_state = "swall_c"; dir = 1},/area/shuttle/escape_pod5/station) "bYx" = (/obj/item/modular_computer/telescreen/preset/generic{pixel_y = 32},/turf/simulated/floor/tiled,/area/crew_quarters/heads/chief) "bYy" = (/obj/structure/table/reinforced,/obj/machinery/light{dir = 1},/obj/machinery/light_switch{pixel_x = 0; pixel_y = 27},/obj/machinery/computer/skills{icon_state = "medlaptop"},/turf/simulated/floor/tiled,/area/crew_quarters/heads/chief) "bYz" = (/obj/effect/floor_decal/corner/white/diagonal,/obj/item/modular_computer/console/preset/engineering,/turf/simulated/floor/tiled,/area/engineering/break_room) @@ -7071,8 +7071,8 @@ "cFY" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plating,/area/engineering/drone_fabrication) "cFZ" = (/obj/structure/table/reinforced,/obj/item/weapon/storage/toolbox/electrical,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/obj/machinery/camera/network/engineering{c_tag = "Engineering Drone Fabrication"; dir = 8},/turf/simulated/floor/plating,/area/engineering/drone_fabrication) "cGa" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/wall/r_wall,/area/engineering/engine_smes) -"cGb" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (EAST)"; icon_state = "swall_s"; dir = 4},/area/shuttle/constructionsite/station) -"cGc" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s"; icon_state = "swall_s"},/area/shuttle/constructionsite/station) +"cGb" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (EAST)"; icon_state = "swall_c"; dir = 4},/area/shuttle/constructionsite/station) +"cGc" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c"; icon_state = "swall_c"},/area/shuttle/constructionsite/station) "cGd" = (/obj/structure/table/rack,/obj/machinery/atmospherics/pipe/manifold/hidden/cyan,/obj/random/loot,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/plating,/area/maintenance/engineering) "cGe" = (/obj/structure/table/rack{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/cyan{dir = 5; icon_state = "intact"; tag = "icon-intact-f (NORTHWEST)"},/obj/random/loot,/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/plating,/area/maintenance/engineering) "cGf" = (/obj/machinery/atmospherics/pipe/simple/hidden/cyan{dir = 9; icon_state = "intact"; tag = "icon-intact-f (NORTHWEST)"},/obj/machinery/meter,/obj/machinery/space_heater,/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/maintenance/engineering) @@ -7104,6 +7104,7 @@ "cGF" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/computer/rcon,/turf/simulated/floor/tiled,/area/engineering/engine_monitoring) "cGG" = (/obj/effect/floor_decal/industrial/warning,/obj/item/modular_computer/console/preset/engineering,/turf/simulated/floor/tiled,/area/engineering/engine_monitoring) "cGH" = (/obj/machinery/computer/station_alert,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled,/area/engineering/engine_monitoring) +"cGI" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (NORTH)"; icon_state = "swall_c"; dir = 1},/area/shuttle/constructionsite/station) "cGJ" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/engineering/drone_fabrication) "cGK" = (/obj/machinery/airlock_sensor{frequency = 1379; id_tag = "eng_al_c_snsr"; pixel_x = -25; pixel_y = 0},/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -29},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 10},/turf/simulated/floor/plating,/area/engineering/engine_airlock) "cGL" = (/obj/machinery/light/small{dir = 4},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/plating,/area/engineering/engine_airlock) @@ -7139,8 +7140,7 @@ "cHp" = (/obj/machinery/atmospherics/pipe/simple/visible/yellow{dir = 6},/obj/effect/floor_decal/industrial/warning{dir = 8},/turf/simulated/floor/plating,/area/engineering/engine_room) "cHq" = (/obj/structure/cable/yellow{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/plating,/area/engineering/engine_room) "cHr" = (/obj/machinery/atmospherics/pipe/manifold/visible/cyan{tag = "icon-map (EAST)"; icon_state = "map"; dir = 4},/turf/simulated/floor/plating,/area/engineering/engine_room) -"cHs" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (NORTH)"; icon_state = "swall_s"; dir = 1},/area/shuttle/constructionsite/station) -"cHt" = (/turf/simulated/shuttle/wall{tag = "icon-swall_s (WEST)"; icon_state = "swall_s"; dir = 8},/area/shuttle/constructionsite/station) +"cHs" = (/turf/space,/turf/simulated/shuttle/wall{tag = "icon-swall_c (WEST)"; icon_state = "swall_c"; dir = 8},/area/shuttle/constructionsite/station) "cHu" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/yellow{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/airless,/area/solar/port) "cHv" = (/obj/machinery/atmospherics/unary/heat_exchanger{dir = 8},/obj/effect/floor_decal/industrial/warning{dir = 9},/turf/simulated/floor/plating,/area/engineering/engine_waste) "cHw" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/manifold/visible/yellow{dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/floor_decal/industrial/warning{tag = "icon-warning (EAST)"; icon_state = "warning"; dir = 4},/turf/simulated/floor/plating,/area/engineering/engine_waste) @@ -7561,7 +7561,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaaaaaaaJaafaafaaachCcFFcGgcFFchCcFHcGhcFHchCcFJcGicFJchCaafchCcFJcGjcFJchCaafaafaafcHhcHicGycGxcGAcGzcHncEKcDXcETcGDcGCcEOcGEcGFcrRcGGcGHcEOcGKcHxcGLcEeaaacHzcHAcHBcGMcHDcHEcGNcHGcMGcHIbOsbOsaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacrgcHJcricricricCpcrgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacswcswcswcswcswaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaBaaaaaachCchCchCchCchCchCchCchCchCchCchCchCchCaaacHKchCchCchCchCaaaaaaaaaaaacCScCScCScCScCScHLcHMcHMcHMcHMcHNcHMcHOcHPcHQcHPcHRcHMcHMcHScHMcHMcHMcHzcHAcHTcGOcHVcHWcHXaafaaaaaaaaaaaaaaaaaaaaaaafaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacswaaaaaaaafaafaaaaafaafaaaaaaaafaafaafaaaaaaaaaaaaaaaaaaaafaaacHYcHZcHZcHZcIacGPcGQcIdcIecGRcGTcIhcGUcIjcGYcGVcHdcIrcIocIpcIqcIrcIscHecIucIvcHecHMcHzcHAcIwcHfcIycIzcGNaafaaacHYcIBcHYcIBcHYcIBaafcICaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafcHgcHkcHjaaacHgcHkcHjaaacHgcHkcHjaafaafaaaaafaafaafaafaafcIGcHZcHZcHZcIacGPcHlcIIcIJcHmcHocIMcHpcIOcHrcHqcITcITcITcIUcITcITcITcIVcITcIWcIXcHMcHscFXcFXcFXcFXcFXcHtaafaafcJacJacJacJacJacJaaafcICaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaafcHgcHkcHjaaacHgcHkcHjaaacHgcHkcHjaafaafaaaaafaafaafaafaafcIGcHZcHZcHZcIacGPcHlcIIcIJcHmcHocIMcHpcIOcHrcHqcITcITcITcIUcITcITcITcIVcITcIWcIXcHMcGIcFXcFXcFXcFXcFXcHsaafaafcJacJacJacJacJacJaaafcICaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamaaacHgcHucHjaaacHgcHucHjaaacHgcHucHjaafaafaaaaafaaaaaacJcaafcHYcHZcHZcHZcIacGPcHlcHvcHycHwcHCcIMcHFcJicJjcIucIucIucIbcHUcJHcIucIucJicJncJocJpcHMcHMcHMcJqaaaaaaaaaaaabvcaaacJrcJrcJrcJrcJrcJraafcICaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaJaafcHgcHucHjaaacHgcHucHjaafcHgcHucHjaafaaaaaaaafaafcJsaaaaafcIGcHZcHZcHZcIacGPcIfcIccIicIgcIlcIkcImcJAcJBcJCcJCcJCcHrcIncLbcJCcJCcJGcJHcJIcJJcJKcJLcJMcJNcJOcJOcJOcJOcJOcJOcJPcJQcJPcJQcJPcJaaafcICaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFcuFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafaaacHgcHucHjaafcHgcHucHjaaacHgcHucHjaaaaaaaaaaaaaafaafaaaaafaaaaaaaaaaaaaafcJRcJScJTcJUcItcIxcIhcIucIucIucIucIDcIAcIFcIEcIKcIHcILcKfcKgcKhcKicKjcINcKlcJNcKmcKncKmcKncKmcKncKmcKncKmcKncKmcJaaafcICaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacyFcyFcyFcyFcyFcyFcyFcyFcyFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl index 6baf2781474..bdb9f82f7d2 100644 --- a/nano/templates/pda.tmpl +++ b/nano/templates/pda.tmpl @@ -213,6 +213,20 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm {{:helper.link('Set Ringtone', 'comment', {'choice' : "Ringtone"}, null, 'fixedLeftWide')}} {{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'fixedLeftWider')}} +
+ Filter PDAs +
+
+ {{:helper.link( 'All',data.pdafilter == 0? 'null' : 'close', {'choice' : "Filter", 'option' : "0"}, null, 'fixedLeft')}} + {{:helper.link('Command',data.pdafilter == 2? 'null': 'close', {'choice' : "Filter", 'option' : "2"}, null, 'fixedLeft')}} + {{:helper.link('Security',data.pdafilter == 3? 'null': 'close', {'choice' : "Filter", 'option' : "3"}, null, 'fixedLeft')}} + {{:helper.link('Engineering',data.pdafilter == 4? 'null': 'close', {'choice' : "Filter", 'option' : "4"}, null, 'fixedLeft')}} + {{:helper.link('Science',data.pdafilter == 5? 'null': 'close', {'choice' : "Filter", 'option' : "5"}, null, 'fixedLeft')}} + {{:helper.link('Cargo',data.pdafilter == 6? 'null': 'close', {'choice' : "Filter", 'option' : "6"}, null, 'fixedLeft')}} + {{:helper.link('Service',data.pdafilter == 7? 'null': 'close', {'choice' : "Filter", 'option' : "7"}, null, 'fixedLeft')}} + {{:helper.link('Medical',data.pdafilter == 8? 'null': 'close', {'choice' : "Filter", 'option' : "8"}, null, 'fixedLeft')}} +
+ {{if data.toff == 0}}