mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-18 11:30:35 +01:00
Update, 19MAR2017
New lights SQL Migrations A tonne of minor fixes and tweaks Some stuff left to be added
This commit is contained in:
Binary file not shown.
@@ -1,11 +1,11 @@
|
||||
# baystation12
|
||||
# Aurorastation
|
||||
|
||||
[Website](http://baystation12.net/) - [Code](http://github.com/Baystation12/Baystation12/) - [IRC](http://baystation12.net/forums/viewtopic.php?f=12&t=5088)
|
||||
[Website](https://aurorastation.org/) - [Code](https://github.com/Aurorastation/Aurora.3)
|
||||
|
||||
---
|
||||
|
||||
### LICENSE
|
||||
Baystation12 is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE-AGPL3.txt.
|
||||
Aurorastation is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE-AGPL3.txt.
|
||||
|
||||
Commits with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt.
|
||||
|
||||
@@ -18,11 +18,11 @@ See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more informatio
|
||||
### GETTING THE CODE
|
||||
The simplest way to obtain the code is using the github .zip feature.
|
||||
|
||||
Click [here](https://github.com/Baystation12/Baystation12/archive/master.zip) to get the latest code as a .zip file, then unzip it to wherever you want.
|
||||
Click [here](https://github.com/Aurorastation/Aurora.3/archive/master.zip) to get the latest stable code as a .zip file, then unzip it to wherever you want.
|
||||
|
||||
The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in:
|
||||
|
||||
git clone https://github.com/Baystation12/Baystation12.git
|
||||
git clone https://github.com/Aurorastation/Aurora.3.git
|
||||
|
||||
(hint: hold down ctrl and press insert to paste into git bash)
|
||||
|
||||
@@ -30,7 +30,7 @@ This will take a while to download, but it provides an easier method for updatin
|
||||
|
||||
Once the repository is in place, run this command:
|
||||
```bash
|
||||
cd Baystation12
|
||||
cd Aurora.3
|
||||
git update-index --assume-unchanged baystation12.int
|
||||
```
|
||||
Now git will ignore changes to the file baystation12.int.
|
||||
@@ -45,7 +45,7 @@ This is a sourcecode-only release, so the next step is to compile the server fil
|
||||
|
||||
baystation12.dmb - 0 errors, 0 warnings
|
||||
|
||||
If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on IRC.
|
||||
If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on the server Discord if you're completely lost.
|
||||
|
||||
Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each round. It's recommended you don't turn on the gamemodes with probability 0, as they have various issues and aren't currently being tested, so they may have unknown and bizarre bugs.
|
||||
|
||||
@@ -78,16 +78,12 @@ When you have done this, you'll need to recompile the code, but then it should w
|
||||
|
||||
### Configuration
|
||||
|
||||
For a basic setup, simply copy every file from config/example to config.
|
||||
For a basic setup, simply copy every file from config/example to config.
|
||||
|
||||
For more advanced setups, setting the server `tick_lag` in the config as well as configuring SQL are good first steps.
|
||||
|
||||
---
|
||||
|
||||
### SQL Setup
|
||||
|
||||
The SQL backend for the library and stats tracking requires a MySQL server. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql. More detailed setup instructions arecoming soon, for now ask in our IRC channel.
|
||||
|
||||
---
|
||||
|
||||
### IRC Bot Setup
|
||||
|
||||
Included in the repo is an IRC bot capable of relaying adminhelps to a specified IRC channel/server (thanks to Skibiliano). Instructions for bot setup are included in the /bot/ folder along with the bot/relay script itself.
|
||||
The SQL backend for the library and stats tracking requires a MySQL server, as does the optional SQL saves system. Your server details go in config/dbconfig.txt, and initial database setup is done with [flyway](https://flywaydb.org/). Detailed instructions can be found [here](https://github.com/Aurorastation/Aurora.3/tree/master/SQL).
|
||||
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -0,0 +1,18 @@
|
||||
-- These are tables used only for debugging/profiling.
|
||||
-- They are not needed for normal server operation.
|
||||
|
||||
CREATE TABLE `ss13dbg_lighting` (
|
||||
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`time` INT(11) UNSIGNED NULL DEFAULT NULL COMMENT 'World time (in ticks)',
|
||||
`tick_usage` DOUBLE UNSIGNED NULL DEFAULT NULL,
|
||||
`type` VARCHAR(32) NULL DEFAULT NULL COMMENT 'The type of the update.' COLLATE 'latin1_bin',
|
||||
`name` VARCHAR(50) NULL DEFAULT NULL COMMENT 'The callee\'s name.' COLLATE 'latin1_bin',
|
||||
`loc_name` VARCHAR(50) NULL DEFAULT NULL COMMENT 'The callee\'s location.' COLLATE 'latin1_bin',
|
||||
`x` SMALLINT(6) NULL DEFAULT NULL,
|
||||
`y` SMALLINT(6) NULL DEFAULT NULL,
|
||||
`z` SMALLINT(6) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
)
|
||||
COLLATE='latin1_bin'
|
||||
ENGINE=MEMORY
|
||||
ROW_FORMAT=FIXED;
|
||||
+105
-24
@@ -23,11 +23,13 @@
|
||||
#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"
|
||||
#include "code\__defines\machinery.dm"
|
||||
#include "code\__defines\math_physics.dm"
|
||||
#include "code\__defines\mining.dm"
|
||||
#include "code\__defines\misc.dm"
|
||||
#include "code\__defines\mobs.dm"
|
||||
#include "code\__defines\process_scheduler.dm"
|
||||
@@ -51,6 +53,7 @@
|
||||
#include "code\_helpers\matrices.dm"
|
||||
#include "code\_helpers\mobs.dm"
|
||||
#include "code\_helpers\names.dm"
|
||||
#include "code\_helpers\overlay.dm"
|
||||
#include "code\_helpers\sanitize_values.dm"
|
||||
#include "code\_helpers\spawn_sync.dm"
|
||||
#include "code\_helpers\text.dm"
|
||||
@@ -78,6 +81,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"
|
||||
@@ -121,6 +125,7 @@
|
||||
#include "code\controllers\emergency_shuttle_controller.dm"
|
||||
#include "code\controllers\hooks-defs.dm"
|
||||
#include "code\controllers\hooks.dm"
|
||||
#include "code\controllers\law.dm"
|
||||
#include "code\controllers\master_controller.dm"
|
||||
#include "code\controllers\shuttle_controller.dm"
|
||||
#include "code\controllers\subsystems.dm"
|
||||
@@ -130,12 +135,13 @@
|
||||
#include "code\controllers\Processes\alarm.dm"
|
||||
#include "code\controllers\Processes\chemistry.dm"
|
||||
#include "code\controllers\Processes\disease.dm"
|
||||
#include "code\controllers\Processes\effects.dm"
|
||||
#include "code\controllers\Processes\emergencyShuttle.dm"
|
||||
#include "code\controllers\Processes\event.dm"
|
||||
#include "code\controllers\Processes\explosives.dm"
|
||||
#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"
|
||||
@@ -165,7 +171,7 @@
|
||||
#include "code\datums\mind.dm"
|
||||
#include "code\datums\mixed.dm"
|
||||
#include "code\datums\modules.dm"
|
||||
#include "code\datums\recipe.dm"
|
||||
#include "code\datums\scheduled_task.dm"
|
||||
#include "code\datums\server_greeting.dm"
|
||||
#include "code\datums\sun.dm"
|
||||
#include "code\datums\supplypacks.dm"
|
||||
@@ -329,6 +335,7 @@
|
||||
#include "code\game\gamemodes\setupgame.dm"
|
||||
#include "code\game\gamemodes\calamity\calamity.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling_items.dm"
|
||||
#include "code\game\gamemodes\changeling\changeling_powers.dm"
|
||||
#include "code\game\gamemodes\changeling\modularchangling.dm"
|
||||
#include "code\game\gamemodes\cult\cult.dm"
|
||||
@@ -459,6 +466,8 @@
|
||||
#include "code\game\machinery\wall_frames.dm"
|
||||
#include "code\game\machinery\washing_machine.dm"
|
||||
#include "code\game\machinery\wishgranter.dm"
|
||||
#include "code\game\machinery\abstract\abstract.dm"
|
||||
#include "code\game\machinery\abstract\intercom_listener.dm"
|
||||
#include "code\game\machinery\atmoalter\area_atmos_computer.dm"
|
||||
#include "code\game\machinery\atmoalter\canister.dm"
|
||||
#include "code\game\machinery\atmoalter\meter.dm"
|
||||
@@ -527,10 +536,13 @@
|
||||
#include "code\game\machinery\kitchen\icecream.dm"
|
||||
#include "code\game\machinery\kitchen\microwave.dm"
|
||||
#include "code\game\machinery\kitchen\smartfridge.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\_appliance.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\_cooker.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\_cooker_output.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\_mixer.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\candy.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\cereal.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\container.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\fryer.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\grill.dm"
|
||||
#include "code\game\machinery\kitchen\cooking_machines\oven.dm"
|
||||
@@ -630,6 +642,8 @@
|
||||
#include "code\game\objects\items\devices\flashlight.dm"
|
||||
#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"
|
||||
@@ -1017,7 +1031,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"
|
||||
@@ -1037,6 +1050,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"
|
||||
@@ -1144,6 +1173,11 @@
|
||||
#include "code\modules\economy\Events.dm"
|
||||
#include "code\modules\economy\Events_Mundane.dm"
|
||||
#include "code\modules\economy\TradeDestinations.dm"
|
||||
#include "code\modules\effects\effect_system.dm"
|
||||
#include "code\modules\effects\visual_effect.dm"
|
||||
#include "code\modules\effects\sparks\procs.dm"
|
||||
#include "code\modules\effects\sparks\spawner.dm"
|
||||
#include "code\modules\effects\sparks\visuals.dm"
|
||||
#include "code\modules\events\apc_damage.dm"
|
||||
#include "code\modules\events\bear_attack.dm"
|
||||
#include "code\modules\events\blob.dm"
|
||||
@@ -1195,7 +1229,10 @@
|
||||
#include "code\modules\flufftext\Dreaming.dm"
|
||||
#include "code\modules\flufftext\Hallucination.dm"
|
||||
#include "code\modules\flufftext\TextFilters.dm"
|
||||
#include "code\modules\food\recipe.dm"
|
||||
#include "code\modules\food\recipes_fryer.dm"
|
||||
#include "code\modules\food\recipes_microwave.dm"
|
||||
#include "code\modules\food\recipes_oven.dm"
|
||||
#include "code\modules\games\boardgame.dm"
|
||||
#include "code\modules\games\cardemon.dm"
|
||||
#include "code\modules\games\cards.dm"
|
||||
@@ -1240,13 +1277,15 @@
|
||||
#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_verbs.dm"
|
||||
#include "code\modules\lighting\~lighting_undefs.dm"
|
||||
#include "code\modules\liquid\splash_simulation.dm"
|
||||
#include "code\modules\maps\dmm_suite.dm"
|
||||
@@ -1276,6 +1315,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"
|
||||
@@ -1505,6 +1545,7 @@
|
||||
#include "code\modules\mob\living\simple_animal\borer\say.dm"
|
||||
#include "code\modules\mob\living\simple_animal\constructs\constructs.dm"
|
||||
#include "code\modules\mob\living\simple_animal\constructs\soulstone.dm"
|
||||
#include "code\modules\mob\living\simple_animal\familiars\familiars.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\cat.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\corgi.dm"
|
||||
#include "code\modules\mob\living\simple_animal\friendly\crab.dm"
|
||||
@@ -1531,6 +1572,9 @@
|
||||
#include "code\modules\mob\living\simple_animal\hostile\russian.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\syndicate.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\tree.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\commanded\_command_defines.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\commanded\bear_companion.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\commanded\commanded.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\retaliate\drone.dm"
|
||||
#include "code\modules\mob\living\simple_animal\hostile\retaliate\retaliate.dm"
|
||||
@@ -1542,23 +1586,27 @@
|
||||
#include "code\modules\mob\new_player\skill.dm"
|
||||
#include "code\modules\mob\new_player\sprite_accessories.dm"
|
||||
#include "code\modules\modular_computers\laptop_vendor.dm"
|
||||
#include "code\modules\modular_computers\computers\item\modular_computer.dm"
|
||||
#include "code\modules\modular_computers\computers\item\processor.dm"
|
||||
#include "code\modules\modular_computers\computers\item\tablet.dm"
|
||||
#include "code\modules\modular_computers\computers\item\tablet_presets.dm"
|
||||
#include "code\modules\modular_computers\computers\machinery\console_presets.dm"
|
||||
#include "code\modules\modular_computers\computers\machinery\modular_computer.dm"
|
||||
#include "code\modules\modular_computers\computers\machinery\modular_console.dm"
|
||||
#include "code\modules\modular_computers\computers\machinery\modular_laptop.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\core.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\damage.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\hardware.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\interaction.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\power.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\ui.dm"
|
||||
#include "code\modules\modular_computers\computers\modular_computer\variables.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\dev_console.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\dev_laptop.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\dev_tablet.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\dev_telescreen.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\preset_console.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\preset_tablet.dm"
|
||||
#include "code\modules\modular_computers\computers\subtypes\preset_telescreen.dm"
|
||||
#include "code\modules\modular_computers\file_system\computer_file.dm"
|
||||
#include "code\modules\modular_computers\file_system\data.dm"
|
||||
#include "code\modules\modular_computers\file_system\news_article.dm"
|
||||
#include "code\modules\modular_computers\file_system\program.dm"
|
||||
#include "code\modules\modular_computers\file_system\program_events.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\_program.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\configurator.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\file_browser.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\ntdownloader.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\app_presets.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\antagonist\hacked_camera.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm"
|
||||
@@ -1571,11 +1619,16 @@
|
||||
#include "code\modules\modular_computers\file_system\programs\generic\news_browser.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\generic\ntnrc_client.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\generic\nttransfer.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\medical\_medical.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\_research.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\medical\suit_sensors.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\ai_restorer.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\exosuit_monitor.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\research\ntmonitor.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\camera.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\client_manager.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\configurator.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\file_browser.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\ntdownloader.dm"
|
||||
#include "code\modules\modular_computers\hardware\ai_slot.dm"
|
||||
#include "code\modules\modular_computers\hardware\battery_module.dm"
|
||||
#include "code\modules\modular_computers\hardware\card_slot.dm"
|
||||
@@ -1596,9 +1649,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"
|
||||
@@ -1718,6 +1768,7 @@
|
||||
#include "code\modules\projectiles\guns\projectile.dm"
|
||||
#include "code\modules\projectiles\guns\energy\laser.dm"
|
||||
#include "code\modules\projectiles\guns\energy\lawgiver.dm"
|
||||
#include "code\modules\projectiles\guns\energy\magic.dm"
|
||||
#include "code\modules\projectiles\guns\energy\nuclear.dm"
|
||||
#include "code\modules\projectiles\guns\energy\pulse.dm"
|
||||
#include "code\modules\projectiles\guns\energy\rifle.dm"
|
||||
@@ -1804,6 +1855,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"
|
||||
@@ -1924,11 +1976,15 @@
|
||||
#include "code\modules\shuttles\shuttles_multi.dm"
|
||||
#include "code\modules\spells\artifacts.dm"
|
||||
#include "code\modules\spells\construct_spells.dm"
|
||||
#include "code\modules\spells\contracts.dm"
|
||||
#include "code\modules\spells\monster_manual.dm"
|
||||
#include "code\modules\spells\no_clothes.dm"
|
||||
#include "code\modules\spells\spell_code.dm"
|
||||
#include "code\modules\spells\spell_projectile.dm"
|
||||
#include "code\modules\spells\spell_verb.dm"
|
||||
#include "code\modules\spells\spellbook.dm"
|
||||
#include "code\modules\spells\spells.dm"
|
||||
#include "code\modules\spells\storage.dm"
|
||||
#include "code\modules\spells\aoe_turf\aoe_turf.dm"
|
||||
#include "code\modules\spells\aoe_turf\blink.dm"
|
||||
#include "code\modules\spells\aoe_turf\charge.dm"
|
||||
@@ -1938,23 +1994,48 @@
|
||||
#include "code\modules\spells\aoe_turf\summons.dm"
|
||||
#include "code\modules\spells\aoe_turf\conjure\conjure.dm"
|
||||
#include "code\modules\spells\aoe_turf\conjure\construct.dm"
|
||||
#include "code\modules\spells\aoe_turf\conjure\druidic_spells.dm"
|
||||
#include "code\modules\spells\aoe_turf\conjure\forcewall.dm"
|
||||
#include "code\modules\spells\aoe_turf\conjure\grove.dm"
|
||||
#include "code\modules\spells\general\area_teleport.dm"
|
||||
#include "code\modules\spells\general\contract_spells.dm"
|
||||
#include "code\modules\spells\general\mark_recall.dm"
|
||||
#include "code\modules\spells\general\return_master.dm"
|
||||
#include "code\modules\spells\general\rune_write.dm"
|
||||
#include "code\modules\spells\hand\hand.dm"
|
||||
#include "code\modules\spells\hand\hand_item.dm"
|
||||
#include "code\modules\spells\spellbook\battlemage.dm"
|
||||
#include "code\modules\spells\spellbook\cleric.dm"
|
||||
#include "code\modules\spells\spellbook\druid.dm"
|
||||
#include "code\modules\spells\spellbook\necromancer.dm"
|
||||
#include "code\modules\spells\spellbook\spatial.dm"
|
||||
#include "code\modules\spells\spellbook\standard.dm"
|
||||
#include "code\modules\spells\spellbook\student.dm"
|
||||
#include "code\modules\spells\targeted\cleric_spells.dm"
|
||||
#include "code\modules\spells\targeted\entangle.dm"
|
||||
#include "code\modules\spells\targeted\ethereal_jaunt.dm"
|
||||
#include "code\modules\spells\targeted\genetic.dm"
|
||||
#include "code\modules\spells\targeted\harvest.dm"
|
||||
#include "code\modules\spells\targeted\mind_transfer.dm"
|
||||
#include "code\modules\spells\targeted\necromancer_spells.dm"
|
||||
#include "code\modules\spells\targeted\shapeshift.dm"
|
||||
#include "code\modules\spells\targeted\shift.dm"
|
||||
#include "code\modules\spells\targeted\subjugate.dm"
|
||||
#include "code\modules\spells\targeted\swap.dm"
|
||||
#include "code\modules\spells\targeted\targeted.dm"
|
||||
#include "code\modules\spells\targeted\torment.dm"
|
||||
#include "code\modules\spells\targeted\equip\equip.dm"
|
||||
#include "code\modules\spells\targeted\equip\holy_relic.dm"
|
||||
#include "code\modules\spells\targeted\equip\horsemask.dm"
|
||||
#include "code\modules\spells\targeted\equip\remove_horsemask.dm"
|
||||
#include "code\modules\spells\targeted\equip\party_hardy.dm"
|
||||
#include "code\modules\spells\targeted\equip\seed.dm"
|
||||
#include "code\modules\spells\targeted\equip\shield.dm"
|
||||
#include "code\modules\spells\targeted\projectile\dumbfire.dm"
|
||||
#include "code\modules\spells\targeted\projectile\fireball.dm"
|
||||
#include "code\modules\spells\targeted\projectile\magic_missile.dm"
|
||||
#include "code\modules\spells\targeted\projectile\passage.dm"
|
||||
#include "code\modules\spells\targeted\projectile\projectile.dm"
|
||||
#include "code\modules\spells\targeted\projectile\stuncuff.dm"
|
||||
#include "code\modules\supermatter\setup_supermatter.dm"
|
||||
#include "code\modules\supermatter\supermatter.dm"
|
||||
#include "code\modules\surgery\_defines.dm"
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -229,7 +229,7 @@ Thus, the two variables affect pump operation are set in New():
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
return 1
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
if(do_after(user, 40))
|
||||
if(do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -358,7 +358,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
@@ -290,7 +290,7 @@
|
||||
user << "<span class='danger'>\The [WT] must be turned on!</span>"
|
||||
else if (WT.remove_fuel(0,user))
|
||||
user << "<span class='notice'>Now welding \the [src].</span>"
|
||||
if(do_after(user, 20))
|
||||
if(do_after(user, 20, act_target = src))
|
||||
if(!src || !WT.isOn()) return
|
||||
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
if(!welded)
|
||||
|
||||
@@ -315,7 +315,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
return 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
|
||||
user << "<span class='notice'>You begin to unfasten \the [src]...</span>"
|
||||
if (do_after(user, 40))
|
||||
if (do_after(user, 40, act_target = src))
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] unfastens \the [src].</span>", \
|
||||
"<span class='notice'>You have unfastened \the [src].</span>", \
|
||||
|
||||
+4
-4
@@ -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, no_update = TRUE) // 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, no_update = TRUE)
|
||||
else
|
||||
icon_state = "1"
|
||||
set_light(3, FIRE_LIGHT_1)
|
||||
set_light(3, FIRE_LIGHT_1, no_update = TRUE)
|
||||
|
||||
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
|
||||
#undef FIRE_LIGHT_3
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
// 1 will enable set background. 0 will disable set background.
|
||||
|
||||
@@ -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;
|
||||
+80
-22
@@ -1,34 +1,92 @@
|
||||
//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 2 // 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
|
||||
|
||||
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
|
||||
//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 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 ;
|
||||
#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)
|
||||
#define LIGHT_COLOR_PURPLE "#A97FAA" //Soft purple. rgb(169, 127, 170)
|
||||
|
||||
//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
|
||||
|
||||
// Some angle presets for directional lighting.
|
||||
#define LIGHT_OMNI null
|
||||
#define LIGHT_SEMI 180
|
||||
#define LIGHT_WIDE 90
|
||||
#define LIGHT_NARROW 45
|
||||
|
||||
// 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
|
||||
// The time (in hours based on worldtime2hours()) that various actions trigger
|
||||
#define MORNING_LIGHT_RESET 7 // 7am or 07:00 - lighting restores to normal in morning
|
||||
#define NIGHT_LIGHT_ACTIVE 18 // 6pm or 18:00 - night lighting mode activates
|
||||
|
||||
// Some brightness/range defines for objects.
|
||||
#define L_WALLMOUNT_POWER 0.4
|
||||
#define L_WALLMOUNT_RANGE 2
|
||||
#define L_WALLMOUNT_HI_POWER 1 // For red/delta alert on fire alarms.
|
||||
#define L_WALLMOUNT_HI_RANGE 4
|
||||
// This controls by how much console sprites are dimmed before being overlayed.
|
||||
#define HOLOSCREEN_ADDITION_FACTOR 1
|
||||
#define HOLOSCREEN_MULTIPLICATION_FACTOR 0.5
|
||||
#define HOLOSCREEN_ADDITION_OPACITY 0.8
|
||||
#define HOLOSCREEN_MULTIPLICATION_OPACITY 1
|
||||
|
||||
// Just so we can avoid unneeded proc calls when profiling is disabled.
|
||||
#define L_PROF(O,T) if (lighting_profiling) {lprof_write(O,T);}
|
||||
|
||||
@@ -68,14 +68,6 @@ var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret
|
||||
#define STAGE_FIVE 9
|
||||
#define STAGE_SUPER 11
|
||||
|
||||
// computer3 error codes, move lower in the file when it passes dev -Sayu
|
||||
#define PROG_CRASH 0x1 // Generic crash.
|
||||
#define MISSING_PERIPHERAL 0x2 // Missing hardware.
|
||||
#define BUSTED_ASS_COMPUTER 0x4 // Self-perpetuating error. BAC will continue to crash forever.
|
||||
#define MISSING_PROGRAM 0x8 // Some files try to automatically launch a program. This is that failing.
|
||||
#define FILE_DRM 0x10 // Some files want to not be copied/moved. This is them complaining that you tried.
|
||||
#define NETWORK_FAILURE 0x20
|
||||
|
||||
// NanoUI flags
|
||||
#define STATUS_INTERACTIVE 2 // GREEN Visability
|
||||
#define STATUS_UPDATE 1 // ORANGE Visability
|
||||
@@ -104,3 +96,17 @@ var/list/restricted_camera_networks = list(NETWORK_ERT,NETWORK_MERCENARY,"Secret
|
||||
#define ATMOS_DEFAULT_VOLUME_FILTER 200 // L.
|
||||
#define ATMOS_DEFAULT_VOLUME_MIXER 200 // L.
|
||||
#define ATMOS_DEFAULT_VOLUME_PIPE 70 // L.
|
||||
|
||||
|
||||
// Misc process flags.
|
||||
#define M_PROCESSES 0x1
|
||||
#define M_USES_POWER 0x2
|
||||
|
||||
// If this is returned from a machine's process() proc, the machine will stop processing but
|
||||
// will continue to have power calculations done.
|
||||
#define M_NO_PROCESS 27
|
||||
|
||||
// This controls how much power the AME generates per unit of fuel.
|
||||
// Assuming 100% efficency, use this equation to figure out power output.
|
||||
// power_generated = (fuel**2) * AM_POWER_FACTOR
|
||||
#define AM_POWER_FACTOR 50000
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#define ORE_URANIUM "uranium"
|
||||
#define ORE_IRON "iron"
|
||||
#define ORE_COAL "coal"
|
||||
#define ORE_SAND "sand"
|
||||
#define ORE_PHORON "phoron"
|
||||
#define ORE_SILVER "silver"
|
||||
#define ORE_GOLD "gold"
|
||||
#define ORE_DIAMOND "diamond"
|
||||
#define ORE_PLATINUM "platinum"
|
||||
#define ORE_HYDROGEN "mhydrogen"
|
||||
+39
-2
@@ -48,6 +48,10 @@
|
||||
#define SHOW_TYPING 0x4000
|
||||
#define CHAT_NOICONS 0x8000
|
||||
|
||||
#define PARALLAX_SPACE 0x1
|
||||
#define PARALLAX_DUST 0x2
|
||||
#define PROGRESS_BARS 0x4
|
||||
|
||||
#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
|
||||
@@ -200,10 +204,11 @@
|
||||
#define NTNETSPEED_DOS_AMPLIFICATION 5 // Multiplier for Denial of Service program. Resulting load on NTNet relay is this multiplied by NTNETSPEED of the device
|
||||
|
||||
// Program bitflags
|
||||
#define PROGRAM_ALL 7
|
||||
#define PROGRAM_ALL 15
|
||||
#define PROGRAM_CONSOLE 1
|
||||
#define PROGRAM_LAPTOP 2
|
||||
#define PROGRAM_TABLET 4
|
||||
#define PROGRAM_TELESCREEN 8
|
||||
|
||||
#define PROGRAM_STATE_KILLED 0
|
||||
#define PROGRAM_STATE_BACKGROUND 1
|
||||
@@ -259,4 +264,36 @@
|
||||
|
||||
#define LAYER_TABLE 2.8
|
||||
#define LAYER_UNDER_TABLE 2.79
|
||||
#define LAYER_ABOVE_TABLE 2.81
|
||||
#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()
|
||||
|
||||
// Effect Systems.
|
||||
#define EFFECT_CONTINUE 0 // Keep processing.
|
||||
#define EFFECT_HALT 1 // Stop processing, but don't qdel.
|
||||
#define EFFECT_DESTROY 2 // qdel.
|
||||
|
||||
// Performance bullshit.
|
||||
|
||||
//supposedly the fastest way to do this according to https://gist.github.com/Giacom/be635398926bb463b42a
|
||||
#define RANGE_TURFS(RADIUS, CENTER) \
|
||||
block( \
|
||||
locate(max(CENTER.x-(RADIUS),1), max(CENTER.y-(RADIUS),1), CENTER.z), \
|
||||
locate(min(CENTER.x+(RADIUS),world.maxx), min(CENTER.y+(RADIUS),world.maxy), CENTER.z) \
|
||||
)
|
||||
|
||||
#define get_turf(A) (get_step(A, 0))
|
||||
#define QDELETED(TARGET) (!TARGET || TARGET.gcDestroyed)
|
||||
#define QDEL_NULL(item) qdel(item); item = null
|
||||
// Shim until addtimer is merged or I figure out if it is safe to use scheduler for this.
|
||||
#define QDEL_IN(OBJ, TIME) spawn(TIME) qdel(OBJ)
|
||||
|
||||
//Recipe type defines. Used to determine what machine makes them
|
||||
#define MICROWAVE 0x1
|
||||
#define FRYER 0x2
|
||||
#define OVEN 0x4
|
||||
#define CANDYMAKER 0x8
|
||||
#define CEREALMAKER 0x10
|
||||
|
||||
@@ -16,3 +16,19 @@
|
||||
// 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; \
|
||||
}
|
||||
|
||||
#define PSCHED_CHECK_TICK (world.tick_usage > 100 || (world.tick_usage - tick_start) > tick_allowance)
|
||||
|
||||
+128
-98
@@ -1,125 +1,155 @@
|
||||
//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"
|
||||
|
||||
if (!check_rights(R_DEBUG))
|
||||
return
|
||||
|
||||
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 += "<b>Stored Variables for Pooling for this type</b><br>"
|
||||
for(var/key in pooledvariables[type])
|
||||
if(pooledvariables[type][key])
|
||||
L += "<br>[key] = [pooledvariables[type][key]]"
|
||||
else
|
||||
L += "<br>[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
|
||||
|
||||
@@ -631,7 +631,6 @@ proc/ColorTone(rgb, tone)
|
||||
/*
|
||||
Get flat icon by DarkCampainger. As it says on the tin, will return an icon with all the overlays
|
||||
as a single icon. Useful for when you want to manipulate an icon via the above as overlays are not normally included.
|
||||
The _flatIcons list is a cache for generated icon files.
|
||||
*/
|
||||
|
||||
proc // Creates a single icon from a given /atom or /image. Only the first argument is required.
|
||||
|
||||
@@ -127,4 +127,12 @@
|
||||
return (val & (val-1)) == 0
|
||||
|
||||
/proc/RoundUpToPowerOfTwo(var/val)
|
||||
return 2 ** -round(-log(2,val))
|
||||
return 2 ** -round(-log(2,val))
|
||||
|
||||
|
||||
//Written by Lohikar
|
||||
//Returns the cube root of the input number
|
||||
/proc/cubert(var/num, var/iterations = 10)
|
||||
. = num
|
||||
for (var/i = 0, i < iterations, i++)
|
||||
. = (1/3) * (num/(.**2)+2*.)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// Factor/Opacity values are defined in __defines\lighting.dm
|
||||
|
||||
/proc/holographic_overlay(obj/target, icon, icon_state)
|
||||
var/image/multiply = make_screen_overlay(icon, icon_state)
|
||||
multiply.blend_mode = BLEND_MULTIPLY
|
||||
multiply.color = list(
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
HOLOSCREEN_MULTIPLICATION_FACTOR, HOLOSCREEN_MULTIPLICATION_FACTOR, HOLOSCREEN_MULTIPLICATION_FACTOR, HOLOSCREEN_MULTIPLICATION_OPACITY
|
||||
)
|
||||
target.overlays += multiply
|
||||
var/image/overlay = make_screen_overlay(icon, icon_state)
|
||||
overlay.blend_mode = BLEND_ADD
|
||||
overlay.color = list(
|
||||
HOLOSCREEN_ADDITION_FACTOR, 0, 0, 0,
|
||||
0, HOLOSCREEN_ADDITION_FACTOR, 0, 0,
|
||||
0, 0, HOLOSCREEN_ADDITION_FACTOR, 0,
|
||||
0, 0, 0, HOLOSCREEN_ADDITION_OPACITY
|
||||
)
|
||||
target.overlays += overlay
|
||||
|
||||
/proc/make_screen_overlay(icon, icon_state, brightness_factor = null)
|
||||
var/image/overlay = image(icon, icon_state)
|
||||
overlay.layer = LIGHTING_LAYER + 0.1
|
||||
if (brightness_factor)
|
||||
overlay.color = list(
|
||||
brightness_factor, 0, 0, 0,
|
||||
0, brightness_factor, 0, 0,
|
||||
0, 0, brightness_factor, 0,
|
||||
0, 0, 0, 1
|
||||
)
|
||||
return overlay
|
||||
@@ -180,6 +180,28 @@
|
||||
if(start)
|
||||
return findtextEx(text, suffix, start, null)
|
||||
|
||||
|
||||
//Parses a string into a list
|
||||
/proc/dd_text2List(text, separator)
|
||||
var/textlength = lentext(text)
|
||||
var/separatorlength = lentext(separator)
|
||||
var/list/textList = new /list()
|
||||
var/searchPosition = 1
|
||||
var/findPosition = 1
|
||||
var/buggyText
|
||||
while (1) // Loop forever.
|
||||
findPosition = findtextEx(text, separator, searchPosition, 0)
|
||||
buggyText = copytext(text, searchPosition, findPosition) // Everything from searchPosition to findPosition goes into a list element.
|
||||
textList += "[buggyText]" // Working around weird problem where "text" != "text" after this copytext().
|
||||
|
||||
searchPosition = findPosition + separatorlength // Skip over separator.
|
||||
if (findPosition == 0) // Didn't find anything at end of string so stop here.
|
||||
return textList
|
||||
else
|
||||
if (searchPosition > textlength) // Found separator at very end of string.
|
||||
textList += "" // So add empty element
|
||||
|
||||
|
||||
/*
|
||||
* Text modification
|
||||
*/
|
||||
|
||||
@@ -10,10 +10,12 @@ proc/worldtime2text(time = world.time, timeshift = 1)
|
||||
if(!roundstart_hour) roundstart_hour = rand(0, 23)
|
||||
return timeshift ? time2text(time+(36000*roundstart_hour), "hh:mm") : time2text(time, "hh:mm")
|
||||
|
||||
proc/worldtime2ticks(time = world.time)
|
||||
if(!roundstart_hour)
|
||||
/proc/worldtime2hours()
|
||||
if (!roundstart_hour)
|
||||
worldtime2text()
|
||||
return ((roundstart_hour * 60 MINUTES) + time) % TICKS_IN_DAY
|
||||
. = (world.timeofday / (60 MINUTES)) + roundstart_hour
|
||||
if (. > 24)
|
||||
. -= 24
|
||||
|
||||
proc/worlddate2text()
|
||||
return num2text(game_year) + "-" + time2text(world.timeofday, "MM-DD")
|
||||
|
||||
+101
-44
@@ -646,45 +646,109 @@ proc/GaussRandRound(var/sigma,var/roundto)
|
||||
|
||||
else return get_step(ref, base_dir)
|
||||
|
||||
/proc/do_mob(var/mob/user, var/mob/target, var/delay = 30, var/numticks = 5, var/needhand = 1) //This is quite an ugly solution but i refuse to use the old request system.
|
||||
if(!user || !target) return 0
|
||||
if(numticks == 0) return 0
|
||||
|
||||
var/delayfraction = round(delay/numticks)
|
||||
var/original_user_loc = user.loc
|
||||
var/original_target_loc = target.loc
|
||||
/proc/do_mob(mob/user , mob/target, delay = 30, numticks = 10, needhand = TRUE, display_progress = TRUE) //This is quite an ugly solution but i refuse to use the old request system.
|
||||
if(!user || !target)
|
||||
return 0
|
||||
var/user_loc = user.loc
|
||||
var/target_loc = target.loc
|
||||
var/holding = user.get_active_hand()
|
||||
|
||||
for(var/i = 0, i<numticks, i++)
|
||||
var/delayfraction = round(delay/numticks)
|
||||
var/image/progbar
|
||||
if(user && user.client && (user.client.prefs.parallax_togs & PROGRESS_BARS) && display_progress)
|
||||
if(!progbar)
|
||||
progbar = image(icon = 'icons/effects/doafter_icon.dmi', loc = target, icon_state = "prog_bar_0")
|
||||
progbar.layer = 21
|
||||
progbar.pixel_z = WORLD_ICON_SIZE
|
||||
progbar.appearance_flags = RESET_TRANSFORM
|
||||
for (var/i = 1 to numticks)
|
||||
if(user && user.client && (user.client.prefs.parallax_togs & PROGRESS_BARS) && progbar && display_progress)
|
||||
progbar.icon_state = "prog_bar_[round(((i / numticks) * 100), 10)]"
|
||||
user.client.images |= progbar
|
||||
sleep(delayfraction)
|
||||
|
||||
if(!user || user.stat || user.weakened || user.stunned || user.loc != original_user_loc)
|
||||
if(!user || !target)
|
||||
if(progbar)
|
||||
progbar.icon_state = "prog_bar_stopped"
|
||||
spawn(2)
|
||||
if(user && user.client)
|
||||
user.client.images -= progbar
|
||||
if(progbar)
|
||||
progbar.loc = null
|
||||
return 0
|
||||
if(!target || target.loc != original_target_loc)
|
||||
if (user.loc != user_loc || target.loc != target_loc || (needhand && user.get_active_hand() != holding) || user.stat || user.weakened || user.stunned)
|
||||
if(progbar)
|
||||
progbar.icon_state = "prog_bar_stopped"
|
||||
spawn(2)
|
||||
if(user && user.client)
|
||||
user.client.images -= progbar
|
||||
if(progbar)
|
||||
progbar.loc = null
|
||||
return 0
|
||||
if(needhand && !(user.get_active_hand() == holding)) //Sometimes you don't want the user to have to keep their active hand
|
||||
return 0
|
||||
|
||||
if(user && user.client)
|
||||
user.client.images -= progbar
|
||||
if(progbar)
|
||||
progbar.loc = null
|
||||
return 1
|
||||
|
||||
/proc/do_after(var/mob/user as mob, delay as num, var/numticks = 5, var/needhand = 1)
|
||||
/proc/do_after(mob/user as mob, delay as num, numticks = 10, needhand = TRUE, atom/movable/act_target = null, use_user_turf = FALSE, display_progress = TRUE)
|
||||
if(!user || isnull(user))
|
||||
return 0
|
||||
if(numticks == 0)
|
||||
return 0
|
||||
|
||||
if (!act_target)
|
||||
act_target = user
|
||||
|
||||
var/delayfraction = round(delay/numticks)
|
||||
var/original_loc = user.loc
|
||||
var/Location
|
||||
if(use_user_turf) //When this is true, do_after() will check whether the user's turf has changed, rather than the user's loc.
|
||||
Location = get_turf(user)
|
||||
else
|
||||
Location = user.loc
|
||||
var/holding = user.get_active_hand()
|
||||
|
||||
for(var/i = 0, i<numticks, i++)
|
||||
var/image/progbar
|
||||
if(user && user.client && (user.client.prefs.parallax_togs & PROGRESS_BARS) && act_target && display_progress)
|
||||
if(!progbar)
|
||||
progbar = image(icon = 'icons/effects/doafter_icon.dmi', loc = act_target, icon_state = "prog_bar_0")
|
||||
progbar.pixel_z = WORLD_ICON_SIZE
|
||||
progbar.layer = 21
|
||||
progbar.appearance_flags = RESET_COLOR | RESET_TRANSFORM
|
||||
for (var/i = 1 to numticks)
|
||||
if(user && user.client && (user.client.prefs.parallax_togs & PROGRESS_BARS) && act_target && display_progress)
|
||||
if(!progbar)
|
||||
progbar = image(icon = 'icons/effects/doafter_icon.dmi', loc = act_target, icon_state = "prog_bar_0")
|
||||
progbar.pixel_z = WORLD_ICON_SIZE
|
||||
progbar.layer = 21
|
||||
progbar.appearance_flags = RESET_COLOR | RESET_TRANSFORM
|
||||
progbar.icon_state = "prog_bar_[round(((i / numticks) * 100), 10)]"
|
||||
user.client.images |= progbar
|
||||
sleep(delayfraction)
|
||||
|
||||
if(!user || user.stat || user.weakened || user.stunned || user.loc != original_loc)
|
||||
var/user_loc_to_check
|
||||
if(use_user_turf)
|
||||
user_loc_to_check = get_turf(user)
|
||||
else
|
||||
user_loc_to_check = user.loc
|
||||
if (!user || user.stat || user.weakened || user.stunned || !(user_loc_to_check == Location))
|
||||
if(progbar)
|
||||
progbar.icon_state = "prog_bar_stopped"
|
||||
spawn(2)
|
||||
if(user && user.client)
|
||||
user.client.images -= progbar
|
||||
if(progbar)
|
||||
progbar.loc = null
|
||||
return 0
|
||||
if(needhand && !(user.get_active_hand() == holding)) //Sometimes you don't want the user to have to keep their active hand
|
||||
if(progbar)
|
||||
progbar.icon_state = "prog_bar_stopped"
|
||||
spawn(2)
|
||||
if(user && user.client)
|
||||
user.client.images -= progbar
|
||||
if(progbar)
|
||||
progbar.loc = null
|
||||
return 0
|
||||
|
||||
if(user && user.client)
|
||||
user.client.images -= progbar
|
||||
if(progbar)
|
||||
progbar.loc = null
|
||||
return 1
|
||||
|
||||
//Takes: Anything that could possibly have variables and a varname to check.
|
||||
@@ -849,12 +913,6 @@ proc/GaussRandRound(var/sigma,var/roundto)
|
||||
if(!istype(M,/mob) || istype(M, /mob/eye)) continue // If we need to check for more mobs, I'll add a variable
|
||||
M.loc = X
|
||||
|
||||
// var/area/AR = X.loc
|
||||
|
||||
// if(AR.lighting_use_dynamic) //TODO: rewrite this code so it's not messed by lighting ~Carn
|
||||
// X.opacity = !X.opacity
|
||||
// X.SetOpacity(!X.opacity)
|
||||
|
||||
toupdate += X
|
||||
|
||||
if(turftoleave)
|
||||
@@ -1063,13 +1121,6 @@ proc/get_mob_with_client_list()
|
||||
else if (zone == "r_foot") return "right foot"
|
||||
else return zone
|
||||
|
||||
//gets the turf the atom is located in (or itself, if it is a turf).
|
||||
//returns null if the atom is not in a turf.
|
||||
/proc/get_turf(atom/A)
|
||||
if(!istype(A)) return
|
||||
for(A, A && !isturf(A), A=A.loc);
|
||||
return A
|
||||
|
||||
/proc/get(atom/loc, type)
|
||||
while(loc)
|
||||
if(istype(loc, type))
|
||||
@@ -1364,15 +1415,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 +1438,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
|
||||
|
||||
@@ -48,3 +48,5 @@
|
||||
#define to_file(file_entry, file_content) file_entry << file_content
|
||||
#define show_browser(target, browser_content, browser_name) target << browse(browser_content, browser_name)
|
||||
#define send_rsc(target, rsc_content, rsc_name) target << browse_rsc(rsc_content, rsc_name)
|
||||
|
||||
#define CanInteract(user, state) (CanUseTopic(user, state) == STATUS_INTERACTIVE)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
// 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
|
||||
var/parallax_speed = 0
|
||||
|
||||
/obj/screen/plane_master
|
||||
appearance_flags = PLANE_MASTER
|
||||
screen_loc = "CENTER,CENTER"
|
||||
|
||||
/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 = new /obj/screen/plane_master/parallax_master
|
||||
if(!C.parallax_spacemaster)
|
||||
C.parallax_spacemaster = new /obj/screen/plane_master/parallax_spacemaster
|
||||
if(!C.parallax_dustmaster)
|
||||
C.parallax_dustmaster = new /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 = new /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 = new /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 = new /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 = new /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
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
/obj/screen/Destroy()
|
||||
master = null
|
||||
screen_loc = null
|
||||
return ..()
|
||||
|
||||
/obj/screen/text
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
/obj/screen/movable/spell_master/proc/silence_spells(var/amount)
|
||||
for(var/obj/screen/spell/spell in spell_objects)
|
||||
spell.spell.silenced = amount
|
||||
spell.spell.process()
|
||||
spell.update_charge(1)
|
||||
|
||||
/obj/screen/movable/spell_master/proc/update_spells(forced = 0, mob/user)
|
||||
|
||||
@@ -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
|
||||
@@ -110,9 +110,7 @@
|
||||
M.Stun(power)
|
||||
M.stuttering = max(M.stuttering, power)
|
||||
|
||||
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
|
||||
s.set_up(5, 1, M)
|
||||
s.start()
|
||||
spark(M, 5, alldirs)
|
||||
|
||||
if(prob(stunprob) && powerlevel >= 8)
|
||||
M.adjustFireLoss(powerlevel * rand(6,10))
|
||||
|
||||
@@ -74,13 +74,19 @@ var/const/tk_maxrange = 15
|
||||
var/atom/movable/focus = null
|
||||
var/mob/living/host = null
|
||||
|
||||
/obj/item/tk_grab/Destroy()
|
||||
if (host)
|
||||
host.remove_from_mob(src)
|
||||
host = null
|
||||
focus = null
|
||||
return ..()
|
||||
|
||||
/obj/item/tk_grab/dropped(mob/user as mob)
|
||||
if(focus && user && loc != user && loc != user.loc) // drop_item() gets called when you tk-attack a table/closet with an item
|
||||
if(focus.Adjacent(loc))
|
||||
focus.loc = loc
|
||||
loc = null
|
||||
spawn(1)
|
||||
qdel(src)
|
||||
QDEL_IN(src, 1)
|
||||
return
|
||||
|
||||
//stops TK grabs being equipped anywhere but into hands
|
||||
@@ -157,7 +163,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 = new(locate(focus.x,focus.y,focus.z))
|
||||
O.name = "sparkles"
|
||||
O.anchored = 1
|
||||
O.density = 0
|
||||
@@ -166,9 +172,7 @@ var/const/tk_maxrange = 15
|
||||
O.icon = 'icons/effects/effects.dmi'
|
||||
O.icon_state = "nothing"
|
||||
flick("empdisable",O)
|
||||
spawn(5)
|
||||
qdel(O)
|
||||
return
|
||||
QDEL_IN(O, 5)
|
||||
|
||||
/obj/item/tk_grab/update_icon()
|
||||
overlays.Cut()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#define STAGE_IDLE 0
|
||||
#define STAGE_EFFECT 1
|
||||
#define STAGE_SUBEFFECT 2
|
||||
|
||||
var/datum/controller/process/effects/effect_master
|
||||
|
||||
/var/list/datum/effect_system/effects_objects = list() // The effect-spawning objects. Shouldn't be many of these.
|
||||
/var/list/obj/visual_effect/effects_visuals = list() // The visible component of an effect. May be created without an effect object.
|
||||
|
||||
/datum/controller/process/effects
|
||||
var/tmp/list/processing_effects = list()
|
||||
var/tmp/list/processing_visuals = list()
|
||||
var/tmp/stage = STAGE_IDLE
|
||||
|
||||
/datum/controller/process/effects/setup()
|
||||
effect_master = src
|
||||
name = "effects"
|
||||
schedule_interval = 2
|
||||
tick_allowance = 15
|
||||
|
||||
/datum/controller/process/effects/doWork()
|
||||
if (stage == STAGE_IDLE)
|
||||
// Start a new work cycle.
|
||||
processing_effects = effects_objects
|
||||
effects_objects = list()
|
||||
stage = STAGE_EFFECT
|
||||
|
||||
while (processing_effects.len)
|
||||
var/datum/effect_system/E = processing_effects[processing_effects.len]
|
||||
processing_effects.len--
|
||||
|
||||
if (!E || E.gcDestroyed)
|
||||
continue
|
||||
|
||||
switch (E.process())
|
||||
if (EFFECT_CONTINUE)
|
||||
effects_objects += E
|
||||
|
||||
if (EFFECT_DESTROY)
|
||||
returnToPool(E)
|
||||
|
||||
F_SCHECK
|
||||
|
||||
if (stage == STAGE_EFFECT)
|
||||
processing_visuals = effects_visuals
|
||||
effects_visuals = list()
|
||||
stage = STAGE_SUBEFFECT
|
||||
|
||||
while (processing_visuals.len)
|
||||
var/obj/visual_effect/V = processing_visuals[processing_visuals.len]
|
||||
processing_visuals.len--
|
||||
|
||||
if (!V || V.gcDestroyed)
|
||||
effects_visuals -= V
|
||||
continue
|
||||
|
||||
switch (V.tick())
|
||||
if (EFFECT_CONTINUE)
|
||||
effects_visuals += V
|
||||
|
||||
if (EFFECT_DESTROY)
|
||||
effects_visuals -= V
|
||||
V.end()
|
||||
returnToPool(V)
|
||||
|
||||
F_SCHECK
|
||||
|
||||
stage = STAGE_IDLE
|
||||
|
||||
// We're done.
|
||||
if (!processing_effects.len && !processing_visuals.len && !effects_objects.len && !effects_visuals.len)
|
||||
disable()
|
||||
|
||||
/datum/controller/process/effects/proc/queue(var/datum/effect_system/E)
|
||||
if (!E || E.gcDestroyed)
|
||||
return
|
||||
|
||||
effects_objects += E
|
||||
enable()
|
||||
|
||||
/datum/controller/process/effects/proc/queue_simple(var/obj/visual_effect/V)
|
||||
if (!V || V.gcDestroyed)
|
||||
return
|
||||
|
||||
effects_visuals += V
|
||||
enable()
|
||||
|
||||
/datum/controller/process/effects/statProcess()
|
||||
..()
|
||||
stat(null, "Effect process is [disabled ? "sleeping" : "processing"].")
|
||||
stat(null, "[effects_objects.len] effects queued, [processing_effects.len] processing")
|
||||
stat(null, "[effects_visuals.len] visuals queued, [processing_visuals.len] processing")
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -127,11 +127,6 @@ world/loop_checks = 0
|
||||
stat(null, "[garbage_collect ? "On" : "Off"], [destroyed.len] queued")
|
||||
stat(null, "Dels: [total_dels], [soft_dels] soft, [hard_dels] hard, [tick_dels] last run")
|
||||
|
||||
|
||||
// Tests if an atom has been deleted.
|
||||
/proc/deleted(atom/A)
|
||||
return !A || !isnull(A.gcDestroyed)
|
||||
|
||||
// Should be treated as a replacement for the 'del' keyword.
|
||||
// Datums passed to this will be given a chance to clean up references to allow the GC to collect them.
|
||||
/proc/qdel(var/datum/A)
|
||||
@@ -151,13 +146,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)
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
log_access("AFK: [key_name(C)]")
|
||||
C << "<SPAN CLASS='warning'>You have been inactive for more than [config.kick_inactive] minute\s and have been disconnected.</SPAN>"
|
||||
del(C) // Don't qdel, cannot override finalize_qdel behaviour for clients.
|
||||
SCHECK
|
||||
F_SCHECK
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/var/global/datum/controller/process/law/corp_regs
|
||||
|
||||
/datum/controller/process/law
|
||||
var/list/laws = list() // All laws
|
||||
|
||||
var/list/low_severity = list()
|
||||
var/list/med_severity = list()
|
||||
var/list/high_severity = list()
|
||||
|
||||
/datum/controller/process/law/New()
|
||||
corp_regs = src
|
||||
|
||||
..()
|
||||
|
||||
/datum/controller/process/law/setup()
|
||||
name = "Law"
|
||||
schedule_interval = 100
|
||||
|
||||
for( var/L in subtypesof( /datum/law/low_severity ))
|
||||
low_severity += new L
|
||||
|
||||
for( var/L in subtypesof( /datum/law/med_severity ))
|
||||
med_severity += new L
|
||||
|
||||
for( var/L in subtypesof( /datum/law/high_severity ))
|
||||
high_severity += new L
|
||||
|
||||
laws = low_severity + med_severity + high_severity
|
||||
@@ -0,0 +1,75 @@
|
||||
#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
|
||||
|
||||
/datum/controller/process/lighting/setup()
|
||||
name = "lighting"
|
||||
lighting_process = src
|
||||
|
||||
/datum/controller/process/lighting/statProcess()
|
||||
..()
|
||||
stat(null, "Server tick usage is [world.tick_usage].")
|
||||
stat(null, "[all_lighting_overlays.len] overlays ([all_lighting_corners.len] corners)")
|
||||
stat(null, "Lights: [lighting_update_lights.len] queued")
|
||||
stat(null, "Corners: [lighting_update_corners.len] queued")
|
||||
stat(null, "Overlays: [lighting_update_overlays.len] queued")
|
||||
|
||||
/datum/controller/process/lighting/doWork()
|
||||
var/list/curr_lights = lighting_update_lights
|
||||
var/list/curr_corners = lighting_update_corners
|
||||
var/list/curr_overlays = lighting_update_overlays
|
||||
|
||||
while (curr_lights.len)
|
||||
var/datum/light_source/L = curr_lights[curr_lights.len]
|
||||
curr_lights.len--
|
||||
|
||||
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 = FALSE
|
||||
L.force_update = FALSE
|
||||
L.needs_update = FALSE
|
||||
|
||||
F_SCHECK
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
#undef STAGE_NONE
|
||||
#undef STAGE_SOURCE
|
||||
#undef STAGE_CORNER
|
||||
#undef STAGE_OVERLAY
|
||||
@@ -1,67 +1,149 @@
|
||||
/var/global/machinery_sort_required = 0
|
||||
/var/global/machinery_sort_required = 0
|
||||
var/global/list/power_using_machines = list()
|
||||
var/global/list/ticking_machines = list()
|
||||
|
||||
#define STAGE_NONE 0
|
||||
#define STAGE_MACHINERY_PROCESS 1
|
||||
#define STAGE_MACHINERY_POWER 2
|
||||
#define STAGE_POWERNET 3
|
||||
#define STAGE_POWERSINK 4
|
||||
#define STAGE_PIPENET 5
|
||||
|
||||
/proc/add_machine(var/obj/machinery/M)
|
||||
if (QDELETED(M))
|
||||
return
|
||||
|
||||
var/type = M.get_process_type()
|
||||
if (type)
|
||||
machines += M
|
||||
|
||||
if (type & M_PROCESSES)
|
||||
ticking_machines += M
|
||||
|
||||
if (type & M_USES_POWER)
|
||||
power_using_machines += M
|
||||
|
||||
/proc/remove_machine(var/obj/machinery/M)
|
||||
machines -= M
|
||||
power_using_machines -= M
|
||||
ticking_machines -= M
|
||||
|
||||
/datum/controller/process/machinery
|
||||
var/tmp/list/processing_machinery = list()
|
||||
var/tmp/list/processing_power_users = 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 = ticking_machines.Copy()
|
||||
stage = STAGE_MACHINERY_PROCESS
|
||||
|
||||
// Process machinery.
|
||||
while (processing_machinery.len)
|
||||
var/obj/machinery/M = processing_machinery[processing_machinery.len]
|
||||
processing_machinery.len--
|
||||
|
||||
if (QDELETED(M))
|
||||
remove_machine(M)
|
||||
continue
|
||||
|
||||
switch (M.process())
|
||||
if (PROCESS_KILL)
|
||||
remove_machine(M)
|
||||
|
||||
if (M_NO_PROCESS)
|
||||
ticking_machines -= M
|
||||
|
||||
F_SCHECK
|
||||
|
||||
if (stage == STAGE_MACHINERY_PROCESS)
|
||||
processing_power_users = power_using_machines.Copy()
|
||||
stage = STAGE_MACHINERY_POWER
|
||||
|
||||
while (processing_power_users.len)
|
||||
var/obj/machinery/M = processing_power_users[processing_power_users.len]
|
||||
processing_power_users.len--
|
||||
|
||||
if (QDELETED(M))
|
||||
remove_machine(M)
|
||||
continue
|
||||
|
||||
if (M.use_power)
|
||||
M.auto_use_power()
|
||||
|
||||
F_SCHECK
|
||||
|
||||
if (stage == STAGE_MACHINERY_POWER)
|
||||
processing_powernets = powernets.Copy()
|
||||
stage = STAGE_POWERNET
|
||||
|
||||
while (processing_powernets.len)
|
||||
var/datum/powernet/PN = processing_powernets[processing_powernets.len]
|
||||
processing_powernets.len--
|
||||
|
||||
if (QDELETED(PN))
|
||||
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 (QDELETED(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 (QDELETED(PN))
|
||||
pipe_networks -= PN
|
||||
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] total machines")
|
||||
stat(null, "[ticking_machines.len] ticking machines, [processing_machinery.len] queued")
|
||||
stat(null, "[power_using_machines.len] power-using machines, [processing_power_users.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_PROCESS
|
||||
#undef STAGE_MACHINERY_POWER
|
||||
#undef STAGE_POWERNET
|
||||
#undef STAGE_POWERSINK
|
||||
#undef STAGE_PIPENET
|
||||
|
||||
@@ -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")
|
||||
stat(null, "[mob_list.len] mobs, [queue.len] queued")
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@ var/datum/controller/process/night_lighting/nl_ctrl
|
||||
|
||||
/datum/controller/process/night_lighting/setup()
|
||||
name = "night lighting controller"
|
||||
schedule_interval = 3600 // Every 5 minutes.
|
||||
schedule_interval = 5 MINUTES
|
||||
|
||||
nl_ctrl = src
|
||||
|
||||
@@ -18,34 +18,26 @@ var/datum/controller/process/night_lighting/nl_ctrl
|
||||
// Stop trying to delete processes. Not how it goes.
|
||||
disabled = 1
|
||||
|
||||
|
||||
/datum/controller/process/night_lighting/preStart()
|
||||
|
||||
switch (worldtime2ticks())
|
||||
if (0 to config.nl_finish)
|
||||
deactivate()
|
||||
if (config.nl_start to TICKS_IN_DAY)
|
||||
activate()
|
||||
|
||||
var/time = worldtime2hours()
|
||||
if (time <= config.nl_finish || time >= config.nl_start)
|
||||
activate()
|
||||
else
|
||||
deactivate()
|
||||
|
||||
/datum/controller/process/night_lighting/doWork()
|
||||
if (manual_override) // don't automatically change lighting if it was manually changed in-game
|
||||
return
|
||||
|
||||
switch (worldtime2ticks())
|
||||
if (0 to config.nl_finish)
|
||||
if (isactive)
|
||||
command_announcement.Announce("Good morning. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now return the public hallway lighting levels to normal.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg')
|
||||
deactivate()
|
||||
|
||||
if (config.nl_start to TICKS_IN_DAY)
|
||||
if (!isactive)
|
||||
command_announcement.Announce("Good evening. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now dim lighting in the public hallways in order to accommodate the circadian rhythm of some species.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg')
|
||||
activate()
|
||||
|
||||
else
|
||||
if (isactive)
|
||||
deactivate()
|
||||
var/time = worldtime2hours()
|
||||
if (time <= config.nl_finish || time >= config.nl_start)
|
||||
if (!isactive)
|
||||
command_announcement.Announce("Good evening. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now dim lighting in the public hallways in order to accommodate the circadian rhythm of some species.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg')
|
||||
activate()
|
||||
else
|
||||
if (isactive)
|
||||
command_announcement.Announce("Good morning. The time is [worldtime2text()]. \n\nThe automated systems aboard the [station_name()] will now return the public hallway lighting levels to normal.", "Automated Lighting System", new_sound = 'sound/misc/bosuns_whistle.ogg')
|
||||
deactivate()
|
||||
|
||||
// 'whitelisted' areas are areas that have nightmode explicitly enabled
|
||||
|
||||
@@ -54,14 +46,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 +65,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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -4,43 +4,141 @@
|
||||
* Scheduler *
|
||||
************/
|
||||
/datum/controller/process/scheduler
|
||||
var/list/scheduled_tasks
|
||||
var/list/datum/scheduled_task/tasks = list()
|
||||
var/datum/scheduled_task/head
|
||||
|
||||
/datum/controller/process/scheduler/setup()
|
||||
name = "scheduler"
|
||||
schedule_interval = 3 SECONDS
|
||||
scheduled_tasks = list()
|
||||
schedule_interval = 2
|
||||
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
|
||||
while (head && !PSCHED_CHECK_TICK)
|
||||
if (head.destroyed)
|
||||
head.kill()
|
||||
head = head.next
|
||||
tasks -= head
|
||||
continue
|
||||
if (head.trigger_time >= world.time)
|
||||
return // Nothing after this will be ready to fire.
|
||||
|
||||
// This one's ready to fire, process it.
|
||||
var/datum/scheduled_task/task = head
|
||||
head = task.next
|
||||
task.pre_process()
|
||||
task.process()
|
||||
task.post_process()
|
||||
if (task.destroyed) // post_process probably destroyed it.
|
||||
tasks -= task
|
||||
task.kill()
|
||||
|
||||
/datum/controller/process/scheduler/proc/queue(datum/scheduled_task/task)
|
||||
if (!task || !task.trigger_time)
|
||||
warning("scheduler: Invalid task queued! Ignoring.")
|
||||
return
|
||||
// Reset this in-case we're doing a rebuild.
|
||||
task.next = null
|
||||
if (!head && !tasks.len)
|
||||
head = task
|
||||
tasks += task
|
||||
return
|
||||
|
||||
if (!head) // Head's missing but we still have tasks, rebuild.
|
||||
tasks += task
|
||||
rebuild_queue()
|
||||
return
|
||||
|
||||
var/datum/scheduled_task/curr = head
|
||||
while (curr.next && curr.trigger_time < task.trigger_time)
|
||||
curr = curr.next
|
||||
|
||||
if (!curr.next)
|
||||
// We're at the end of the queue, just append.
|
||||
curr.next = task
|
||||
tasks += task
|
||||
return
|
||||
|
||||
// Inserting midway into the list.
|
||||
var/old_next = curr.next
|
||||
curr.next = task
|
||||
task.next = old_next
|
||||
tasks += task
|
||||
|
||||
// Rebuilds the queue linked-list, removing invalid or destroyed entries.
|
||||
/datum/controller/process/scheduler/proc/rebuild_queue()
|
||||
log_debug("scheduler: Rebuilding queue.")
|
||||
var/list/old_tasks = tasks
|
||||
tasks = list()
|
||||
if (!old_tasks.len)
|
||||
log_debug("scheduler: rebuild was called on empty queue! Aborting.")
|
||||
return
|
||||
|
||||
// Find the head.
|
||||
for (var/thing in old_tasks)
|
||||
var/datum/scheduled_task/task = thing
|
||||
if (QDELETED(task))
|
||||
old_tasks -= task
|
||||
continue
|
||||
|
||||
if (task.destroyed)
|
||||
old_tasks -= task
|
||||
task.kill()
|
||||
continue
|
||||
|
||||
if (!head || task.trigger_time < head.trigger_time)
|
||||
head = task
|
||||
|
||||
if (!head)
|
||||
log_debug("scheduler: unable to find head! Purging task queue.")
|
||||
for (var/thing in old_tasks)
|
||||
var/datum/scheduled_task/task = thing
|
||||
if (QDELETED(task))
|
||||
continue
|
||||
|
||||
task.kill()
|
||||
|
||||
head = null
|
||||
return
|
||||
|
||||
// Don't queue the head.
|
||||
tasks += head
|
||||
old_tasks -= head
|
||||
|
||||
// Now rebuild the queue.
|
||||
for (var/thing in old_tasks)
|
||||
var/datum/scheduled_task/task = thing
|
||||
|
||||
queue(task)
|
||||
|
||||
log_debug("scheduler: Queue diff is [old_tasks.len - tasks.len].")
|
||||
|
||||
/datum/controller/process/scheduler/statProcess()
|
||||
..()
|
||||
stat(null, "[scheduled_tasks.len] task\s")
|
||||
stat(null, "[tasks.len] task\s")
|
||||
|
||||
/datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st)
|
||||
scheduled_tasks += st
|
||||
destroyed_event.register(st, src, /datum/controller/process/scheduler/proc/unschedule)
|
||||
queue(st)
|
||||
|
||||
/datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st)
|
||||
if(st in scheduled_tasks)
|
||||
scheduled_tasks -= st
|
||||
destroyed_event.unregister(st, src)
|
||||
st.destroyed = TRUE
|
||||
|
||||
/**********
|
||||
* Helpers *
|
||||
**********/
|
||||
/proc/schedule(source, the_proc, time, ...)
|
||||
if (time < 0)
|
||||
return
|
||||
time += world.time
|
||||
var/list/the_args
|
||||
if (length(args) > 3)
|
||||
the_args = args.Copy(4)
|
||||
else
|
||||
the_args = list()
|
||||
if (source)
|
||||
return schedule_task_with_source(time, the_proc, the_args)
|
||||
else
|
||||
return schedule_task(time, the_proc, the_args)
|
||||
|
||||
/proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list())
|
||||
return schedule_task(world.time + in_time, procedure, arguments)
|
||||
|
||||
@@ -66,68 +164,3 @@
|
||||
var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
|
||||
scheduler.schedule(st)
|
||||
return st
|
||||
|
||||
/*************
|
||||
* Task Datum *
|
||||
*************/
|
||||
/datum/scheduled_task
|
||||
var/trigger_time
|
||||
var/procedure
|
||||
var/list/arguments
|
||||
var/task_after_process
|
||||
var/list/task_after_process_args
|
||||
|
||||
/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
|
||||
..()
|
||||
src.trigger_time = trigger_time
|
||||
src.procedure = procedure
|
||||
src.arguments = arguments ? arguments : list()
|
||||
src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task
|
||||
src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list()
|
||||
task_after_process_args += src
|
||||
|
||||
/datum/scheduled_task/Destroy()
|
||||
procedure = null
|
||||
arguments.Cut()
|
||||
task_after_process = null
|
||||
task_after_process_args.Cut()
|
||||
return ..()
|
||||
|
||||
/datum/scheduled_task/proc/pre_process()
|
||||
task_triggered_event.raise_event(list(src))
|
||||
|
||||
/datum/scheduled_task/proc/process()
|
||||
if(procedure)
|
||||
call(procedure)(arglist(arguments))
|
||||
|
||||
/datum/scheduled_task/proc/post_process()
|
||||
call(task_after_process)(arglist(task_after_process_args))
|
||||
|
||||
// Resets the trigger time, has no effect if the task has already triggered
|
||||
/datum/scheduled_task/proc/trigger_task_in(var/trigger_in)
|
||||
src.trigger_time = world.time + trigger_in
|
||||
|
||||
/datum/scheduled_task/source
|
||||
var/datum/source
|
||||
|
||||
/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
|
||||
src.source = source
|
||||
destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
|
||||
..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
|
||||
|
||||
/datum/scheduled_task/source/Destroy()
|
||||
source = null
|
||||
return ..()
|
||||
|
||||
/datum/scheduled_task/source/process()
|
||||
call(source, procedure)(arglist(arguments))
|
||||
|
||||
/datum/scheduled_task/source/proc/source_destroyed()
|
||||
qdel(src)
|
||||
|
||||
/proc/destroy_scheduled_task(var/datum/scheduled_task/st)
|
||||
qdel(st)
|
||||
|
||||
/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st)
|
||||
st.trigger_time = world.time + trigger_delay
|
||||
scheduler.schedule(st)
|
||||
|
||||
@@ -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()
|
||||
..()
|
||||
|
||||
@@ -69,4 +69,4 @@ var/datum/controller/process/wireless/wirelessProcess
|
||||
process_conections -= C
|
||||
if(!target_found)
|
||||
unsuccesful_connections += C
|
||||
SCHECK
|
||||
F_SCHECK
|
||||
|
||||
@@ -177,8 +177,8 @@ var/list/gamemode_cache = list()
|
||||
var/ghost_interaction = 0
|
||||
|
||||
var/night_lighting = 0
|
||||
var/nl_start = 19 * TICKS_IN_HOUR
|
||||
var/nl_finish = 8 * TICKS_IN_HOUR
|
||||
var/nl_start = 19
|
||||
var/nl_finish = 8
|
||||
|
||||
var/comms_password = ""
|
||||
|
||||
@@ -187,6 +187,7 @@ var/list/gamemode_cache = list()
|
||||
var/use_discord_bot = 0
|
||||
var/discord_bot_host = "localhost"
|
||||
var/discord_bot_port = 0
|
||||
var/use_discord_pins = 0
|
||||
var/python_path = "python" //Path to the python executable. Defaults to "python" on windows and "/usr/bin/env python2" on unix
|
||||
var/use_lib_nudge = 0 //Use the C library nudge instead of the python nudge.
|
||||
var/use_overmap = 0
|
||||
@@ -629,10 +630,10 @@ var/list/gamemode_cache = list()
|
||||
config.night_lighting = 1
|
||||
|
||||
if("nl_start_hour")
|
||||
config.nl_start = text2num(value) * TICKS_IN_HOUR
|
||||
config.nl_start = text2num(value)
|
||||
|
||||
if("nl_finish_hour")
|
||||
config.nl_finish = text2num(value) * TICKS_IN_HOUR
|
||||
config.nl_finish = text2num(value)
|
||||
|
||||
if("disable_player_mice")
|
||||
config.disable_player_mice = 1
|
||||
@@ -652,6 +653,9 @@ var/list/gamemode_cache = list()
|
||||
if("discord_bot_port")
|
||||
config.discord_bot_port = value
|
||||
|
||||
if("use_discord_pins")
|
||||
config.use_discord_pins = 1
|
||||
|
||||
if("python_path")
|
||||
if(value)
|
||||
config.python_path = value
|
||||
@@ -878,6 +882,8 @@ var/list/gamemode_cache = list()
|
||||
discord_bot.active = 1
|
||||
if ("robust_debug")
|
||||
discord_bot.robust_debug = 1
|
||||
if ("subscriber")
|
||||
discord_bot.subscriber_role = value
|
||||
else
|
||||
log_misc("Unknown setting in discord configuration: '[name]'")
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/var/global/datum/controller/law/corp_regs
|
||||
|
||||
/datum/controller/law
|
||||
var/list/laws = list() // All laws
|
||||
|
||||
var/list/low_severity = list()
|
||||
var/list/med_severity = list()
|
||||
var/list/high_severity = list()
|
||||
|
||||
/datum/controller/law/New()
|
||||
corp_regs = src
|
||||
|
||||
for (var/L in subtypesof(/datum/law/low_severity))
|
||||
low_severity += new L
|
||||
|
||||
for (var/L in subtypesof(/datum/law/med_severity))
|
||||
med_severity += new L
|
||||
|
||||
for (var/L in subtypesof(/datum/law/high_severity))
|
||||
high_severity += new L
|
||||
|
||||
laws = low_severity + med_severity + high_severity
|
||||
|
||||
..()
|
||||
@@ -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()
|
||||
@@ -86,5 +94,8 @@ datum/controller/game_controller/proc/setup_objects()
|
||||
//Set up spawn points.
|
||||
populate_spawn_points()
|
||||
|
||||
// Setup laws.
|
||||
global.corp_regs = new
|
||||
|
||||
admin_notice("<span class='danger'>Initializations complete.</span>", R_DEBUG)
|
||||
sleep(-1)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -194,8 +194,15 @@ datum/controller/vote
|
||||
|
||||
proc/submit_vote(var/ckey, var/vote)
|
||||
if(mode)
|
||||
if(config.vote_no_dead && usr.stat == DEAD && !usr.client.holder)
|
||||
return 0
|
||||
if(config.vote_no_dead && usr && !usr.client.holder)
|
||||
if (isnewplayer(usr))
|
||||
usr << "<span class='warning'>You must be playing or have been playing to start a vote.</span>"
|
||||
return 0
|
||||
else if (isobserver(usr))
|
||||
var/mob/dead/observer/O = usr
|
||||
if (O.started_as_observer)
|
||||
usr << "<span class='warning'>You must be playing or have been playing to start a vote.</span>"
|
||||
return 0
|
||||
if(vote && vote >= 1 && vote <= choices.len)
|
||||
if(current_votes[ckey])
|
||||
choices[choices[current_votes[ckey]]]--
|
||||
@@ -211,6 +218,16 @@ datum/controller/vote
|
||||
// Transfer votes are their own little special snowflake
|
||||
var/next_allowed_time = 0
|
||||
if (vote_type == "crew_transfer")
|
||||
if (config.vote_no_dead && !usr.client.holder)
|
||||
if (isnewplayer(usr))
|
||||
usr << "<span class='warning'>You must be playing or have been playing to start a vote.</span>"
|
||||
return 0
|
||||
else if (isobserver(usr))
|
||||
var/mob/dead/observer/O = usr
|
||||
if (O.started_as_observer)
|
||||
usr << "<span class='warning'>You must be playing or have been playing to start a vote.</span>"
|
||||
return 0
|
||||
|
||||
if (last_transfer_vote)
|
||||
next_allowed_time = (last_transfer_vote + config.vote_delay)
|
||||
else
|
||||
|
||||
+335
-48
@@ -1,6 +1,13 @@
|
||||
#define CHAN_ADMIN "channel_admin"
|
||||
#define CHAN_CCIAA "channel_cciaa"
|
||||
#define CHAN_ANNOUNCE "channel_announce"
|
||||
#define CHAN_INVITE "channel_invite"
|
||||
|
||||
#define SEND_OK 0
|
||||
#define SEND_TIMEOUT 1
|
||||
#define ERROR_PROC 2
|
||||
#define ERROR_CURL 3
|
||||
#define ERROR_HTTP 4
|
||||
|
||||
var/datum/discord_bot/discord_bot = null
|
||||
|
||||
@@ -15,21 +22,34 @@ var/datum/discord_bot/discord_bot = null
|
||||
|
||||
discord_bot.update_channels()
|
||||
|
||||
if (config.use_discord_pins && server_greeting)
|
||||
server_greeting.update_pins()
|
||||
|
||||
return 1
|
||||
|
||||
/datum/discord_bot
|
||||
var/list/channels = list()
|
||||
var/list/channels_to_group = list() // Group flag -> list of channel datums map.
|
||||
var/list/channels = list() // Channel ID -> channel datum map. Will ensure that only one datum per channel ID exists.
|
||||
|
||||
var/datum/discord_channel/invite = null // The channel datum where the ingame Join Channel button will link to.
|
||||
|
||||
var/active = 0
|
||||
var/auth_token = ""
|
||||
var/subscriber_role = ""
|
||||
|
||||
var/robust_debug = 0
|
||||
|
||||
// Lazy man's rate limiting vars
|
||||
var/rate_limited_since = 0
|
||||
var/queue_being_pushed = 0
|
||||
var/datum/scheduled_task/push_task
|
||||
var/list/queue = list()
|
||||
|
||||
/*
|
||||
* Proc update_channels
|
||||
* Used to load channels from the database and construct them with the discord API.
|
||||
* Wipes all current channels and channel maps.
|
||||
*
|
||||
* @return num - Error code. 0 upon success.
|
||||
*/
|
||||
/datum/discord_bot/proc/update_channels()
|
||||
if (!active)
|
||||
return 1
|
||||
@@ -38,27 +58,56 @@ var/datum/discord_bot/discord_bot = null
|
||||
log_debug("BOREALIS: Failed to update channels due to missing database.")
|
||||
return 2
|
||||
|
||||
channels = list()
|
||||
// Reset the channel lists.
|
||||
channels_to_group.Cut()
|
||||
channels.Cut()
|
||||
|
||||
var/DBQuery/channel_query = dbcon.NewQuery("SELECT channel_group, channel_id FROM discord_channels")
|
||||
var/DBQuery/channel_query = dbcon.NewQuery("SELECT channel_group, channel_id, pin_flag, server_id FROM discord_channels")
|
||||
channel_query.Execute()
|
||||
|
||||
var/list/A
|
||||
while (channel_query.NextRow())
|
||||
if (isnull(channels[channel_query.item[1]]))
|
||||
channels[channel_query.item[1]] = list()
|
||||
// Create the channel map.
|
||||
if (isnull(channels_to_group[channel_query.item[1]]))
|
||||
channels_to_group[channel_query.item[1]] = list()
|
||||
|
||||
A = channels[channel_query.item[1]]
|
||||
A += channel_query.item[2]
|
||||
var/datum/discord_channel/B = channels[channel_query.item[2]]
|
||||
|
||||
// We don't have this channel datum yet.
|
||||
if (isnull(B))
|
||||
B = new(channel_query.item[2], channel_query.item[4], text2num(channel_query.item[3]))
|
||||
|
||||
if (!B)
|
||||
log_debug("BOREALIS: Bad channel data during update channels. [jointext(channel_query.item, ", ")].")
|
||||
continue
|
||||
|
||||
channels[channel_query.item[2]] = B
|
||||
|
||||
if (text2num(channel_query.item[3]))
|
||||
B.pin_flag |= text2num(channel_query.item[3])
|
||||
|
||||
// Add the channel to the required lists.
|
||||
channels_to_group[channel_query.item[1]] += B
|
||||
|
||||
if (!isnull(channels_to_group[CHAN_INVITE]))
|
||||
invite = channels_to_group[CHAN_INVITE][1]
|
||||
else if (robust_debug)
|
||||
log_debug("BOREALIS: No invite channel designated.")
|
||||
|
||||
log_debug("BOREALIS: Channels updated successfully.")
|
||||
return 0
|
||||
|
||||
/*
|
||||
* Proc send_message
|
||||
* Used to send a message to a specific channel group.
|
||||
*
|
||||
* @param text channel_group - The name of the channel group which to target.
|
||||
* @param text message - The message to send.
|
||||
*/
|
||||
/datum/discord_bot/proc/send_message(var/channel_group, var/message)
|
||||
if (!active || !auth_token)
|
||||
return
|
||||
|
||||
if (!channel_group || !channels.len || isnull(channels[channel_group]))
|
||||
if (!channel_group || !channels.len || isnull(channels_to_group[channel_group]))
|
||||
return
|
||||
|
||||
if (!message)
|
||||
@@ -70,18 +119,18 @@ var/datum/discord_bot/discord_bot = null
|
||||
// Let's run it through the proper JSON encoder, just in case of special characters.
|
||||
message = json_encode(list("content" = message))
|
||||
|
||||
var/list/A = channels[channel_group]
|
||||
var/list/A = channels_to_group[channel_group]
|
||||
var/list/sent = list()
|
||||
for (var/channel in A)
|
||||
if (send_post_request("https://discordapp.com/api/channels/[channel]/messages", message, "Authorization: Bot [auth_token]", "Content-Type: application/json") == 429)
|
||||
for (var/B in A)
|
||||
var/datum/discord_channel/channel = B
|
||||
if (channel.send_message_to(auth_token, message) == SEND_TIMEOUT)
|
||||
// Whoopsies, rate limited.
|
||||
// Set up the queue.
|
||||
rate_limited_since = world.time
|
||||
queue.Add(list(message, A - sent))
|
||||
queue.Add(list(list(message, A - sent)))
|
||||
|
||||
// Schedule a push.
|
||||
spawn (100)
|
||||
push_queue()
|
||||
if (!push_task)
|
||||
push_task = schedule_task_with_source_in(10 SECONDS, src, /datum/discord_bot/proc/push_queue)
|
||||
|
||||
// And exit.
|
||||
return
|
||||
@@ -89,43 +138,87 @@ var/datum/discord_bot/discord_bot = null
|
||||
sent += channel
|
||||
|
||||
if (robust_debug)
|
||||
log_debug("BOEALIS: Message sent to [channel_group]. JSON body: '[message]'")
|
||||
log_debug("BOREALIS: Message sent to [channel_group]. JSON body: '[message]'")
|
||||
|
||||
/*
|
||||
* Proc retreive_pins
|
||||
* Used to fetch a list of all pins from the designated channels.
|
||||
*
|
||||
* @return list - A multilayered list of flags associated with pins. Structure looks like this:
|
||||
* list("pin_flag" = list(list("author" = author name, "content" = content),
|
||||
* list("author" = author name, "content" = content)))
|
||||
*/
|
||||
/datum/discord_bot/proc/retreive_pins()
|
||||
if (!active || !auth_token)
|
||||
return list()
|
||||
|
||||
if (!channels.len || isnull(channels_to_group["channel_pins"]))
|
||||
testing("No group.")
|
||||
return list()
|
||||
|
||||
var/list/output = list()
|
||||
|
||||
for (var/A in channels_to_group["channel_pins"])
|
||||
var/datum/discord_channel/channel = A
|
||||
if (isnull(output["[channel.pin_flag]"]))
|
||||
output["[channel.pin_flag]"] = list()
|
||||
|
||||
output["[channel.pin_flag]"] += channel.get_pins(auth_token)
|
||||
|
||||
return output
|
||||
|
||||
/*
|
||||
* Proc retreive_invite
|
||||
* Used to retreive the invite to the invite channel.
|
||||
* One will be created if none exist.
|
||||
*
|
||||
* @return text - The invite URL to the designated invite channel.
|
||||
*/
|
||||
/datum/discord_bot/proc/retreive_invite()
|
||||
if (!active || !auth_token)
|
||||
return ""
|
||||
|
||||
if (!invite)
|
||||
return ""
|
||||
|
||||
var/res = invite.get_invite(auth_token)
|
||||
return isnum(res) ? "" : res
|
||||
|
||||
/*
|
||||
* Proc send_to_admin
|
||||
* Forwards a message to the admin channels.
|
||||
*/
|
||||
/datum/discord_bot/proc/send_to_admins(message)
|
||||
send_message(CHAN_ADMIN, message)
|
||||
|
||||
/*
|
||||
* Proc send_to_cciaa
|
||||
* Forwards a message to the CCIAA channels.
|
||||
*/
|
||||
/datum/discord_bot/proc/send_to_cciaa(message)
|
||||
send_message(CHAN_CCIAA, message)
|
||||
|
||||
/datum/discord_bot/proc/send_to_announce(message)
|
||||
/*
|
||||
* Proc send_to_announce
|
||||
* Forwards a message to the announcements channels.
|
||||
*/
|
||||
/datum/discord_bot/proc/send_to_announce(message, prepend_role = 0)
|
||||
if (prepend_role && subscriber_role)
|
||||
message = "<@&[subscriber_role]> " + message
|
||||
send_message(CHAN_ANNOUNCE, message)
|
||||
|
||||
/*
|
||||
* Proc push_queue
|
||||
* Handles the queue pushing for the bot. If there is no need to reschedule (all messages get successfully
|
||||
* pushed), then it deletes push_task and sets it back to null. Otherwise, it simply reschedules it.
|
||||
*/
|
||||
/datum/discord_bot/proc/push_queue()
|
||||
// What facking queue.
|
||||
if (!queue.len)
|
||||
if (!queue || !queue.len)
|
||||
if (robust_debug)
|
||||
log_debug("BOREALIS: Attempted to push a null length queue.")
|
||||
if (queue_being_pushed)
|
||||
queue_being_pushed = 0
|
||||
return
|
||||
|
||||
if (queue_being_pushed)
|
||||
if (robust_debug)
|
||||
log_debug("BOREALIS: Attempted to initialize a second queue driver.")
|
||||
return
|
||||
|
||||
if ((world.time - rate_limited_since) < 100)
|
||||
// Something broke the limit again. Ideally, this wouldn't happen. But sure.
|
||||
// Use a longer timeout, just in case.
|
||||
spawn (200)
|
||||
push_queue()
|
||||
|
||||
queue_being_pushed = 0
|
||||
return
|
||||
|
||||
// Async process lock var. No touchy.
|
||||
queue_being_pushed = 1
|
||||
|
||||
// A[1] - message body.
|
||||
// A[2] - list of channels to send to.
|
||||
var/message
|
||||
@@ -134,22 +227,216 @@ var/datum/discord_bot/discord_bot = null
|
||||
message = A[1]
|
||||
destinations = A[2]
|
||||
|
||||
for (var/channel in destinations)
|
||||
if (send_post_request("https://discordapp.com/api/channels/[channel]/messages", message, "Authorization: Bot [auth_token]", "Content-Type: application/json") == 429)
|
||||
// Limited again. Reschedule.
|
||||
rate_limited_since = world.time
|
||||
spawn (100)
|
||||
push_queue()
|
||||
for (var/B in destinations)
|
||||
var/datum/discord_channel/channel = B
|
||||
if (channel.send_message_to(auth_token, message) == SEND_TIMEOUT)
|
||||
// Tasks nuke themselves after use. So just make a new one! What could possibly go wrong!
|
||||
push_task = schedule_task_with_source_in(10 SECONDS, src, /datum/discord_bot/proc/push_queue)
|
||||
|
||||
queue_being_pushed = 0
|
||||
return
|
||||
else
|
||||
destinations.Remove(channel)
|
||||
|
||||
queue.Remove(A)
|
||||
|
||||
queue_being_pushed = 0
|
||||
// A holder class for channels.
|
||||
/datum/discord_channel
|
||||
var/id = ""
|
||||
var/server_id = ""
|
||||
var/pin_flag = 0
|
||||
var/invite_url = ""
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*
|
||||
* @param text _id - the discord API id of the channel, as a string.
|
||||
* @param text _sid - the discord API server id for the channel, as a string.
|
||||
* @param num _pin - the bitflags of admin permissions which have access to the pins from this channel.
|
||||
*/
|
||||
/datum/discord_channel/New(var/_id, var/_sid, var/_pin)
|
||||
id = _id
|
||||
server_id = _sid
|
||||
|
||||
if (_pin)
|
||||
pin_flag = _pin
|
||||
|
||||
/*
|
||||
* Proc send_message_to
|
||||
* Sends a message to the channel.
|
||||
*
|
||||
* @param text token - the authorization token to be used for the requests.
|
||||
* @param text message - the sanitized message content to be sent.
|
||||
* @return num - a specific return code for the discord_bot to handle.
|
||||
*/
|
||||
/datum/discord_channel/proc/send_message_to(var/token, var/message)
|
||||
if (!token || !message)
|
||||
return ERROR_PROC
|
||||
|
||||
var/res = send_post_request("https://discordapp.com/api/channels/[id]/messages", message, "Authorization: Bot [token]", "Content-Type: application/json")
|
||||
|
||||
switch (res)
|
||||
if (-1)
|
||||
return ERROR_PROC
|
||||
|
||||
if (200)
|
||||
return SEND_OK
|
||||
|
||||
if (429)
|
||||
return SEND_TIMEOUT
|
||||
|
||||
if (0 to 90)
|
||||
log_debug("BOREALIS: cURL error while forwarding message to Discord API: [res]. Message body: [message].")
|
||||
return ERROR_CURL
|
||||
|
||||
else
|
||||
log_debug("BOREALIS: HTTP error while forwarding message to Discord API: [res]. Channel: [id]. Message body: [message].")
|
||||
return ERROR_HTTP
|
||||
|
||||
/*
|
||||
* Proc get_pins
|
||||
* Retreives a list of pinned messages from the channel.
|
||||
*
|
||||
* @param text token - the authorization token to be used for the requests.
|
||||
* @return mixed - 2d array of content upon success, in format: list(list("author" = text, "content" = text)).
|
||||
* Num upon failure.
|
||||
*/
|
||||
/datum/discord_channel/proc/get_pins(var/token)
|
||||
var/res = send_get_request("https://discordapp.com/api/channels/[id]/pins", "Authorization: Bot [token]")
|
||||
|
||||
// Is a number, so an error code.
|
||||
if (isnum(res))
|
||||
switch (res)
|
||||
if (-1)
|
||||
return ERROR_PROC
|
||||
|
||||
if (0 to 90)
|
||||
log_debug("BOREALIS: cURL error while fetching pins from the Discord API: [res].")
|
||||
return ERROR_CURL
|
||||
|
||||
if (100 to 600)
|
||||
log_debug("BOREALIS: HTTP error while fetching pins from the Discord API: [res].")
|
||||
return ERROR_HTTP
|
||||
|
||||
else
|
||||
log_debug("BOREALIS: Unknown response code while fetching pins from the Discord API: [res].")
|
||||
return ERROR_PROC
|
||||
else
|
||||
var/list/A = res
|
||||
var/list/pinned_messages = list()
|
||||
|
||||
// Begin processing the list structure delivered back to us from send_get_request.
|
||||
for (var/list/B in A)
|
||||
var/content = B["content"]
|
||||
|
||||
// We have mentions to take care of.
|
||||
if (!isnull(B["mentions"]))
|
||||
var/list/mentions = B["mentions"]
|
||||
|
||||
for (var/list/C in mentions)
|
||||
content = replacetextEx(content, "<@[C["id"]]>", C["username"])
|
||||
|
||||
// Role mentions are up next.
|
||||
if (!isnull(B["mention_roles"]))
|
||||
var/list/mentions = B["mention_roles"]
|
||||
|
||||
for (var/C in mentions)
|
||||
content = replacetextEx(content, "<@&[C]>", "@SomeRole")
|
||||
|
||||
pinned_messages += list(list("author" = B["author"]["username"], "content" = content))
|
||||
|
||||
return pinned_messages
|
||||
|
||||
/*
|
||||
* Proc get_invite
|
||||
* Retreives (or creates if none found) an invite URL to the specific channel.
|
||||
*
|
||||
* @param text token - the authorization token to be used for the requests.
|
||||
* @return mixed - text upon success, the link to the invite; num upon failure.
|
||||
*/
|
||||
/datum/discord_channel/proc/get_invite(var/token)
|
||||
if (invite_url)
|
||||
return invite_url
|
||||
|
||||
var/res = send_get_request("https://discordapp.com/api/channels/[id]/invites", "Authorization: Bot [token]")
|
||||
|
||||
// Is a number, so an error code.
|
||||
if (isnum(res))
|
||||
switch (res)
|
||||
if (-1)
|
||||
return ERROR_PROC
|
||||
|
||||
if (0 to 90)
|
||||
log_debug("BOREALIS: cURL error while fetching pins from the Discord API: [res].")
|
||||
return ERROR_CURL
|
||||
|
||||
if (100 to 600)
|
||||
log_debug("BOREALIS: HTTP error while fetching pins from the Discord API: [res].")
|
||||
return ERROR_HTTP
|
||||
|
||||
else
|
||||
log_debug("BOREALIS: Unknown response code while fetching pins from the Discord API: [res].")
|
||||
return ERROR_PROC
|
||||
else
|
||||
var/list/A = res
|
||||
|
||||
// No length to return data, but a valid 200 return header.
|
||||
// So we simply have no invites active. Make one!
|
||||
if (!A || !A.len)
|
||||
return create_invite(token)
|
||||
|
||||
var/best_age = A[1]["max_age"]
|
||||
var/code = A[1]["code"]
|
||||
|
||||
// Find the best invite.
|
||||
// Why? Because round time expires are lame, I guess.
|
||||
if (best_age != 0)
|
||||
for (var/i = 2, i < A.len, i++)
|
||||
if (A[i]["max_age"] == 0)
|
||||
code = A[i]["code"]
|
||||
break
|
||||
|
||||
if (best_age < A[i]["max_age"])
|
||||
best_age = A[i]["max_age"]
|
||||
code = A[i]["code"]
|
||||
|
||||
// Sanity check for debug I guess.
|
||||
if (!code)
|
||||
log_debug("BOREALIS: Retreived an empty invite. This should not happen. Response object: [json_encode(A)]")
|
||||
|
||||
// Save the URL for later retreival.
|
||||
invite_url = "https://discord.gg/[code]"
|
||||
return invite_url
|
||||
|
||||
/*
|
||||
* Proc create_invite
|
||||
* Creates a permanent invite to a channel and returns it, under the assumption that
|
||||
* there are no other invites for this channel.
|
||||
*
|
||||
* @param text token - the authorization token to be used for the requests.
|
||||
* @return mixed - String upon success - the URL of the newly generated invite.
|
||||
* Num upon failure.
|
||||
*/
|
||||
/datum/discord_channel/proc/create_invite(var/token)
|
||||
var/data = list("max_age" = 0, "max_uses" = 0)
|
||||
var/res = send_post_request("https://discordapp.com/api/channels/[id]/invites", json_encode(data), "Authorization: Bot [token]", "Content-Type: application/json")
|
||||
|
||||
if (res == 200)
|
||||
var/list/get_req = send_get_request("https://discordapp.com/api/channels/[id]/invites", "Authorization: Bot [token]")
|
||||
|
||||
if (!istype(get_req) || !get_req.len)
|
||||
return ERROR_PROC
|
||||
|
||||
// The first index should now exist. So we just use that!
|
||||
invite_url = "https://discord.gg/[get_req[1]["code"]]"
|
||||
return invite_url
|
||||
|
||||
#undef CHAN_ADMIN
|
||||
#undef CHAN_CCIAA
|
||||
#undef CHAN_ANNOUNCE
|
||||
#undef CHAN_INVITE
|
||||
|
||||
#undef SEND_OK
|
||||
#undef SEND_TIMEOUT
|
||||
#undef ERROR_PROC
|
||||
#undef ERROR_CURL
|
||||
#undef ERROR_HTTP
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
expansions.Cut()
|
||||
return ..()
|
||||
|
||||
/obj/ResetVars(var/list/exclude = list())
|
||||
/obj/resetVariables(var/list/exclude = list())
|
||||
exclude += "expansions"
|
||||
..(exclude)
|
||||
//expansions = list()
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
var/atom/movable/teleatom //atom to teleport
|
||||
var/atom/destination //destination to teleport to
|
||||
var/precision = 0 //teleport precision
|
||||
var/datum/effect/effect/system/effectin //effect to show right before teleportation
|
||||
var/datum/effect/effect/system/effectout //effect to show right after teleportation
|
||||
var/datum/effect_system/effectin //effect to show right before teleportation
|
||||
var/datum/effect_system/effectout //effect to show right after teleportation
|
||||
var/soundin //soundfile to play before teleportation
|
||||
var/soundout //soundfile to play after teleportation
|
||||
var/force_teleport = 1 //if false, teleport will use Move() proc (dense objects will prevent teleportation)
|
||||
@@ -78,13 +78,13 @@
|
||||
/datum/teleport/proc/teleportChecks()
|
||||
return 1
|
||||
|
||||
/datum/teleport/proc/playSpecials(atom/location,datum/effect/effect/system/effect,sound)
|
||||
/datum/teleport/proc/playSpecials(atom/location,datum/effect_system/effect,sound)
|
||||
if(location)
|
||||
if(effect)
|
||||
spawn(-1)
|
||||
src = null
|
||||
effect.attach(location)
|
||||
effect.start()
|
||||
effect.location = location
|
||||
effect.queue()
|
||||
if(sound)
|
||||
spawn(-1)
|
||||
src = null
|
||||
@@ -141,8 +141,7 @@
|
||||
|
||||
/datum/teleport/instant/science/setEffects(datum/effect/effect/system/aeffectin,datum/effect/effect/system/aeffectout)
|
||||
if(!aeffectin || !aeffectout)
|
||||
var/datum/effect/effect/system/spark_spread/aeffect = new
|
||||
aeffect.set_up(5, 1, teleatom)
|
||||
var/datum/effect_system/sparks/aeffect = getFromPool(/datum/effect_system/sparks, null, FALSE, 5, alldirs)
|
||||
effectin = effectin || aeffect
|
||||
effectout = effectout || aeffect
|
||||
return 1
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* /datum/recipe by rastaf0 13 apr 2011 *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* This is powerful and flexible recipe system.
|
||||
* It exists not only for food.
|
||||
* supports both reagents and objects as prerequisites.
|
||||
* In order to use this system you have to define a deriative from /datum/recipe
|
||||
* * reagents are reagents. Acid, milc, booze, etc.
|
||||
* * items are objects. Fruits, tools, circuit boards.
|
||||
* * result is type to create as new object
|
||||
* * time is optional parameter, you shall use in in your machine,
|
||||
default /datum/recipe/ procs does not rely on this parameter.
|
||||
*
|
||||
* Functions you need:
|
||||
* /datum/recipe/proc/make(var/obj/container as obj)
|
||||
* Creates result inside container,
|
||||
* deletes prerequisite reagents,
|
||||
* transfers reagents from prerequisite objects,
|
||||
* deletes all prerequisite objects (even not needed for recipe at the moment).
|
||||
*
|
||||
* /proc/select_recipe(list/datum/recipe/avaiable_recipes, obj/obj as obj, exact = 1)
|
||||
* Wonderful function that select suitable recipe for you.
|
||||
* obj is a machine (or magik hat) with prerequisites,
|
||||
* exact = 0 forces algorithm to ignore superfluous stuff.
|
||||
*
|
||||
*
|
||||
* Functions you do not need to call directly but could:
|
||||
* /datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents)
|
||||
* /datum/recipe/proc/check_items(var/obj/container as obj)
|
||||
*
|
||||
* */
|
||||
|
||||
/datum/recipe
|
||||
var/list/reagents // example: = list("berryjuice" = 5) // do not list same reagent twice
|
||||
var/list/items // example: = list(/obj/item/weapon/crowbar, /obj/item/weapon/welder) // place /foo/bar before /foo
|
||||
var/list/fruit // example: = list("fruit" = 3)
|
||||
var/result // example: = /obj/item/weapon/reagent_containers/food/snacks/donut/normal
|
||||
var/time = 100 // 1/10 part of second
|
||||
|
||||
/datum/recipe/proc/check_reagents(var/datum/reagents/avail_reagents)
|
||||
. = 1
|
||||
for (var/r_r in reagents)
|
||||
var/aval_r_amnt = avail_reagents.get_reagent_amount(r_r)
|
||||
if (!(abs(aval_r_amnt - reagents[r_r])<0.5)) //if NOT equals
|
||||
if (aval_r_amnt>reagents[r_r])
|
||||
. = 0
|
||||
else
|
||||
return -1
|
||||
if ((reagents?(reagents.len):(0)) < avail_reagents.reagent_list.len)
|
||||
return 0
|
||||
return .
|
||||
|
||||
/datum/recipe/proc/check_fruit(var/obj/container)
|
||||
. = 1
|
||||
if(fruit && fruit.len)
|
||||
var/list/checklist = list()
|
||||
// You should trust Copy().
|
||||
checklist = fruit.Copy()
|
||||
for(var/obj/item/weapon/reagent_containers/food/snacks/grown/G in container)
|
||||
if(!G.seed || !G.seed.kitchen_tag || isnull(checklist[G.seed.kitchen_tag]))
|
||||
continue
|
||||
checklist[G.seed.kitchen_tag]--
|
||||
for(var/ktag in checklist)
|
||||
if(!isnull(checklist[ktag]))
|
||||
if(checklist[ktag] < 0)
|
||||
. = 0
|
||||
else if(checklist[ktag] > 0)
|
||||
. = -1
|
||||
break
|
||||
return .
|
||||
|
||||
/datum/recipe/proc/check_items(var/obj/container as obj)
|
||||
. = 1
|
||||
if (items && items.len)
|
||||
var/list/checklist = list()
|
||||
checklist = items.Copy() // You should really trust Copy
|
||||
for(var/obj/O in container)
|
||||
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/grown))
|
||||
continue // Fruit is handled in check_fruit().
|
||||
var/found = 0
|
||||
for(var/i = 1; i < checklist.len+1; i++)
|
||||
var/item_type = checklist[i]
|
||||
if (istype(O,item_type))
|
||||
checklist.Cut(i, i+1)
|
||||
found = 1
|
||||
break
|
||||
if (!found)
|
||||
. = 0
|
||||
if (checklist.len)
|
||||
. = -1
|
||||
return .
|
||||
|
||||
//general version
|
||||
/datum/recipe/proc/make(var/obj/container as obj)
|
||||
var/obj/result_obj = new result(container)
|
||||
for (var/obj/O in (container.contents-result_obj))
|
||||
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
|
||||
qdel(O)
|
||||
container.reagents.clear_reagents()
|
||||
return result_obj
|
||||
|
||||
// food-related
|
||||
/datum/recipe/proc/make_food(var/obj/container as obj)
|
||||
if(!result)
|
||||
world << "<span class='danger'>Recipe [type] is defined without a result, please bug this.</span>"
|
||||
return
|
||||
var/obj/result_obj = new result(container)
|
||||
for (var/obj/O in (container.contents-result_obj))
|
||||
if (O.reagents)
|
||||
O.reagents.del_reagent("nutriment")
|
||||
O.reagents.update_total()
|
||||
O.reagents.trans_to_obj(result_obj, O.reagents.total_volume)
|
||||
qdel(O)
|
||||
container.reagents.clear_reagents()
|
||||
return result_obj
|
||||
|
||||
/proc/select_recipe(var/list/datum/recipe/avaiable_recipes, var/obj/obj as obj, var/exact)
|
||||
var/list/datum/recipe/possible_recipes = new
|
||||
var/target = exact ? 0 : 1
|
||||
for (var/datum/recipe/recipe in avaiable_recipes)
|
||||
if((recipe.check_reagents(obj.reagents) < target) || (recipe.check_items(obj) < target) || (recipe.check_fruit(obj) < target))
|
||||
continue
|
||||
possible_recipes |= recipe
|
||||
if (possible_recipes.len==0)
|
||||
return null
|
||||
else if (possible_recipes.len==1)
|
||||
return possible_recipes[1]
|
||||
else //okay, let's select the most complicated recipe
|
||||
var/highest_count = 0
|
||||
. = possible_recipes[1]
|
||||
for (var/datum/recipe/recipe in possible_recipes)
|
||||
var/count = ((recipe.items)?(recipe.items.len):0) + ((recipe.reagents)?(recipe.reagents.len):0) + ((recipe.fruit)?(recipe.fruit.len):0)
|
||||
if (count >= highest_count)
|
||||
highest_count = count
|
||||
. = recipe
|
||||
return .
|
||||
@@ -0,0 +1,79 @@
|
||||
/*************
|
||||
* Task Datum *
|
||||
*************/
|
||||
/datum/scheduled_task
|
||||
var/trigger_time
|
||||
var/procedure
|
||||
var/list/arguments
|
||||
var/task_after_process
|
||||
var/list/task_after_process_args
|
||||
var/datum/scheduled_task/next
|
||||
var/destroyed = FALSE
|
||||
|
||||
/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
|
||||
..()
|
||||
src.trigger_time = trigger_time
|
||||
src.procedure = procedure
|
||||
src.arguments = arguments ? arguments : list()
|
||||
src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task
|
||||
src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list()
|
||||
task_after_process_args += src
|
||||
|
||||
/datum/scheduled_task/Destroy()
|
||||
if (!destroyed)
|
||||
kill(no_del = TRUE)
|
||||
procedure = null
|
||||
arguments.Cut()
|
||||
task_after_process = null
|
||||
task_after_process_args.Cut()
|
||||
return ..()
|
||||
|
||||
/datum/scheduled_task/proc/pre_process()
|
||||
return
|
||||
|
||||
/datum/scheduled_task/proc/process()
|
||||
if(procedure)
|
||||
call(procedure)(arglist(arguments))
|
||||
|
||||
/datum/scheduled_task/proc/post_process()
|
||||
call(task_after_process)(arglist(task_after_process_args))
|
||||
|
||||
// Resets the trigger time, has no effect if the task has already triggered
|
||||
/datum/scheduled_task/proc/trigger_task_in(var/trigger_in)
|
||||
src.trigger_time = world.time + trigger_in
|
||||
|
||||
/datum/scheduled_task/proc/kill(no_del = FALSE)
|
||||
if (!destroyed)
|
||||
warning("scheduler: Non-destroyed task was killed!")
|
||||
destroyed = TRUE
|
||||
|
||||
if (src in scheduler.tasks)
|
||||
warning("scheduler: Task was not cleaned up correctly, rebuilding scheduler queue!")
|
||||
scheduler.rebuild_queue()
|
||||
|
||||
if (!no_del)
|
||||
qdel(src)
|
||||
|
||||
/datum/scheduled_task/source
|
||||
var/datum/source
|
||||
|
||||
/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
|
||||
src.source = source
|
||||
..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
|
||||
|
||||
/datum/scheduled_task/source/Destroy()
|
||||
source = null
|
||||
return ..()
|
||||
|
||||
/datum/scheduled_task/source/process()
|
||||
call(source, procedure)(arglist(arguments))
|
||||
|
||||
/datum/scheduled_task/source/proc/source_destroyed()
|
||||
destroyed = TRUE
|
||||
|
||||
/proc/destroy_scheduled_task(var/datum/scheduled_task/st)
|
||||
st.destroyed = TRUE
|
||||
|
||||
/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st)
|
||||
st.trigger_time = world.time + trigger_delay
|
||||
scheduler.schedule(st)
|
||||
+111
-15
@@ -46,8 +46,9 @@
|
||||
if (F["motd"])
|
||||
F["motd"] >> motd
|
||||
|
||||
if (F["memo"])
|
||||
F["memo"] >> memo_list
|
||||
if (!config.use_discord_pins)
|
||||
if (F["memo"])
|
||||
F["memo"] >> memo_list
|
||||
|
||||
update_data()
|
||||
|
||||
@@ -63,18 +64,32 @@
|
||||
motd = initial(motd)
|
||||
motd_hash = ""
|
||||
|
||||
if (memo_list.len)
|
||||
memo = ""
|
||||
for (var/ckey in memo_list)
|
||||
var/data = {"<p><b>[ckey]</b> wrote on [memo_list[ckey]["date"]]:<br>
|
||||
[memo_list[ckey]["content"]]</p>"}
|
||||
if (!config.use_discord_pins)
|
||||
// The initialization of memos in case use_discord_pins == 1 is done in discord_bot.dm
|
||||
// Primary reason is to avoid null references when the bot isn't created yet.
|
||||
if (memo_list.len)
|
||||
memo = ""
|
||||
for (var/ckey in memo_list)
|
||||
var/data = {"<p><b>[ckey]</b> wrote on [memo_list[ckey]["date"]]:<br>
|
||||
[memo_list[ckey]["content"]]</p>"}
|
||||
|
||||
memo += data
|
||||
memo += data
|
||||
|
||||
memo_hash = md5(memo)
|
||||
else
|
||||
memo = initial(memo)
|
||||
memo_hash = ""
|
||||
memo_hash = md5(memo)
|
||||
else
|
||||
memo = initial(memo)
|
||||
memo_hash = ""
|
||||
|
||||
/datum/server_greeting/proc/update_pins()
|
||||
var/list/temp_list = discord_bot.retreive_pins()
|
||||
|
||||
// A is a number in a string form
|
||||
// temp_list[A] is a list of lists.
|
||||
for (var/A in temp_list)
|
||||
var/list/memos = temp_list[A]
|
||||
var/flag = text2num(A)
|
||||
|
||||
memo_list += new /datum/memo_datum(memos, flag)
|
||||
|
||||
/*
|
||||
* Helper to update the MoTD or memo contents.
|
||||
@@ -94,9 +109,15 @@
|
||||
motd = new_value
|
||||
|
||||
if ("memo_write")
|
||||
if (config.use_discord_pins)
|
||||
return 0
|
||||
|
||||
memo_list[new_value[1]] = list("date" = time2text(world.realtime, "DD-MMM-YYYY"), "content" = new_value[2])
|
||||
|
||||
if ("memo_delete")
|
||||
if (config.use_discord_pins)
|
||||
return 0
|
||||
|
||||
if (memo_list[new_value])
|
||||
memo_list -= new_value
|
||||
else
|
||||
@@ -132,7 +153,7 @@
|
||||
if (motd_hash && user.prefs.motd_hash != motd_hash)
|
||||
outdated_info |= OUTDATED_MOTD
|
||||
|
||||
if (user.holder && memo_hash && user.prefs.memo_hash != memo_hash)
|
||||
if (user.holder && user.prefs.memo_hash != get_memo_hash(user))
|
||||
outdated_info |= OUTDATED_MEMO
|
||||
|
||||
if (user.prefs.notifications.len)
|
||||
@@ -185,13 +206,13 @@
|
||||
else
|
||||
if (outdated_info & OUTDATED_MEMO)
|
||||
data["update"] = 1
|
||||
data["changeHash"] = memo_hash
|
||||
data["changeHash"] = get_memo_hash(user)
|
||||
else
|
||||
data["update"] = 0
|
||||
data["changeHash"] = null
|
||||
|
||||
data["div"] = "#memo"
|
||||
data["content"] = memo
|
||||
data["content"] = get_memo_content(user)
|
||||
user << output(JS_SANITIZE(data), "greeting.browser:AddContent")
|
||||
|
||||
if (outdated_info & OUTDATED_MOTD)
|
||||
@@ -216,6 +237,81 @@
|
||||
if ("request_data")
|
||||
send_to_javascript(C)
|
||||
|
||||
/*
|
||||
* Gets the appropriate memo hash for the memo system in use.
|
||||
* Args:
|
||||
* - var/C client
|
||||
* Returns:
|
||||
* - string
|
||||
*/
|
||||
/datum/server_greeting/proc/get_memo_hash(var/client/C)
|
||||
if (!C || !C.holder)
|
||||
return ""
|
||||
|
||||
if (!config.use_discord_pins)
|
||||
return memo_hash
|
||||
|
||||
var/joint_checksum = ""
|
||||
for (var/A in memo_list)
|
||||
var/datum/memo_datum/memo = A
|
||||
if (C.holder.rights & memo.flag)
|
||||
joint_checksum += memo.hash
|
||||
|
||||
return md5(joint_checksum)
|
||||
|
||||
/*
|
||||
* Gets the appropriate memo content for the memo system in use.
|
||||
* Args:
|
||||
* - var/C client
|
||||
* Returns:
|
||||
* - string if old memo system is used (config.use_discord_pins = 0)
|
||||
* - list of strings if new memo system is used
|
||||
*/
|
||||
/datum/server_greeting/proc/get_memo_content(var/client/C)
|
||||
if (!C || !C.holder)
|
||||
return ""
|
||||
|
||||
if (!config.use_discord_pins)
|
||||
return memo
|
||||
|
||||
var/list/content = list()
|
||||
for (var/A in memo_list)
|
||||
var/datum/memo_datum/memo = A
|
||||
if (C.holder.rights & memo.flag)
|
||||
content += memo.contents
|
||||
|
||||
return content
|
||||
|
||||
/datum/memo_datum
|
||||
var/contents
|
||||
var/hash
|
||||
var/flag
|
||||
|
||||
/datum/memo_datum/New(var/list/input = list(), var/_flag)
|
||||
flag = _flag
|
||||
|
||||
// Yes. This is an unfortunately acceptable way of doing it.
|
||||
// Why? Because you cannot use numbers as indexes in an assoc list without fucking DM.
|
||||
var/static/list/flags_to_divs = list("[R_ADMIN]" = "danger",
|
||||
"[R_MOD]" = "warning",
|
||||
"[(R_MOD|R_ADMIN)]" = "warning",
|
||||
"[R_CCIAA]" = "info",
|
||||
"[R_DEV]" = "info")
|
||||
|
||||
if (input.len)
|
||||
contents = "<div class='alert alert-[flags_to_divs["[flag]"]]'>"
|
||||
for (var/i = 1, i <= input.len, i++)
|
||||
contents += "<b>[input[i]["author"]]</b> wrote:<br>[nl2br(input[i]["content"])]"
|
||||
|
||||
if (i < input.len)
|
||||
contents += "<hr></hr>"
|
||||
|
||||
contents += "</div>"
|
||||
else
|
||||
contents = ""
|
||||
|
||||
hash = md5(contents)
|
||||
|
||||
#undef OUTDATED_NOTE
|
||||
#undef OUTDATED_MEMO
|
||||
#undef OUTDATED_MOTD
|
||||
|
||||
@@ -1733,3 +1733,44 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
|
||||
containertype = /obj/structure/closet/crate
|
||||
containername = "IPC/Shell tag implanters"
|
||||
group = "Security"
|
||||
|
||||
/datum/supply_packs/ame_ctrl
|
||||
name = "Antimatter Reactor Control Unit"
|
||||
contains = list(
|
||||
/obj/machinery/power/am_control_unit
|
||||
)
|
||||
cost = 40
|
||||
containertype = /obj/structure/closet/crate/secure/large
|
||||
containername = "antimatter reactor control unit kit"
|
||||
group = "Engineering"
|
||||
access = access_ce
|
||||
|
||||
/datum/supply_packs/ame_section
|
||||
name = "Antimatter Reactor Shielding Kit"
|
||||
contains = list(
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container,
|
||||
/obj/item/device/am_shielding_container
|
||||
)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate/secure/phoron
|
||||
containername = "antimatter reactor shielding (9x) crate"
|
||||
group = "Engineering"
|
||||
access = access_ce
|
||||
|
||||
/datum/supply_packs/ame_fuel
|
||||
name = "Antimatter Reactor Fuel"
|
||||
contains = list(
|
||||
/obj/item/weapon/am_containment
|
||||
)
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/crate/secure/bin
|
||||
containername = "antimatter fuel container"
|
||||
group = "Engineering"
|
||||
access = access_engine
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
item_cost = 2
|
||||
path = /obj/item/weapon/storage/toolbox/syndicate
|
||||
|
||||
/datum/uplink_item/item/tools/advancedpinpointer
|
||||
name = "Advanced pinpointer"
|
||||
item_cost = 15
|
||||
path = /obj/item/weapon/pinpointer/advpinpointer
|
||||
desc = "An advanced pinpointer that can find any target with DNA along with various other items."
|
||||
|
||||
/datum/uplink_item/item/tools/money
|
||||
name = "Operations Funding"
|
||||
item_cost = 2
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
|
||||
|
||||
+12
-11
@@ -173,7 +173,7 @@
|
||||
throw_range = 5
|
||||
w_class = 2.0
|
||||
attack_verb = list("warned", "cautioned", "smashed")
|
||||
|
||||
|
||||
/obj/item/weapon/caution/attack_self(mob/user as mob)
|
||||
if(src.icon_state == "caution")
|
||||
src.icon_state = "caution_blinking"
|
||||
@@ -181,14 +181,15 @@
|
||||
else
|
||||
src.icon_state = "caution"
|
||||
user << "You turn the sign off."
|
||||
|
||||
|
||||
/obj/item/weapon/caution/AltClick()
|
||||
if(src.icon_state == "caution")
|
||||
src.icon_state = "caution_blinking"
|
||||
usr << "You turn the sign on."
|
||||
else
|
||||
src.icon_state = "caution"
|
||||
usr << "You turn the sign off."
|
||||
if(!usr || usr.stat || usr.lying || usr.restrained() || !Adjacent(usr)) return
|
||||
if(src.icon_state == "caution")
|
||||
src.icon_state = "caution_blinking"
|
||||
usr << "You turn the sign on."
|
||||
else
|
||||
src.icon_state = "caution"
|
||||
usr << "You turn the sign off."
|
||||
|
||||
/obj/item/weapon/caution/cone
|
||||
desc = "This cone is trying to warn you of something!"
|
||||
@@ -197,10 +198,10 @@
|
||||
item_state = "cone"
|
||||
contained_sprite = 1
|
||||
slot_flags = SLOT_HEAD
|
||||
|
||||
|
||||
/obj/item/weapon/caution/cone/attack_self(mob/user as mob)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/weapon/caution/cone/AltClick()
|
||||
return
|
||||
|
||||
@@ -427,7 +428,7 @@
|
||||
icon = 'icons/obj/stock_parts.dmi'
|
||||
w_class = 2.0
|
||||
var/rating = 1
|
||||
|
||||
|
||||
/obj/item/weapon/stock_parts/New()
|
||||
src.pixel_x = rand(-5.0, 5)
|
||||
src.pixel_y = rand(-5.0, 5)
|
||||
|
||||
@@ -14,6 +14,7 @@ var/datum/antagonist/xenos/xenomorphs
|
||||
faction_descriptor = "Hive"
|
||||
faction_welcome = "Your will is ripped away as your humanity merges with the xenomorph overmind. You are now \
|
||||
a thrall to the queen and her brood. Obey their instructions without question. Serve the hive."
|
||||
faction = "xenomorph"
|
||||
|
||||
hard_cap = 5
|
||||
hard_cap_round = 8
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
var/faction_descriptor // Description of the cause. Mandatory for faction role.
|
||||
var/faction_verb // Verb added when becoming a member of the faction, if any.
|
||||
var/faction_welcome // Message shown to faction members.
|
||||
var/faction = "neutral" // Faction name, mostly used for simple animals.
|
||||
|
||||
// Spawn values (autotraitor and game mode)
|
||||
var/hard_cap = 3 // Autotraitor var. Won't spawn more than this many antags.
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
create_antagonist(player, move_to_spawn, do_not_announce, preserve_appearance)
|
||||
if(!do_not_equip)
|
||||
equip(player.current)
|
||||
|
||||
player.current.faction = faction
|
||||
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/add_antagonist_mind(var/datum/mind/player, var/ignore_role, var/nonstandard_role_type, var/nonstandard_role_msg)
|
||||
@@ -42,7 +45,7 @@
|
||||
update_icons_added(player)
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message, var/implanted)
|
||||
/datum/antagonist/proc/remove_antagonist(var/datum/mind/player, var/show_message = TRUE, var/implanted)
|
||||
if(!istype(player))
|
||||
return 0
|
||||
|
||||
@@ -50,14 +53,15 @@
|
||||
player.current.verbs -= faction_verb
|
||||
|
||||
if(player in current_antagonists)
|
||||
player.current << "<span class='danger'><font size = 3>You are no longer a [role_text]!</font></span>"
|
||||
if (show_message)
|
||||
player.current << "<span class='danger'><font size = 3>You are no longer a [role_text]!</font></span>"
|
||||
current_antagonists -= player
|
||||
faction_members -= player
|
||||
player.special_role = null
|
||||
update_icons_removed(player)
|
||||
BITSET(player.current.hud_updateflag, SPECIALROLE_HUD)
|
||||
|
||||
if (!is_special_character(player))
|
||||
if (!is_special_character(player) && !player.current.client.holder)
|
||||
player.current.client.verbs -= /client/proc/aooc
|
||||
|
||||
return 1
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
player.drop_from_inventory(thing)
|
||||
if(thing.loc != player)
|
||||
qdel(thing)
|
||||
player.species.equip_survival_gear(player)
|
||||
return 1
|
||||
|
||||
/datum/antagonist/proc/unequip(var/mob/living/carbon/human/player)
|
||||
if(!istype(player))
|
||||
return 0
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
set category = "Abilities"
|
||||
if(!M.mind)
|
||||
return
|
||||
for (var/obj/item/weapon/implant/loyalty/I in M)
|
||||
if (I.implanted)
|
||||
src << "<span class='warning'>[M] is too loyal to the company!</span>"
|
||||
return
|
||||
convert_to_faction(M.mind, revs)
|
||||
|
||||
/mob/living/proc/convert_to_faction(var/datum/mind/player, var/datum/antagonist/faction)
|
||||
|
||||
@@ -30,7 +30,7 @@ var/datum/antagonist/ert/ert
|
||||
/datum/antagonist/ert/greet(var/datum/mind/player)
|
||||
if(!..())
|
||||
return
|
||||
player.current << "The Emergency Response Team works for Asset Protection; your job is to protect NanoTrasen's assets. There is a code red alert on [station_name()], you are tasked to go and fix the problem."
|
||||
player.current << "The Emergency Response Team works for Asset Protection; your job is to protect [company_name]'s assets. There is a code red alert on [station_name()], you are tasked to go and fix the problem."
|
||||
player.current << "You should first gear up and discuss a plan with your team. More members may be joining, don't move out before you're ready."
|
||||
|
||||
/datum/antagonist/ert/equip(var/mob/living/carbon/human/player)
|
||||
|
||||
@@ -14,7 +14,8 @@ var/datum/antagonist/wizard/wizards
|
||||
hard_cap_round = 3
|
||||
initial_spawn_req = 1
|
||||
initial_spawn_target = 1
|
||||
|
||||
|
||||
faction = "Space Wizard"
|
||||
|
||||
/datum/antagonist/wizard/New()
|
||||
..()
|
||||
@@ -85,7 +86,8 @@ var/datum/antagonist/wizard/wizards
|
||||
if(wizard_mob.backbag == 5) wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/duffel/wizard(wizard_mob), slot_back)
|
||||
wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box(wizard_mob), slot_in_backpack)
|
||||
wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/teleportation_scroll(wizard_mob), slot_r_store)
|
||||
wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/spellbook(wizard_mob), slot_r_hand)
|
||||
var/obj/item/I = new /obj/item/weapon/spellbook(get_turf(wizard_mob))
|
||||
wizard_mob.put_in_hands(I)
|
||||
wizard_mob.update_icons()
|
||||
return 1
|
||||
|
||||
@@ -100,6 +102,22 @@ var/datum/antagonist/wizard/wizards
|
||||
feedback_set_details("round_end_result","loss - wizard killed")
|
||||
world << "<span class='danger'><font size = 3>The [(current_antagonists.len>1)?"[role_text_plural] have":"[role_text] has"] been killed by the crew! The Space Wizards Federation has been taught a lesson they will not soon forget!</font></span>"
|
||||
|
||||
/datum/antagonist/wizard/print_player_summary()
|
||||
..()
|
||||
for(var/p in current_antagonists)
|
||||
var/datum/mind/player = p
|
||||
var/text = "<b>[player.name]'s spells were:</b>"
|
||||
if(!player.learned_spells || !player.learned_spells.len)
|
||||
text += "<br>None!"
|
||||
else
|
||||
for(var/s in player.learned_spells)
|
||||
var/spell/spell = s
|
||||
text += "<br><b>[spell.name]</b> - "
|
||||
text += "Speed: [spell.spell_levels["speed"]] Power: [spell.spell_levels["power"]]"
|
||||
text += "<br>"
|
||||
world << text
|
||||
|
||||
|
||||
//To batch-remove wizard spells. Linked to mind.dm.
|
||||
/mob/proc/spellremove()
|
||||
for(var/spell/spell_to_remove in src.spell_list)
|
||||
@@ -120,13 +138,13 @@ Made a proc so this is not repeated 14 (or more) times.*/
|
||||
|
||||
// Humans can wear clothes.
|
||||
/mob/living/carbon/human/wearing_wiz_garb()
|
||||
if(!is_wiz_garb(src.wear_suit))
|
||||
if(!is_wiz_garb(src.wear_suit) && (!src.species.hud || (slot_wear_suit in src.species.hud.equip_slots)))
|
||||
src << "<span class='warning'>I don't feel strong enough without my robe.</span>"
|
||||
return 0
|
||||
if(!is_wiz_garb(src.shoes))
|
||||
if(!is_wiz_garb(src.shoes) && (!species.hud || (slot_shoes in src.species.hud.equip_slots)))
|
||||
src << "<span class='warning'>I don't feel strong enough without my sandals.</span>"
|
||||
return 0
|
||||
if(!is_wiz_garb(src.head))
|
||||
if(!is_wiz_garb(src.head) && (!species.hud || (slot_head in src.species.hud.equip_slots)))
|
||||
src << "<span class='warning'>I don't feel strong enough without my hat.</span>"
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -6,6 +6,12 @@ var/datum/antagonist/cultist/cult
|
||||
if(player.mind in cult.current_antagonists)
|
||||
return 1
|
||||
|
||||
/proc/iscult(var/mob/test)
|
||||
if (test.faction == "cult")
|
||||
return 1
|
||||
|
||||
else return iscultist(test)
|
||||
|
||||
/datum/antagonist/cultist
|
||||
id = MODE_CULTIST
|
||||
role_text = "Cultist"
|
||||
@@ -104,11 +110,15 @@ var/datum/antagonist/cultist/cult
|
||||
player.memory = ""
|
||||
if(show_message)
|
||||
player.current.visible_message("<FONT size = 3>[player.current] looks like they just reverted to their old faith!</FONT>")
|
||||
if(. && player.current && !istype(player.current, /mob/living/simple_animal/construct))
|
||||
player.current.remove_language(LANGUAGE_CULT)
|
||||
|
||||
/datum/antagonist/cultist/add_antagonist(var/datum/mind/player)
|
||||
. = ..()
|
||||
if(.)
|
||||
player << "You catch a glimpse of the Realm of Nar-Sie, the Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of That Which Waits. Assist your new compatriots in their dark dealings. Their goals are yours, and yours are theirs. You serve the Dark One above all else. Bring It back."
|
||||
if(player.current && !istype(player.current, /mob/living/simple_animal/construct))
|
||||
player.current.add_language(LANGUAGE_CULT)
|
||||
|
||||
/datum/antagonist/cultist/can_become_antag(var/datum/mind/player, ignore_role = 1)
|
||||
if(!..())
|
||||
|
||||
@@ -28,8 +28,8 @@ var/datum/antagonist/revolutionary/revs
|
||||
faction_indicator = "rev"
|
||||
faction_invisible = 1
|
||||
|
||||
restricted_jobs = list("Internal Affairs Agent", "AI", "Cyborg","Captain", "Head of Personnel", "Head of Security", "Chief Engineer", "Research Director", "Chief Medical Officer")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective")
|
||||
restricted_jobs = list("AI", "Cyborg")
|
||||
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Personnel", "Chief Engineer", "Research Director", "Chief Medical Officer", "Captain", "Head of Security", "Internal Affairs Agent")
|
||||
|
||||
/datum/antagonist/revolutionary/New()
|
||||
..()
|
||||
@@ -46,3 +46,11 @@ var/datum/antagonist/revolutionary/revs
|
||||
rev_obj.target = player.mind
|
||||
rev_obj.explanation_text = "Assassinate, capture or convert [player.real_name], the [player.mind.assigned_role]."
|
||||
global_objectives += rev_obj
|
||||
|
||||
/datum/antagonist/revolutionary/can_become_antag(var/datum/mind/player)
|
||||
if(!..())
|
||||
return 0
|
||||
for(var/obj/item/weapon/implant/loyalty/L in player.current)
|
||||
if(L && (L.imp_in == player.current))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
@@ -2,8 +2,8 @@ var/datum/antagonist/thrall/vampire_thrall = null
|
||||
|
||||
/datum/antagonist/thrall
|
||||
id = MODE_THRALL
|
||||
role_text = "thrall"
|
||||
role_text_plural = "thralls"
|
||||
role_text = "Thrall"
|
||||
role_text_plural = "Thralls"
|
||||
bantype = "vampires"
|
||||
feedback_tag = "thrall_objective"
|
||||
restricted_jobs = list("AI", "Cyborg", "Chaplain")
|
||||
|
||||
@@ -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
|
||||
@@ -350,7 +350,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
|
||||
@@ -389,7 +389,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
|
||||
@@ -444,7 +444,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
|
||||
|
||||
@@ -468,7 +468,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
|
||||
|
||||
@@ -477,7 +477,7 @@ area/space/atmosalert()
|
||||
|
||||
/area/acting/stage
|
||||
name = "\improper Stage"
|
||||
lighting_use_dynamic = 1
|
||||
dynamic_lighting = 1
|
||||
icon_state = "yellow"
|
||||
|
||||
|
||||
@@ -544,7 +544,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
|
||||
@@ -676,6 +676,13 @@ area/space/atmosalert()
|
||||
flags = RAD_SHIELDED
|
||||
sound_env = TUNNEL_ENCLOSED
|
||||
turf_initializer = new /datum/turf_initializer/maintenance()
|
||||
ambience = list(
|
||||
'sound/ambience/ambimaint1.ogg',
|
||||
'sound/ambience/ambimaint2.ogg',
|
||||
'sound/ambience/ambimaint3.ogg',
|
||||
'sound/ambience/ambimaint4.ogg',
|
||||
'sound/ambience/ambimaint5.ogg'
|
||||
)
|
||||
|
||||
/area/maintenance/aft
|
||||
name = "Aft Maintenance"
|
||||
@@ -1063,7 +1070,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
|
||||
|
||||
@@ -1133,13 +1140,19 @@ area/space/atmosalert()
|
||||
/area/engineering/
|
||||
name = "\improper Engineering"
|
||||
icon_state = "engineering"
|
||||
ambience = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
|
||||
ambience = list(
|
||||
'sound/ambience/ambisin1.ogg',
|
||||
'sound/ambience/ambisin2.ogg',
|
||||
'sound/ambience/ambisin3.ogg',
|
||||
'sound/ambience/ambisin4.ogg'
|
||||
)
|
||||
|
||||
/area/engineering/atmos
|
||||
name = "\improper Atmospherics"
|
||||
icon_state = "atmos"
|
||||
sound_env = LARGE_ENCLOSED
|
||||
no_light_control = 1
|
||||
name = "\improper Atmospherics"
|
||||
icon_state = "atmos"
|
||||
sound_env = LARGE_ENCLOSED
|
||||
no_light_control = 1
|
||||
ambience = list('sound/ambience/ambiatm1.ogg')
|
||||
|
||||
/area/engineering/atmos/monitoring
|
||||
name = "\improper Atmospherics Monitoring Room"
|
||||
@@ -1217,7 +1230,6 @@ area/space/atmosalert()
|
||||
/area/solar
|
||||
requires_power = 1
|
||||
always_unpowered = 1
|
||||
lighting_use_dynamic = 0
|
||||
base_turf = /turf/space
|
||||
|
||||
auxport
|
||||
@@ -1580,6 +1592,7 @@ area/space/atmosalert()
|
||||
/area/hydroponics
|
||||
name = "\improper Hydroponics"
|
||||
icon_state = "hydro"
|
||||
no_light_control = TRUE
|
||||
|
||||
/area/hydroponics/garden
|
||||
name = "\improper Garden"
|
||||
@@ -1613,10 +1626,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"
|
||||
@@ -1949,25 +1964,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"
|
||||
@@ -2143,7 +2158,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
|
||||
@@ -2265,7 +2280,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
|
||||
|
||||
+34
-14
@@ -6,9 +6,10 @@
|
||||
/area
|
||||
var/global/global_uid = 0
|
||||
var/uid
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
|
||||
/area/New()
|
||||
icon_state = ""
|
||||
icon_state = "white"
|
||||
layer = 10
|
||||
uid = ++global_uid
|
||||
all_areas += src
|
||||
@@ -18,7 +19,7 @@
|
||||
power_equip = 0
|
||||
power_environ = 0
|
||||
|
||||
if(lighting_use_dynamic)
|
||||
if(dynamic_lighting)
|
||||
luminosity = 0
|
||||
else
|
||||
luminosity = 1
|
||||
@@ -148,21 +149,40 @@
|
||||
D.open()
|
||||
return
|
||||
|
||||
#define DO_PARTY(COLOR) animate(color = COLOR, time = 0.5 SECONDS, easing = QUAD_EASING)
|
||||
|
||||
/area/proc/updateicon()
|
||||
if ((fire || eject || party) && (!requires_power||power_environ) && !istype(src, /area/space))//If it doesn't require power, can still activate this proc.
|
||||
if(fire && !eject && !party)
|
||||
icon_state = "blue"
|
||||
/*else if(atmosalm && !fire && !eject && !party)
|
||||
icon_state = "bluenew"*/
|
||||
else if(!fire && eject && !party)
|
||||
icon_state = "red"
|
||||
else if(party && !fire && !eject)
|
||||
icon_state = "party"
|
||||
if(fire && !eject && !party) // FIRE
|
||||
color = "#ff9292"
|
||||
animate(src) // stop any current animations.
|
||||
animate(src, color = "#ffa5b2", time = 1 SECOND, loop = -1, easing = SINE_EASING)
|
||||
animate(color = "#ff9292", time = 1 SECOND, easing = SINE_EASING)
|
||||
else if(!fire && eject && !party) // EJECT
|
||||
color = "#ff9292"
|
||||
animate(src)
|
||||
animate(src, color = "#bc8a81", time = 1 SECOND, loop = -1, easing = EASE_IN|CUBIC_EASING)
|
||||
animate(color = "#ff9292", time = 0.5 SECOND, easing = EASE_OUT|CUBIC_EASING)
|
||||
else if(party && !fire && !eject) // PARTY
|
||||
color = "#ff728e"
|
||||
animate(src)
|
||||
animate(src, color = "#7272ff", time = 0.5 SECONDS, loop = -1, easing = QUAD_EASING)
|
||||
DO_PARTY("#72aaff")
|
||||
DO_PARTY("#ffc68e")
|
||||
DO_PARTY("#72c6ff")
|
||||
DO_PARTY("#ff72e2")
|
||||
DO_PARTY("#72ff8e")
|
||||
DO_PARTY("#ffff8e")
|
||||
DO_PARTY("#ff728e")
|
||||
else
|
||||
icon_state = "blue-red"
|
||||
color = "#ffb2b2"
|
||||
animate(src)
|
||||
animate(src, color = "#B3DFFF", time = 0.5 SECOND, loop = -1, easing = SINE_EASING)
|
||||
animate(color = "#ffb2b2", time = 0.5 SECOND, loop = -1, easing = SINE_EASING)
|
||||
else
|
||||
// new lighting behaviour with obj lights
|
||||
icon_state = null
|
||||
animate(src, color = "#FFFFFF", time = 0.5 SECONDS, easing = QUAD_EASING) // Stop the animation.
|
||||
|
||||
#undef DO_PARTY
|
||||
|
||||
|
||||
/*
|
||||
@@ -353,4 +373,4 @@ var/list/mob/living/forced_ambiance_list = new
|
||||
turfs += F
|
||||
if (turfs.len)
|
||||
return pick(turfs)
|
||||
else return null
|
||||
else return null
|
||||
|
||||
+8
-2
@@ -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)
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -59,9 +59,7 @@
|
||||
C.prefs.be_special_role ^= MODE_MERCENARY
|
||||
|
||||
obj/item/weapon/antag_spawner/borg_tele/spawn_antag(client/C, turf/T)
|
||||
var/datum/effect/effect/system/spark_spread/S = new /datum/effect/effect/system/spark_spread
|
||||
S.set_up(4, 1, src)
|
||||
S.start()
|
||||
spark(T, 4, alldirs)
|
||||
var/mob/living/silicon/robot/H = new /mob/living/silicon/robot/syndicate(T)
|
||||
H.key = C.key
|
||||
var/newname = sanitizeSafe(input(H,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN)
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/obj/item/weapon/melee/arm_blade
|
||||
name = "arm blade"
|
||||
desc = "A grotesque blade made out of bone and flesh that cleaves through people as a hot knife through butter."
|
||||
icon = 'icons/obj/changeling.dmi'
|
||||
icon_state = "arm_blade"
|
||||
item_state = "arm_blade"
|
||||
contained_sprite = 1
|
||||
w_class = 4
|
||||
force = 30
|
||||
sharp = 1
|
||||
edge = 1
|
||||
anchored = 1
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
can_embed = 0
|
||||
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
|
||||
var/mob/living/creator
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/New()
|
||||
processing_objects |= src
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/Destroy()
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/dropped()
|
||||
visible_message("<span class='danger'>With a sickening crunch, [user] reforms their arm blade into an arm!</span>",
|
||||
"<span class='notice'>We assimilate the weapon back into our body.</span>",
|
||||
"<span class='warning'>You hear organic matter ripping and tearing!</span>")
|
||||
playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
spawn(1) if(src) qdel(src)
|
||||
|
||||
/obj/item/weapon/melee/arm_blade/process()
|
||||
if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src))
|
||||
// Tidy up a bit.
|
||||
if(istype(loc,/mob/living))
|
||||
var/mob/living/carbon/human/host = loc
|
||||
if(istype(host))
|
||||
for(var/obj/item/organ/external/organ in host.organs)
|
||||
for(var/obj/item/O in organ.implants)
|
||||
if(O == src)
|
||||
organ.implants -= src
|
||||
host.pinned -= src
|
||||
host.embedded -= src
|
||||
host.drop_from_inventory(src)
|
||||
spawn(1) if(src) qdel(src)
|
||||
|
||||
/obj/item/weapon/shield/riot/changeling
|
||||
name = "shield-like mass"
|
||||
desc = "A mass of tough, boney tissue. You can still see the fingers as a twisted pattern in the shield."
|
||||
icon = 'icons/obj/changeling.dmi'
|
||||
icon_state = "ling_shield"
|
||||
item_state = "ling_shield"
|
||||
contained_sprite = 1
|
||||
slot_flags = null
|
||||
anchored = 1
|
||||
throwforce = 0 //Just to be on the safe side
|
||||
throw_range = 0
|
||||
throw_speed = 0
|
||||
can_embed = 0
|
||||
var/mob/living/creator
|
||||
|
||||
/obj/item/weapon/shield/riot/changeling/New()
|
||||
processing_objects |= src
|
||||
|
||||
/obj/item/weapon/shield/riot/changeling/Destroy()
|
||||
processing_objects -= src
|
||||
..()
|
||||
|
||||
/obj/item/weapon/shield/riot/changeling/dropped()
|
||||
visible_message("<span class='danger'>With a sickening crunch, [user] reforms their arm blade into an arm!</span>",
|
||||
"<span class='notice'>We assimilate the weapon back into our body.</span>",
|
||||
"<span class='warning'>You hear organic matter ripping and tearing!</span>")
|
||||
playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
spawn(1) if(src) qdel(src)
|
||||
|
||||
/obj/item/weapon/shield/riot/changeling/process()
|
||||
if(!creator || loc != creator || (creator.l_hand != src && creator.r_hand != src))
|
||||
// Tidy up a bit.
|
||||
if(istype(loc,/mob/living))
|
||||
var/mob/living/carbon/human/host = loc
|
||||
if(istype(host))
|
||||
for(var/obj/item/organ/external/organ in host.organs)
|
||||
for(var/obj/item/O in organ.implants)
|
||||
if(O == src)
|
||||
organ.implants -= src
|
||||
host.pinned -= src
|
||||
host.embedded -= src
|
||||
host.drop_from_inventory(src)
|
||||
spawn(1) if(src) qdel(src)
|
||||
@@ -1,8 +1,7 @@
|
||||
var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega")
|
||||
|
||||
/datum/changeling //stores changeling powers, changeling recharge thingie, changeling absorbed DNA and changeling ID (for changeling hivemind)
|
||||
var/list/absorbed_dna = list()
|
||||
var/list/absorbed_species = list()
|
||||
var/list/datum/absorbed_dna/absorbed_dna = list()
|
||||
var/list/absorbed_languages = list()
|
||||
var/absorbedcount = 0
|
||||
var/chem_charges = 20
|
||||
@@ -31,12 +30,24 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
geneticdamage = max(0, geneticdamage-1)
|
||||
|
||||
/datum/changeling/proc/GetDNA(var/dna_owner)
|
||||
var/datum/dna/chosen_dna
|
||||
for(var/datum/dna/DNA in absorbed_dna)
|
||||
if(dna_owner == DNA.real_name)
|
||||
chosen_dna = DNA
|
||||
break
|
||||
return chosen_dna
|
||||
for(var/datum/absorbed_dna/DNA in absorbed_dna)
|
||||
if(dna_owner == DNA.name)
|
||||
return DNA
|
||||
|
||||
/mob/proc/absorbDNA(var/datum/absorbed_dna/newDNA)
|
||||
var/datum/changeling/changeling = null
|
||||
if(src.mind && src.mind.changeling)
|
||||
changeling = src.mind.changeling
|
||||
if(!changeling)
|
||||
return
|
||||
|
||||
for(var/language in newDNA.languages)
|
||||
changeling.absorbed_languages |= language
|
||||
|
||||
changeling_update_languages(changeling.absorbed_languages)
|
||||
|
||||
if(!changeling.GetDNA(newDNA.name)) // Don't duplicate - I wonder if it's possible for it to still be a different DNA? DNA code could use a rewrite
|
||||
changeling.absorbed_dna += newDNA
|
||||
|
||||
//Restores our verbs. It will only restore verbs allowed during lesser (monkey) form if we are not human
|
||||
/mob/proc/make_changeling()
|
||||
@@ -65,14 +76,13 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
if(!(P in src.verbs))
|
||||
src.verbs += P.verbpath
|
||||
|
||||
mind.changeling.absorbed_dna |= dna
|
||||
for(var/language in languages)
|
||||
mind.changeling.absorbed_languages |= language
|
||||
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(istype(H))
|
||||
mind.changeling.absorbed_species += H.species.name
|
||||
|
||||
for(var/language in languages)
|
||||
mind.changeling.absorbed_languages |= language
|
||||
var/datum/absorbed_dna/newDNA = new(H.real_name, H.dna, H.species.name, H.languages)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
return 1
|
||||
|
||||
@@ -83,13 +93,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
if(P.isVerb)
|
||||
verbs -= P.verbpath
|
||||
|
||||
//removes changeling powers but keeps those with allowduringlesserform
|
||||
/mob/proc/remove_changeling_powers_monkey()
|
||||
if(!mind || !mind.changeling) return
|
||||
for(var/datum/power/changeling/P in mind.changeling.purchasedpowers)
|
||||
if(P.isVerb && (P.allowduringlesserform == 0))
|
||||
verbs -= P.verbpath
|
||||
|
||||
|
||||
//Helper proc. Does all the checks and stuff for us to avoid copypasta
|
||||
/mob/proc/changeling_power(var/required_chems=0, var/required_dna=0, var/max_genetic_damage=100, var/max_stat=0)
|
||||
@@ -133,46 +136,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
|
||||
return
|
||||
|
||||
//Used to switch species based on the changeling datum.
|
||||
/mob/proc/changeling_change_species()
|
||||
|
||||
set category = "Changeling"
|
||||
set name = "Change Species (5)"
|
||||
|
||||
var/mob/living/carbon/human/H = src
|
||||
if(!istype(H))
|
||||
src << "<span class='warning'>We may only use this power while in humanoid form.</span>"
|
||||
return
|
||||
|
||||
var/datum/changeling/changeling = changeling_power(5,1,0)
|
||||
if(!changeling) return
|
||||
|
||||
if(changeling.absorbed_species.len < 2)
|
||||
src << "<span class='warning'>We do not know of any other species genomes to use.</span>"
|
||||
return
|
||||
|
||||
var/S = input("Select the target species: ", "Target Species", null) as null|anything in changeling.absorbed_species
|
||||
if(!S) return
|
||||
|
||||
domutcheck(src, null)
|
||||
|
||||
changeling.chem_charges -= 5
|
||||
changeling.geneticdamage = 30
|
||||
|
||||
src.visible_message("<span class='warning'>[src] transforms!</span>")
|
||||
|
||||
src.verbs -= /mob/proc/changeling_change_species
|
||||
H.set_species(S,1) //Until someone moves body colour into DNA, they're going to have to use the default.
|
||||
|
||||
spawn(10)
|
||||
src.verbs += /mob/proc/changeling_change_species
|
||||
src.regenerate_icons()
|
||||
|
||||
changeling_update_languages(changeling.absorbed_languages)
|
||||
feedback_add_details("changeling_powers","TR")
|
||||
|
||||
return 1
|
||||
|
||||
//Absorbs the victim's DNA making them uncloneable. Requires a strong grip on the victim.
|
||||
//Doesn't cost anything as it's the most basic ability.
|
||||
/mob/proc/changeling_absorb_dna()
|
||||
@@ -196,6 +159,10 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
src << "<span class='warning'>We do not know how to parse this creature's DNA!</span>"
|
||||
return
|
||||
|
||||
if(islesserform(T))
|
||||
src << "<span class='warning'>This creature DNA is not compatible with our form!</span>"
|
||||
return
|
||||
|
||||
if(HUSK in T.mutations)
|
||||
src << "<span class='warning'>This creature's DNA is ruined beyond useability!</span>"
|
||||
return
|
||||
@@ -213,6 +180,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
switch(stage)
|
||||
if(1)
|
||||
src << "<span class='notice'>This creature is compatible. We must hold still...</span>"
|
||||
src.visible_message("<span class='warning'>[src]'s skin begins to shift and squirm!</span>")
|
||||
if(2)
|
||||
src << "<span class='notice'>We extend a proboscis.</span>"
|
||||
src.visible_message("<span class='warning'>[src] extends a proboscis!</span>")
|
||||
@@ -234,9 +202,6 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
src.visible_message("<span class='danger'>[src] sucks the fluids from [T]!</span>")
|
||||
T << "<span class='danger'>You have been absorbed by the changeling!</span>"
|
||||
|
||||
T.dna.real_name = T.real_name //Set this again, just to be sure that it's properly set.
|
||||
changeling.absorbed_dna |= T.dna
|
||||
if(src.nutrition < max_nutrition) src.nutrition = min((nutrition + T.nutrition), max_nutrition)
|
||||
changeling.chem_charges += 10
|
||||
changeling.geneticpoints += 2
|
||||
|
||||
@@ -247,16 +212,15 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
|
||||
changeling_update_languages(changeling.absorbed_languages)
|
||||
|
||||
//Steal their species!
|
||||
if(T.species && !(T.species.name in changeling.absorbed_species))
|
||||
changeling.absorbed_species += T.species.name
|
||||
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
if(T.mind && T.mind.changeling)
|
||||
if(T.mind.changeling.absorbed_dna)
|
||||
for(var/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
|
||||
if(dna_data in changeling.absorbed_dna)
|
||||
for(var/datum/absorbed_dna/dna_data in T.mind.changeling.absorbed_dna) //steal all their loot
|
||||
if(changeling.GetDNA(dna_data.name))
|
||||
continue
|
||||
changeling.absorbed_dna += dna_data
|
||||
absorbDNA(dna_data)
|
||||
changeling.absorbedcount++
|
||||
T.mind.changeling.absorbed_dna.len = 1
|
||||
|
||||
@@ -295,31 +259,44 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
if(!changeling) return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/dna/DNA in changeling.absorbed_dna)
|
||||
names += "[DNA.real_name]"
|
||||
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
|
||||
names += "[DNA.name]"
|
||||
|
||||
var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
|
||||
if(!S) return
|
||||
|
||||
var/datum/dna/chosen_dna = changeling.GetDNA(S)
|
||||
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
return
|
||||
|
||||
changeling.chem_charges -= 5
|
||||
src.visible_message("<span class='warning'>[src] transforms!</span>")
|
||||
changeling.geneticdamage = 30
|
||||
src.dna = chosen_dna.Clone()
|
||||
src.real_name = chosen_dna.real_name
|
||||
src.flavor_text = ""
|
||||
src.UpdateAppearance()
|
||||
domutcheck(src, null)
|
||||
|
||||
handle_changeling_transform(chosen_dna)
|
||||
|
||||
src.verbs -= /mob/proc/changeling_transform
|
||||
spawn(10) src.verbs += /mob/proc/changeling_transform
|
||||
spawn(10)
|
||||
src.verbs += /mob/proc/changeling_transform
|
||||
|
||||
changeling_update_languages(changeling.absorbed_languages)
|
||||
|
||||
feedback_add_details("changeling_powers","TR")
|
||||
return 1
|
||||
|
||||
/mob/proc/handle_changeling_transform(var/datum/absorbed_dna/chosen_dna)
|
||||
src.visible_message("<span class='warning'>[src] transforms!</span>")
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
var/newSpecies = chosen_dna.speciesName
|
||||
H.set_species(newSpecies,1)
|
||||
|
||||
src.dna = chosen_dna.dna
|
||||
src.real_name = chosen_dna.name
|
||||
src.flavor_text = ""
|
||||
domutcheck(src, null)
|
||||
src.UpdateAppearance()
|
||||
|
||||
|
||||
//Transform into a monkey.
|
||||
/mob/proc/changeling_lesser_form()
|
||||
@@ -340,15 +317,10 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
return
|
||||
|
||||
changeling.chem_charges--
|
||||
H.remove_changeling_powers_monkey() //we weren't making us of allowduringlesserform before for some reason? -Ryan784
|
||||
H.visible_message("<span class='warning'>[H] transforms!</span>")
|
||||
changeling.geneticdamage = 30
|
||||
H << "<span class='warning'>Our genes cry out!</span>"
|
||||
var/list/implants = list() //Try to preserve implants.
|
||||
for(var/obj/item/weapon/implant/W in H)
|
||||
implants += W
|
||||
H.monkeyize()
|
||||
verbs += /mob/proc/changeling_lesser_transform //allow us to actually transform BACK into a human - Ryan784
|
||||
H = H.monkeyize()
|
||||
feedback_add_details("changeling_powers","LF")
|
||||
return 1
|
||||
|
||||
@@ -457,25 +429,29 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
// charge the changeling chemical cost for stasis
|
||||
changeling.chem_charges -= 20
|
||||
|
||||
// restore us to health
|
||||
C.revive()
|
||||
|
||||
// remove our fake death flag
|
||||
C.status_flags &= ~(FAKEDEATH)
|
||||
|
||||
// let us move again
|
||||
C.update_canmove()
|
||||
|
||||
// re-add out changeling powers
|
||||
C.make_changeling()
|
||||
|
||||
// sending display messages
|
||||
C << "<span class='notice'>We have regenerated.</span>"
|
||||
|
||||
C << "<span class='notice'><font size='5'>We are ready to rise. Use the <b>Revive</b> verb when you are ready.</font></span>"
|
||||
C.verbs += /mob/proc/changeling_revive
|
||||
|
||||
feedback_add_details("changeling_powers","FD")
|
||||
return 1
|
||||
|
||||
/mob/proc/changeling_revive()
|
||||
set category = "Changeling"
|
||||
set name = "Revive"
|
||||
|
||||
var/mob/living/carbon/C = src
|
||||
// restore us to health
|
||||
C.revive()
|
||||
// remove our fake death flag
|
||||
C.status_flags &= ~(FAKEDEATH)
|
||||
// let us move again
|
||||
C.update_canmove()
|
||||
// re-add out changeling powers
|
||||
C.make_changeling()
|
||||
// sending display messages
|
||||
C << "<span class='notice'>We have regenerated.</span>"
|
||||
C.verbs -= /mob/proc/changeling_revive
|
||||
|
||||
|
||||
//Boosts the range of your next sting attack by 1
|
||||
/mob/proc/changeling_boost_range()
|
||||
@@ -581,7 +557,7 @@ var/global/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","E
|
||||
|
||||
// HIVE MIND UPLOAD/DOWNLOAD DNA
|
||||
|
||||
var/list/datum/dna/hivemind_bank = list()
|
||||
var/list/datum/absorbed_dna/hivemind_bank = list()
|
||||
|
||||
/mob/proc/changeling_hiveupload()
|
||||
set category = "Changeling"
|
||||
@@ -592,9 +568,14 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
if(!changeling) return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/dna/DNA in changeling.absorbed_dna)
|
||||
if(!(DNA in hivemind_bank))
|
||||
names += DNA.real_name
|
||||
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
|
||||
var/valid = 1
|
||||
for(var/datum/absorbed_dna/DNB in hivemind_bank)
|
||||
if(DNA.name == DNB.name)
|
||||
valid = 0
|
||||
break
|
||||
if(valid)
|
||||
names += DNA.name
|
||||
|
||||
if(names.len <= 0)
|
||||
src << "<span class='notice'>The airwaves already have all of our DNA.</span>"
|
||||
@@ -603,7 +584,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
var/S = input("Select a DNA to channel: ", "Channel DNA", null) as null|anything in names
|
||||
if(!S) return
|
||||
|
||||
var/datum/dna/chosen_dna = changeling.GetDNA(S)
|
||||
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
return
|
||||
|
||||
@@ -622,9 +603,9 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
if(!changeling) return
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/dna/DNA in hivemind_bank)
|
||||
if(!(DNA in changeling.absorbed_dna))
|
||||
names[DNA.real_name] = DNA
|
||||
for(var/datum/absorbed_dna/DNA in hivemind_bank)
|
||||
if(!(changeling.GetDNA(DNA.name)))
|
||||
names[DNA.name] = DNA
|
||||
|
||||
if(names.len <= 0)
|
||||
src << "<span class='notice'>There's no new DNA to absorb from the air.</span>"
|
||||
@@ -637,7 +618,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
return
|
||||
|
||||
changeling.chem_charges -= 20
|
||||
changeling.absorbed_dna += chosen_dna
|
||||
absorbDNA(chosen_dna)
|
||||
src << "<span class='notice'>We absorb the DNA of [S] from the air.</span>"
|
||||
feedback_add_details("changeling_powers","HD")
|
||||
return 1
|
||||
@@ -692,7 +673,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
return 1
|
||||
|
||||
//Handles the general sting code to reduce on copypasta (seeming as somebody decided to make SO MANY dumb abilities)
|
||||
/mob/proc/changeling_sting(var/required_chems=0, var/verb_path)
|
||||
/mob/proc/changeling_sting(var/required_chems=0, var/verb_path, var/stealthy = 0)
|
||||
var/datum/changeling/changeling = changeling_power(required_chems)
|
||||
if(!changeling) return
|
||||
|
||||
@@ -711,9 +692,20 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
src.verbs -= verb_path
|
||||
spawn(10) src.verbs += verb_path
|
||||
|
||||
src << "<span class='notice'>We stealthily sting [T].</span>"
|
||||
if(stealthy == 1)
|
||||
src << "<span class='notice'>We stealthily sting [T].</span>"
|
||||
T << "<span class='warning'>You feel a tiny prick.</span>"
|
||||
else
|
||||
src.visible_message(pick("<span class='danger'>[src]'s eyes balloon and burst out in a welter of blood, burrowing into [T]!</span>",
|
||||
"<span class='danger'>[src]'s arm rapidly shifts into a giant scorpion-stinger and stabs into [T]!</span>",
|
||||
"<span class='danger'>[src]'s throat lengthens and twists before vomitting a chunky red spew all over [T]!</span>",
|
||||
"<span class='danger'>[src]'s tongue stretches an impossible length and stabs into [T]!</span>",
|
||||
"<span class='danger'>[src] sneezes a cloud of shrieking spiders at [T]!</span>",
|
||||
"<span class='danger'>[src] erupts a grotesque tail and impales [T]!</span>",
|
||||
"<span class='danger'>[src]'s chin skin bulges and tears, launching a bone-dart at [T]!</span>"))
|
||||
|
||||
if(!T.mind || !T.mind.changeling) return T //T will be affected by the sting
|
||||
T << "<span class='warning'>You feel a tiny prick.</span>"
|
||||
|
||||
return
|
||||
|
||||
|
||||
@@ -722,7 +714,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Hallucination Sting (15)"
|
||||
set desc = "Causes terror in the target."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting)
|
||||
var/mob/living/carbon/T = changeling_sting(15,/mob/proc/changeling_lsdsting,stealthy = 1)
|
||||
if(!T) return 0
|
||||
spawn(rand(300,600))
|
||||
if(T) T.hallucination += 400
|
||||
@@ -734,7 +726,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Silence sting (10)"
|
||||
set desc="Sting target"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(10,/mob/proc/changeling_silence_sting,stealthy = 1)
|
||||
if(!T) return 0
|
||||
T.silent += 30
|
||||
feedback_add_details("changeling_powers","SS")
|
||||
@@ -745,7 +737,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Blind sting (20)"
|
||||
set desc="Sting target"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(20,/mob/proc/changeling_blind_sting,stealthy = 0)
|
||||
if(!T) return 0
|
||||
T << "<span class='danger'>Your eyes burn horrificly!</span>"
|
||||
T.disabilities |= NEARSIGHTED
|
||||
@@ -760,7 +752,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Deaf sting (5)"
|
||||
set desc="Sting target:"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_deaf_sting,stealthy = 0)
|
||||
if(!T) return 0
|
||||
T << "<span class='danger'>Your ears pop and begin ringing loudly!</span>"
|
||||
T.sdisabilities |= DEAF
|
||||
@@ -773,7 +765,7 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Paralysis sting (30)"
|
||||
set desc="Sting target"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(30,/mob/proc/changeling_paralysis_sting,stealthy = 0)
|
||||
if(!T) return 0
|
||||
T << "<span class='danger'>Your muscles begin to painfully tighten.</span>"
|
||||
T.Weaken(20)
|
||||
@@ -788,29 +780,25 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
var/datum/changeling/changeling = changeling_power(40)
|
||||
if(!changeling) return 0
|
||||
|
||||
|
||||
|
||||
var/list/names = list()
|
||||
for(var/datum/dna/DNA in changeling.absorbed_dna)
|
||||
names += "[DNA.real_name]"
|
||||
for(var/datum/absorbed_dna/DNA in changeling.absorbed_dna)
|
||||
names += "[DNA.name]"
|
||||
|
||||
var/S = input("Select the target DNA: ", "Target DNA", null) as null|anything in names
|
||||
if(!S) return
|
||||
|
||||
var/datum/dna/chosen_dna = changeling.GetDNA(S)
|
||||
var/datum/absorbed_dna/chosen_dna = changeling.GetDNA(S)
|
||||
if(!chosen_dna)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_transformation_sting,stealthy = 1)
|
||||
if(!T) return 0
|
||||
if((HUSK in T.mutations) || (!ishuman(T) && !issmall(T)))
|
||||
src << "<span class='warning'>Our sting appears ineffective against its DNA.</span>"
|
||||
return 0
|
||||
T.visible_message("<span class='warning'>[T] transforms!</span>")
|
||||
T.dna = chosen_dna.Clone()
|
||||
T.real_name = chosen_dna.real_name
|
||||
T.UpdateAppearance()
|
||||
domutcheck(T, null)
|
||||
|
||||
T.handle_changeling_transform(chosen_dna)
|
||||
|
||||
feedback_add_details("changeling_powers","TS")
|
||||
return 1
|
||||
|
||||
@@ -819,10 +807,9 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Unfat sting (5)"
|
||||
set desc = "Sting target"
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting)
|
||||
var/mob/living/carbon/T = changeling_sting(5,/mob/proc/changeling_unfat_sting,stealthy = 1)
|
||||
if(!T) return 0
|
||||
T << "<span class='danger'>you feel a small prick as stomach churns violently and you become to feel skinnier.</span>"
|
||||
T.overeatduration = 0
|
||||
T.nutrition -= 100
|
||||
feedback_add_details("changeling_powers","US")
|
||||
return 1
|
||||
@@ -832,13 +819,13 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
set name = "Death Sting (40)"
|
||||
set desc = "Causes spasms onto death."
|
||||
|
||||
var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting)
|
||||
var/mob/living/carbon/T = changeling_sting(40,/mob/proc/changeling_DEATHsting,stealthy = 0)
|
||||
if(!T) return 0
|
||||
T << "<span class='danger'>You feel a small prick and your chest becomes tight.</span>"
|
||||
T.silent = 10
|
||||
T.Paralyse(10)
|
||||
T.make_jittery(1000)
|
||||
if(T.reagents) T.reagents.add_reagent("lexorin", 40)
|
||||
if(T.reagents) T.reagents.add_reagent("cyanide", 5)
|
||||
feedback_add_details("changeling_powers","DTHS")
|
||||
return 1
|
||||
|
||||
@@ -853,13 +840,66 @@ var/list/datum/dna/hivemind_bank = list()
|
||||
if(!changeling)
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting)
|
||||
var/mob/living/carbon/human/T = changeling_sting(40, /mob/proc/changeling_extract_dna_sting,stealthy = 1)
|
||||
if(!T) return 0
|
||||
|
||||
T.dna.real_name = T.real_name
|
||||
changeling.absorbed_dna |= T.dna
|
||||
if(T.species && !(T.species.name in changeling.absorbed_species))
|
||||
changeling.absorbed_species += T.species.name
|
||||
var/datum/absorbed_dna/newDNA = new(T.real_name, T.dna, T.species.name, T.languages)
|
||||
absorbDNA(newDNA)
|
||||
|
||||
feedback_add_details("changeling_powers","ED")
|
||||
return 1
|
||||
|
||||
/mob/proc/armblades()
|
||||
set category = "Changeling"
|
||||
set name = "Form Blades"
|
||||
set desc="Rupture the flesh and mend the bone of your hand into a deadly blade."
|
||||
|
||||
var/mob/living/M = src
|
||||
|
||||
if(M.l_hand && M.r_hand)
|
||||
M << "<span class='danger'>Your hands are full.</span>"
|
||||
return
|
||||
|
||||
var/obj/item/weapon/melee/arm_blade/blade = new(M)
|
||||
blade.creator = M
|
||||
M.put_in_hands(blade)
|
||||
playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
src.visible_message("<span class='danger'>A grotesque blade forms around [M]\'s arm!</span>",
|
||||
"<span class='danger'>Our arm twists and mutates, transforming it into a deadly blade.</span>",
|
||||
"<span class='danger'>You hear organic matter ripping and tearing!</span>")
|
||||
gibs(src.loc)
|
||||
|
||||
/mob/proc/changeling_shield()
|
||||
set category = "Changeling"
|
||||
set name = "Form Shield"
|
||||
set desc="Bend the flesh and bone of your hand into a grotesque shield."
|
||||
|
||||
var/mob/living/M = src
|
||||
|
||||
if(M.l_hand && M.r_hand)
|
||||
M << "<span class='danger'>Your hands are full.</span>"
|
||||
return
|
||||
|
||||
var/obj/item/weapon/shield/riot/changeling/shield = new(M)
|
||||
shield.creator = M
|
||||
M.put_in_hands(shield)
|
||||
playsound(loc, 'sound/effects/blobattack.ogg', 30, 1)
|
||||
src.visible_message("<span class='warning'>The end of [M]\'s hand inflates rapidly, forming a huge shield-like mass!</span>",
|
||||
"<span class='warning'>We inflate our hand into a robust shield.</span>",
|
||||
"<span class='warning'>You hear organic matter ripping and tearing!</span>")
|
||||
gibs(src.loc)
|
||||
|
||||
//dna related datum
|
||||
|
||||
/datum/absorbed_dna
|
||||
var/name
|
||||
var/datum/dna/dna
|
||||
var/speciesName
|
||||
var/list/languages
|
||||
|
||||
/datum/absorbed_dna/New(var/newName, var/newDNA, var/newSpecies, var/newLanguages)
|
||||
..()
|
||||
name = newName
|
||||
dna = newDNA
|
||||
speciesName = newSpecies
|
||||
languages = newLanguages
|
||||
|
||||
@@ -26,12 +26,6 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
genomecost = 0
|
||||
verbpath = /mob/proc/changeling_transform
|
||||
|
||||
/datum/power/changeling/change_species
|
||||
name = "Change Species"
|
||||
desc = "We take on the apperance of a species that we have absorbed."
|
||||
genomecost = 0
|
||||
verbpath = /mob/proc/changeling_change_species
|
||||
|
||||
/datum/power/changeling/fakedeath
|
||||
name = "Regenerative Stasis"
|
||||
desc = "We become weakened to a death-like state, where we will rise again from death."
|
||||
@@ -64,14 +58,14 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
|
||||
/datum/power/changeling/deaf_sting
|
||||
name = "Deaf Sting"
|
||||
desc = "We silently sting a human, completely deafening them for a short time."
|
||||
desc = "We sting a human, completely deafening them for a short time."
|
||||
genomecost = 1
|
||||
allowduringlesserform = 1
|
||||
verbpath = /mob/proc/changeling_deaf_sting
|
||||
|
||||
/datum/power/changeling/blind_sting
|
||||
name = "Blind Sting"
|
||||
desc = "We silently sting a human, completely blinding them for a short time."
|
||||
desc = "We sting a human, completely blinding them for a short time."
|
||||
genomecost = 2
|
||||
allowduringlesserform = 1
|
||||
verbpath = /mob/proc/changeling_blind_sting
|
||||
@@ -108,7 +102,7 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
|
||||
/datum/power/changeling/paralysis_sting
|
||||
name = "Paralysis Sting"
|
||||
desc = "We silently sting a human, paralyzing them for a short time."
|
||||
desc = "We sting a human, paralyzing them for a short time."
|
||||
genomecost = 8
|
||||
verbpath = /mob/proc/changeling_paralysis_sting
|
||||
|
||||
@@ -121,7 +115,7 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
|
||||
/datum/power/changeling/DeathSting
|
||||
name = "Death Sting"
|
||||
desc = "We silently sting a human, filling them with potent chemicals. Their rapid death is all but assured."
|
||||
desc = "We sting a human, filling them with potent chemicals. Their rapid death is all but assured."
|
||||
genomecost = 10
|
||||
verbpath = /mob/proc/changeling_DEATHsting
|
||||
|
||||
@@ -184,7 +178,19 @@ var/list/datum/power/changeling/powerinstances = list()
|
||||
genomecost = 7
|
||||
verbpath = /mob/proc/changeling_rapidregen
|
||||
|
||||
//weapon and armor like powers
|
||||
|
||||
/datum/power/changeling/armblades
|
||||
name = "Mutate Armblades"
|
||||
desc = "Permits us to reshape our arms into a deadly blade."
|
||||
genomecost = 2
|
||||
verbpath = /mob/proc/armblades
|
||||
|
||||
/datum/power/changeling/shield
|
||||
name = "Mutate Shield"
|
||||
desc = "Permits us to bloat our hands into a robust shield."
|
||||
genomecost = 3
|
||||
verbpath = /mob/proc/changeling_shield
|
||||
|
||||
// Modularchangling, totally stolen from the new player panel. YAYY
|
||||
/datum/changeling/proc/EvolutionMenu()//The new one
|
||||
|
||||
@@ -17,59 +17,565 @@
|
||||
desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie"
|
||||
icon_state = "forge"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Cult pylons can be used as arcane defensive turrets.
|
||||
|
||||
First of all they must be empowered with a sacrifice. Any small organic creature that can be picked up is valid
|
||||
Hit the pylon with the creature - while still alive - to present it as a sacrifice, and then end its life to complete the process.
|
||||
|
||||
Once empowered, pylons will fire rapid, weak magical beams at non cult mobs.
|
||||
|
||||
As crystals, pylons are immune to energy weaponry. More than immune, they will absorb lasers and become
|
||||
supercharged for some time, boosting their damage. Pylons can only be harmed by ballistics and physical weapons
|
||||
Building reinforced windows around them is highly recommended.
|
||||
|
||||
Pylons are fairly fragile and will quickly break under direct hits.
|
||||
A damaged pylon will self repair, if it contains a soul.
|
||||
|
||||
|
||||
Pylons are largely intended as a stalling, early warning, fire support and area denial system. They are unlikely to actually
|
||||
kill anyone alone but they can keep pesky civilians away for long enough to learn runes and prepare rituals.
|
||||
|
||||
If you can get ahold of a laser rifle to supercharge them, they can even give security some pause
|
||||
|
||||
Recommended tools for combatting pylons:
|
||||
Heavy melee (fireaxe, baseball bat, etc)
|
||||
Sniper rifles
|
||||
Exosuits
|
||||
Explosives
|
||||
Ablative armour
|
||||
*/
|
||||
/obj/structure/cult/pylon
|
||||
name = "Pylon"
|
||||
desc = "A floating crystal that hums with an unearthly energy"
|
||||
icon_state = "pylon"
|
||||
description_antag = "A pylon can be upgraded into a magical defensive turret that shoots anyone opposing the cult\
|
||||
</br>Upgrading a pylon requires a sacrifice. Bring it a small organic creature, like a monkey or mouse. Use the creature on the pylon, or drag and drop to present it.\
|
||||
</br>Once the sacrifice is accepted, kill it to complete the process. This will gib its body and make a very visible mess. After this point the pylon is fixed to the floor and cant be moved\
|
||||
</br>The pylon will fire weak beams that are harmless to the cult. In addition it can be upgraded even more by shooting it with a laser, which will give it a limited number of extra-power shots."
|
||||
|
||||
icon_state = "pylonbase"
|
||||
var/isbroken = 0
|
||||
light_range = 5
|
||||
light_color = "#3e0000"
|
||||
var/obj/item/wepon = null
|
||||
var/pylonmode = 0
|
||||
//Pylon has three states:
|
||||
//0 = Idle, the pylon is an inert crystal
|
||||
//1 = Awaiting sacrifice. The pylon is actively tracking a creature to be sacrificed to it
|
||||
//2 = Turret. The pylon has been empowered by a sacrifice and is now a turret permanantly
|
||||
|
||||
var/damagetaken = 0
|
||||
var/empowered = 0 //Number of empowered, higher-damage shots remaining
|
||||
var/processing = 0
|
||||
var/mob/living/sacrifice //Holds a reference to a mob that is a pending sacrifice
|
||||
var/mob/living/sacrificer //A reference to the last mob that attempted to sacrifice something. So we can message them
|
||||
//Sacrifier is also used in target handling. the pylon will not bite the hand that feeds it. Noncultist colleagues are fair game though
|
||||
|
||||
var/next_shot = 0 //Absolute world time when we're allowed to fire again
|
||||
var/shot_delay = 5 //Minimum delay between shots, in deciseconds
|
||||
var/mob/living/target
|
||||
|
||||
var/notarget //Number of times handle_firing has been called without finding anything to shoot at
|
||||
//This is used for switching to lower-intensity processing
|
||||
|
||||
var/datum/language/cultcommon/lang
|
||||
//An instance of the cult language datum. Used to scramble speech when speaking to noncultists
|
||||
|
||||
var/turf/last_target_loc
|
||||
|
||||
var/process_interval = 1
|
||||
var/ticks
|
||||
anchored = 0
|
||||
|
||||
|
||||
//Just a subtype that starts off in turret mode. For adminbus and debugging. Maybe a future wizard spell
|
||||
//Spawn them next to ERPers
|
||||
/obj/structure/cult/pylon/turret
|
||||
pylonmode = 2
|
||||
|
||||
/obj/structure/cult/pylon/turret/New()
|
||||
..()
|
||||
start_process()
|
||||
|
||||
|
||||
//Another subtype which starts with infinite empower shots. For empowered adminbus
|
||||
/obj/structure/cult/pylon/turret/empowered
|
||||
empowered = 99999999
|
||||
|
||||
|
||||
/obj/structure/cult/pylon/New()
|
||||
..()
|
||||
lang = new /datum/language/cultcommon()
|
||||
update_icon()
|
||||
|
||||
/obj/structure/cult/pylon/examine(var/mob/user)
|
||||
..()
|
||||
if (damagetaken)
|
||||
switch (damagetaken)
|
||||
if (1 to 8)
|
||||
user << "It has very faint hairline fractures."
|
||||
if (8 to 20)
|
||||
user << "It has several cracks across its surface."
|
||||
if (20 to 30)
|
||||
user << "It is chipped and deeply cracked, it may shatter with much more pressure."
|
||||
if (30 to INFINITY)
|
||||
user << "It is almost cleaved in two, the pylon looks like it will fall to shards under its own weight."
|
||||
|
||||
|
||||
/obj/structure/cult/pylon/Move()
|
||||
..()
|
||||
last_target_loc = null
|
||||
|
||||
/obj/structure/cult/pylon/proc/start_process()
|
||||
process_interval = 1
|
||||
if (!processing)
|
||||
processing_objects += src
|
||||
processing = 1
|
||||
|
||||
|
||||
//If the pylon goes a long time without shooting anything, it will consider slowing down processing
|
||||
/obj/structure/cult/pylon/proc/reconsider_interval()
|
||||
var/mindist = INFINITY
|
||||
for (var/m in player_list)
|
||||
var/mob/living/L = m
|
||||
if (L.z != z)
|
||||
continue
|
||||
|
||||
if (L.stat == DEAD)
|
||||
continue
|
||||
|
||||
if (iscult(L))
|
||||
continue
|
||||
|
||||
if (L == sacrificer)
|
||||
continue
|
||||
|
||||
var/d = get_dist(src, L)
|
||||
if (d < mindist)
|
||||
mindist = d
|
||||
|
||||
mindist = min(150, mindist)
|
||||
process_interval = Ceiling(mindist*0.1)
|
||||
process_interval = max(1, process_interval)
|
||||
|
||||
|
||||
//Run each process loop, this function checks if we can stop processing yet.
|
||||
//Returns 0 if its time to stop. Returns 1 if we should keep going.
|
||||
/obj/structure/cult/pylon/proc/check_process()
|
||||
if (isbroken)
|
||||
return 0
|
||||
|
||||
if (pylonmode == 2)
|
||||
return 1
|
||||
|
||||
if (pylonmode == 1)
|
||||
if (sacrifice)
|
||||
return 1
|
||||
|
||||
if (empowered > 0)
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
/obj/structure/cult/pylon/process()
|
||||
ticks++
|
||||
if(!check_process())
|
||||
processing_objects.Remove(src)
|
||||
processing = 0
|
||||
return
|
||||
|
||||
switch (pylonmode)
|
||||
if (1)
|
||||
handle_sacrifice()
|
||||
if (2)
|
||||
if ((ticks % process_interval) == 0)
|
||||
handle_firing()
|
||||
if (damagetaken && prob(50))
|
||||
damagetaken = max(0, damagetaken-1) //An empowered pylon slowly self repairs
|
||||
if (prob(10))
|
||||
visible_message("Cracks in the [src] gradually seal as new crystalline matter grows to fill them.")
|
||||
|
||||
if (empowered && prob(2))
|
||||
empowered = max(0, empowered - 1) //Overcharging gradually wears off over time
|
||||
if (empowered <= 0)
|
||||
update_icon()
|
||||
|
||||
|
||||
//If user is a cultist, speaks message to them with a prefix
|
||||
//If user is not cultist, then speaks cult-y gibberish
|
||||
/obj/structure/cult/pylon/proc/speak_to(var/mob/user, var/message)
|
||||
if (iscult(user) || (/datum/language/cultcommon in user.languages))
|
||||
user << "A voice speaks into your mind, [span("cult","\"<I>[message]</I>\"")]"
|
||||
else
|
||||
user << "A voice speaks into your mind, [span("cult","\"<I>[lang.scramble(message)]</I>\"")]"
|
||||
|
||||
|
||||
//Todo: Replace the messages here with better ones. Should display a proper message to cultists
|
||||
//And nonsensical arcane gibberish to non cultists
|
||||
/obj/structure/cult/pylon/proc/present_sacrifice(var/mob/living/user, var/mob/living/victim)
|
||||
if (!user || !victim)
|
||||
return 0
|
||||
|
||||
if (isbroken)
|
||||
user << "The pylon lies silent."
|
||||
return 0
|
||||
|
||||
if (pylonmode != 0)
|
||||
return 0
|
||||
|
||||
if (!(victim.mob_size) || victim.mob_size > 6)
|
||||
//toolarge sacrifice, display a message and return
|
||||
speak_to(user, "This creature is too large, we only require a lesser sacrifice. A small morsel of life...")
|
||||
return
|
||||
|
||||
if (victim.stat == DEAD)
|
||||
speak_to(user, "You are too late, the spark of life is already gone from this one. It is naught but an empty husk...")
|
||||
return
|
||||
|
||||
var/types = victim.find_type()
|
||||
if ((!(types & TYPE_ORGANIC)) || ((types & TYPE_WIERD)))
|
||||
//Invalid sacrifice. Display a message and return
|
||||
speak_to(user, "This soulless automaton cannot satisfy our hunger. We yearn for life essence, it must have a soul.")
|
||||
return
|
||||
|
||||
sacrifice = victim
|
||||
sacrificer = user
|
||||
//Sacrifice accepted, display message here
|
||||
speak_to(user, "Your sacrifice has been deemed worthy, and accepted. End its life now, and liberate its soul, to seal our contract...")
|
||||
sacrifice << span("danger", "You feel an invisible force grip your soul, as you're drawn inexorably towards the pylon. Every part of you screams to flee from here!")
|
||||
|
||||
if (istype(sacrifice.loc,/obj/item/weapon/holder))
|
||||
var/obj/item/weapon/holder/H = sacrifice.loc
|
||||
H.release_to_floor()
|
||||
else
|
||||
sacrifice.forceMove(get_turf(sacrifice))
|
||||
pylonmode = 1
|
||||
update_icon()
|
||||
start_process()
|
||||
|
||||
|
||||
|
||||
//Runs every proc while there's a pending sacrifice. This checks whether the sacrifice was killed or escaped
|
||||
/obj/structure/cult/pylon/proc/handle_sacrifice()
|
||||
.=0 //Return value has 3 states.
|
||||
//0 = waiting, the sacrifice is still alive
|
||||
//1 = Finished, the sacrifice was killed, finalize the process and become a turret
|
||||
//-1 = Escape: The sacrifice left the vicinity of the pylon, return to inert mode.
|
||||
|
||||
if (!sacrifice)
|
||||
//If the sacrifice was deleted somehow, we cant know exactly what happened. We'll assume it escaped
|
||||
.=-1
|
||||
|
||||
else if(get_dist(src, sacrifice) > 5)
|
||||
//If the sacrifice gets more than 5 tiles away, it has escaped
|
||||
.=-1
|
||||
else if (sacrifice.stat == DEAD)
|
||||
.=1
|
||||
|
||||
switch(.)
|
||||
if (1)
|
||||
finalize_sacrifice()
|
||||
if (-1)
|
||||
speak_to(sacrificer, "Fool! Your offering has escaped. Bring it back, or find us another...")
|
||||
sacrifice = null
|
||||
pylonmode = 0
|
||||
update_icon()
|
||||
if (sacrifice)
|
||||
walk_to(sacrifice,0)
|
||||
else
|
||||
walk_towards(sacrifice,src, 10)
|
||||
|
||||
/obj/structure/cult/pylon/proc/finalize_sacrifice()
|
||||
sacrifice.visible_message(span("danger","\The [sacrifice]'s physical form unwinds as its soul is extracted from the remains, and drawn into the pylon!"))
|
||||
if (istype(sacrifice.loc,/obj/item/weapon/holder))
|
||||
var/obj/item/weapon/holder/H = sacrifice.loc
|
||||
H.release_to_floor()
|
||||
else
|
||||
sacrifice.forceMove(get_turf(sacrifice)) //Make sure its on the floor before we gib it
|
||||
pylonmode = 2
|
||||
sacrifice.gib()
|
||||
|
||||
update_icon()
|
||||
|
||||
|
||||
//Called every process in turret mode, and also by chaining spawns
|
||||
/obj/structure/cult/pylon/proc/handle_firing()
|
||||
|
||||
if ((world.time < next_shot) || isbroken)
|
||||
return
|
||||
//Not ready to fire yet
|
||||
|
||||
|
||||
var/list/stuffcache
|
||||
//Stuffcache holds a list of things found by a dview call, so we only need to do it once per proc.
|
||||
|
||||
|
||||
if (target && (target.stat != DEAD))
|
||||
if (target.loc == last_target_loc)
|
||||
//To minimise expensive DVIEW calls, if the target hasnt moved since the last shot we'll assume they're still in sight
|
||||
//This could cause problems in some edge cases (like lowering firelocks or shutters without moving)
|
||||
//But it has a major performance gain that makes it worth it
|
||||
fire_at(target)
|
||||
return
|
||||
else
|
||||
stuffcache = mobs_in_view(10, src)
|
||||
//for (var/turf/T in stuffcache)
|
||||
//new /obj/effect/testtrans(T)
|
||||
if ((target in stuffcache) && isInSight(src, target))
|
||||
for (var/mob/m in stuffcache)
|
||||
fire_at(target)
|
||||
return
|
||||
else
|
||||
target = null
|
||||
|
||||
//We may have already populated stuffcache this run, dont repeat work
|
||||
if (!stuffcache)
|
||||
stuffcache = mobs_in_view(10, src)
|
||||
|
||||
target = null //Either we lost a target or lack one
|
||||
//for (var/turf/T in stuffcache)
|
||||
//new /obj/effect/testtrans(T)
|
||||
|
||||
for (var/mob/living/L in stuffcache)
|
||||
if (L == sacrificer)
|
||||
continue
|
||||
//A pylon won't shoot the person who created it, regardless of cult status.
|
||||
//This is mainly for xenoarch antags
|
||||
|
||||
if (L.stat == DEAD)
|
||||
continue
|
||||
//No point shooting at corpses
|
||||
|
||||
if (iscult(L))
|
||||
continue
|
||||
//Pylon wont shoot at cultists or constructs
|
||||
|
||||
if (!isInSight(src, L))
|
||||
continue
|
||||
|
||||
target = L
|
||||
|
||||
|
||||
break
|
||||
|
||||
if (target)
|
||||
fire_at(target)
|
||||
else
|
||||
notarget++
|
||||
if (notarget > 60 || process_interval > 1)
|
||||
notarget = 0
|
||||
reconsider_interval()
|
||||
|
||||
|
||||
/obj/structure/cult/pylon/proc/fire_at(var/atom/target)
|
||||
//Only store loc if target is on a turf. Otherwise this bugs out with people in exosuits
|
||||
if (istype(target.loc, /turf))
|
||||
last_target_loc = target.loc
|
||||
|
||||
process_interval = 1 //Instantly wake up if we found a target
|
||||
var/obj/item/projectile/beam/cult/A
|
||||
if (empowered > 0)
|
||||
A = new /obj/item/projectile/beam/cult/heavy(loc)
|
||||
empowered = max(0, empowered-1)
|
||||
playsound(loc, 'sound/weapons/laserdeep.ogg', 100, 1)
|
||||
if (empowered <= 0)
|
||||
update_icon()
|
||||
else
|
||||
A = new /obj/item/projectile/beam/cult(loc)
|
||||
playsound(loc, 'sound/weapons/laserdeep.ogg', 65, 1)
|
||||
A.ignore = sacrificer
|
||||
A.launch(target)
|
||||
next_shot = world.time + shot_delay
|
||||
spawn(shot_delay+1)
|
||||
handle_firing()
|
||||
|
||||
|
||||
|
||||
/obj/structure/cult/pylon/attack_hand(mob/M as mob)
|
||||
attackpylon(M, 5)
|
||||
if (M.a_intent == "help")
|
||||
M << "The pylon feels warm to the touch...."
|
||||
else
|
||||
attackpylon(M, 4, M)
|
||||
|
||||
/obj/structure/cult/pylon/attack_generic(var/mob/user, var/damage)
|
||||
attackpylon(user, damage)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
|
||||
//Artificiers maintain pylons
|
||||
if(istype(user, /mob/living/simple_animal/construct))
|
||||
var/mob/living/simple_animal/construct/C = user
|
||||
if (C.can_repair)
|
||||
repair(user)
|
||||
return
|
||||
attackpylon(user, damage, user)
|
||||
|
||||
/obj/structure/cult/pylon/attackby(obj/item/W as obj, mob/user as mob)
|
||||
attackpylon(user, W.force)
|
||||
if (istype(W, /obj/item/weapon/holder))
|
||||
var/obj/item/weapon/holder/H = W
|
||||
if (H.contained)
|
||||
present_sacrifice(user, H.contained)
|
||||
return
|
||||
|
||||
/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
if(!isbroken)
|
||||
if(prob(1+ damage * 5))
|
||||
user.visible_message(
|
||||
"<span class='danger'>[user] smashed the pylon!</span>",
|
||||
"<span class='warning'>You hit the pylon, and its crystal breaks apart!</span>",
|
||||
"You hear a tinkle of crystal shards"
|
||||
attackpylon(user, W.force, W)
|
||||
|
||||
|
||||
//Mousedrop so that constructs can drag mice out of maintenance to make turrets
|
||||
/obj/structure/cult/pylon/MouseDrop_T(var/atom/movable/C, mob/user)
|
||||
if (istype(C, /mob/living))
|
||||
present_sacrifice(user, C)
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/structure/cult/pylon/bullet_act(var/obj/item/projectile/Proj)
|
||||
attackpylon(user, Proj.damage, Proj)
|
||||
|
||||
//Explosions will usually cause instant shattering, or heavy damage
|
||||
//Class 3 or lower blast is sometimes survivable. 2 or higher will always shatter
|
||||
/obj/structure/cult/pylon/ex_act(var/severity)
|
||||
if (severity > 0)
|
||||
attackpylon(null, (rand(200,400)/severity), null)
|
||||
|
||||
/obj/structure/cult/pylon/proc/attackpylon(mob/user as mob, var/damage, var/source)
|
||||
var/ranged = 0
|
||||
if (user)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
if (istype(source, /obj/item))
|
||||
var/obj/item/I = source
|
||||
if (I.damtype != BRUTE)
|
||||
user << "You swing at the pylon to no effect."
|
||||
return
|
||||
|
||||
if (istype(source, /obj/item/projectile))
|
||||
if (istype(source, /obj/item/projectile/beam/cult))
|
||||
return //No feedback loops
|
||||
var/obj/item/projectile/proj = source
|
||||
if (proj.damage_type == BURN)
|
||||
if (empowered <= 0)
|
||||
visible_message(
|
||||
"<span class='cult'>The beam refracts inside the pylon, splitting into an indistinct violet glow. The crystal takes on a new, more ominous aura!</span>"
|
||||
)
|
||||
empowered += damage*0.3
|
||||
//When shot with a laser, the pylon absorbs the beam, becoming empowered for a while, glowing brighter
|
||||
// and firing more powerful blasts which have some armor penetration
|
||||
// Using lasers to empower a defensive pylon yields more total damage than directly shooting your enemies
|
||||
|
||||
start_process()
|
||||
update_icon()
|
||||
return
|
||||
else if (proj.damage_type != BRUTE)
|
||||
return
|
||||
ranged = 1
|
||||
|
||||
if (!damage)
|
||||
return
|
||||
|
||||
damagetaken += damage
|
||||
|
||||
if(!isbroken)
|
||||
if (user)
|
||||
user.do_attack_animation(src)
|
||||
playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
|
||||
isbroken = 1
|
||||
density = 0
|
||||
icon_state = "pylon-broken"
|
||||
set_light(0)
|
||||
if(prob(damagetaken*0.5))
|
||||
shatter()
|
||||
else
|
||||
user << "You hit the pylon!"
|
||||
if (user && !ranged)
|
||||
user << "You hit the pylon!"
|
||||
playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1)
|
||||
else
|
||||
if(prob(damage * 2))
|
||||
user << "You pulverize what was left of the pylon!"
|
||||
if(prob(damagetaken))
|
||||
if (user)
|
||||
user << "You pulverize what was left of the pylon!"
|
||||
qdel(src)
|
||||
else
|
||||
else if (user && !ranged)
|
||||
user << "You hit the pylon!"
|
||||
playsound(get_turf(src), 'sound/effects/Glasshit.ogg', 75, 1)
|
||||
|
||||
start_process()
|
||||
|
||||
/obj/structure/cult/pylon/proc/shatter()
|
||||
visible_message(
|
||||
"<span class='danger'>The pylon shatters into shards of crystal!</span>",
|
||||
"You hear a tinkle of crystal shards"
|
||||
)
|
||||
playsound(get_turf(src), 'sound/effects/Glassbr3.ogg', 75, 1)
|
||||
isbroken = 1
|
||||
if (pylonmode == 2)
|
||||
//If the pylon had a soul in it then it plays a creepy evil sound as the soul is released
|
||||
var/possibles = list('sound/hallucinations/far_noise.ogg',
|
||||
'sound/hallucinations/growl3.ogg',
|
||||
'sound/hallucinations/veryfar_noise.ogg',
|
||||
'sound/hallucinations/wail.ogg',
|
||||
'sound/voice/hiss5.ogg')
|
||||
playsound(get_turf(src), pick(possibles), 50, 1)
|
||||
|
||||
pylonmode = 0 //A broken pylon loses its soul. Even if repaired it will need a new sacrifice to re-empower it
|
||||
|
||||
//Make sure we stop it from firing
|
||||
target = null
|
||||
sacrificer = null
|
||||
notarget = 0
|
||||
last_target_loc = null
|
||||
process_interval = 1
|
||||
//It will stop processing after the next check, start of the next process
|
||||
|
||||
empowered = 0
|
||||
density = 0
|
||||
update_icon()
|
||||
|
||||
|
||||
|
||||
/obj/structure/cult/pylon/proc/repair(mob/user as mob)
|
||||
if(isbroken)
|
||||
user << "You repair the pylon."
|
||||
if(user)
|
||||
user << span("notice","You weave forgotten magic, summoning the shards of the crystal and knitting them anew, until it hovers flawless once more.")
|
||||
isbroken = 0
|
||||
density = 1
|
||||
icon_state = "pylon"
|
||||
set_light(5)
|
||||
else if (damagetaken > 0)
|
||||
user << span("notice","You meld the crystal lattice back into integrity, sealing over the cracks until they never were.")
|
||||
|
||||
else
|
||||
user << span("notice","The crystal lights up at your touch.")
|
||||
|
||||
process_interval = 1 //Wake up the crystal
|
||||
notarget = 0
|
||||
damagetaken = 0
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/structure/cult/pylon/update_icon()
|
||||
overlays.Cut()
|
||||
if (pylonmode == 2)
|
||||
anchored = 1
|
||||
if (empowered > 0)
|
||||
overlays += "crystal_overcharge"
|
||||
set_light(7, 3, l_color = "#a160bf")
|
||||
else
|
||||
set_light(6, 3, l_color = "#3e0000")
|
||||
overlays += "crystal_turret"
|
||||
else if (!isbroken)
|
||||
set_light(5, 2, l_color = "#3e0000")
|
||||
overlays += "crystal_idle"
|
||||
if (pylonmode == 1)
|
||||
anchored = 1
|
||||
else
|
||||
anchored = 0
|
||||
else
|
||||
anchored = 0
|
||||
set_light(0)
|
||||
|
||||
|
||||
|
||||
//============================================
|
||||
/obj/structure/cult/tome
|
||||
name = "Desk"
|
||||
desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl"
|
||||
@@ -144,7 +650,7 @@
|
||||
if(M.has_brain_worms())
|
||||
return //Borer stuff - RR
|
||||
|
||||
if(iscultist(M)) return
|
||||
if(iscult(M)) return
|
||||
if(!ishuman(M) && !isrobot(M)) return
|
||||
|
||||
M.transforming = 1
|
||||
@@ -174,3 +680,12 @@
|
||||
new_mob.key = M.key
|
||||
|
||||
new_mob << "<B>Your form morphs into that of a corgi.</B>" //Because we don't have cluwnes
|
||||
|
||||
/obj/effect/testtrans
|
||||
icon = 'icons/obj/cult.dmi'
|
||||
icon_state = "tt"
|
||||
|
||||
/obj/effect/testtrans/New()
|
||||
..()
|
||||
spawn(10)
|
||||
qdel(src)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -69,3 +69,5 @@
|
||||
universe = new newstate
|
||||
if(on_enter)
|
||||
universe.OnEnter()
|
||||
|
||||
/datum/universal_state/proc/convert_parallax(parallax_spacemaster)
|
||||
@@ -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.15, 0.5)
|
||||
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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user