mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-16 01:23:41 +01:00
Merge branch 'master' into Clinging-to-hope
This commit is contained in:
+3
-2
@@ -5,9 +5,9 @@
|
||||
|
||||
### AffectedArc07
|
||||
# Actual Code
|
||||
/code/controllers/subsystem/instancing.dm @AffectedArc07
|
||||
/code/controllers/subsystem/mapping.dm @AffectedArc07
|
||||
/code/controllers/subsystem/ticker.dm @AffectedArc07
|
||||
/tgui/ @AffectedArc07
|
||||
|
||||
# CI + Tooling
|
||||
/.github/workflows/ @AffectedArc07
|
||||
@@ -18,7 +18,8 @@
|
||||
dreamchecker.exe @AffectedArc07
|
||||
rust_g.dll @AffectedArc07
|
||||
|
||||
|
||||
### dearmochi
|
||||
/tgui/ @dearmochi
|
||||
|
||||
### Fox-McCloud
|
||||
/code/controllers/subsystem/air.dm @Fox-McCloud
|
||||
|
||||
@@ -671,9 +671,10 @@ responsible for properly tagging new pull requests and issues, moderating commen
|
||||
pull requests/issues, and merging/closing pull requests.
|
||||
|
||||
### Maintainer List
|
||||
* [AffectedArc07](https://github.com/AffectedArc07)
|
||||
|
||||
* [Ansari](https://github.com/variableundefined)
|
||||
* [Crazy Lemon](https://github.com/Crazylemon64)
|
||||
* [Crazylemon](https://github.com/marlyn-x86)
|
||||
* [dearmochi](https://github.com/dearmochi)
|
||||
* [Fox P McCloud](https://github.com/Fox-McCloud)
|
||||
|
||||
### Maintainer instructions
|
||||
|
||||
@@ -14,7 +14,7 @@ When that's installed, right click in any folder and click on "Git Bash".
|
||||
When that opens, type in:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/ParadiseSS13/Paradise.git
|
||||
git clone https://github.com/ParadiseSS13/Paradise.git --depth 1
|
||||
```
|
||||
|
||||
(hint: hold down ctrl and press insert to paste into git bash)
|
||||
@@ -88,7 +88,7 @@ and then copy the `config` and `data` folders over.
|
||||
If you used the git method, you simply need to type this in to git bash:
|
||||
|
||||
```sh
|
||||
git pull
|
||||
git pull --depth 1
|
||||
```
|
||||
|
||||
When you have done this, you'll need to recompile the code, but then it should work fine and be up to date with the live server.
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
no_balance_label = "GBP: No Update"
|
||||
reset_label = "GBP: Reset"
|
||||
|
||||
[points]
|
||||
"Administration" = 2
|
||||
"Balance" = -8
|
||||
"Code Improvement" = 1
|
||||
"Feature" = -9
|
||||
"Fix" = 3
|
||||
"GC Related" = 12
|
||||
"Grammar and Formatting" = 1
|
||||
"High Priority" = 20
|
||||
"Infrastructure" = 5
|
||||
"Performance" = 12
|
||||
"Refactor" = 3
|
||||
"Sound" = 1
|
||||
"Sprites" = 1
|
||||
@@ -0,0 +1,47 @@
|
||||
# This generates GBP balances
|
||||
name: GBP
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed, opened]
|
||||
|
||||
jobs:
|
||||
gbp:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps"
|
||||
id: value_holder
|
||||
env:
|
||||
ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }}
|
||||
run: |
|
||||
unset SECRET_EXISTS
|
||||
if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi
|
||||
echo "::set-output name=ACTIONS_ENABLED::$SECRET_EXISTS"
|
||||
|
||||
- name: Checkout
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup git
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
run: |
|
||||
git config --global user.name "gbp-action"
|
||||
git config --global user.email "<>"
|
||||
|
||||
- name: Checkout alternate branch
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "gbp-balances" # The branch name
|
||||
path: gbp-balances
|
||||
# This is to ensure we keep the gbp.toml from master
|
||||
# without having to update our separate branch.
|
||||
- name: Copy configuration
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml
|
||||
- name: GBP action
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
uses: tgstation/gbp-action@master
|
||||
with:
|
||||
branch: "gbp-balances"
|
||||
directory: ./gbp-balances
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,51 @@
|
||||
# This collects balances to one merged file
|
||||
name: GBP Collection
|
||||
# Every hour at the :20 minute mark. GitHub tells us to pick odd hours, instead of just using the start.
|
||||
on:
|
||||
schedule:
|
||||
- cron: "20 * * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
gbp_collection:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: "Check for ACTION_ENABLER secret and pass true to output if it exists to be checked by later steps"
|
||||
id: value_holder
|
||||
env:
|
||||
ENABLER_SECRET: ${{ secrets.ACTION_ENABLER }}
|
||||
run: |
|
||||
unset SECRET_EXISTS
|
||||
if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi
|
||||
echo "::set-output name=ACTIONS_ENABLED::$SECRET_EXISTS"
|
||||
|
||||
- name: Checkout
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup git
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Checkout alternate branch
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "gbp-balances" # The branch name
|
||||
path: gbp-balances
|
||||
|
||||
# This is to ensure we keep the gbp.toml from master
|
||||
# without having to update our separate branch.
|
||||
- name: Copy configuration
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
run: cp ./.github/gbp.toml ./gbp-balances/.github/gbp.toml
|
||||
|
||||
- name: GBP action
|
||||
if: steps.value_holder.outputs.ACTIONS_ENABLED
|
||||
uses: tgstation/gbp-action@master
|
||||
with:
|
||||
collect: "true"
|
||||
directory: ./gbp-balances
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -75,6 +75,10 @@ CREATE TABLE `characters` (
|
||||
`body_accessory` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`gear` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`autohiss` tinyint(1) NOT NULL,
|
||||
`hair_gradient` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`hair_gradient_offset` varchar(7) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0,0',
|
||||
`hair_gradient_colour` varchar(7) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '#000000',
|
||||
`hair_gradient_alpha` tinyint(3) UNSIGNED NOT NULL DEFAULT '255',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ckey` (`ckey`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=125467 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -114,6 +118,7 @@ CREATE TABLE `death` (
|
||||
`pod` text NOT NULL COMMENT 'Place of death',
|
||||
`coord` text NOT NULL COMMENT 'X, Y, Z POD',
|
||||
`tod` datetime NOT NULL COMMENT 'Time of death',
|
||||
`server_id` TEXT NULL DEFAULT NULL,
|
||||
`job` text NOT NULL,
|
||||
`special` text NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
@@ -197,6 +202,7 @@ CREATE TABLE `ban` (
|
||||
`bantime` datetime NOT NULL,
|
||||
`ban_round_id` INT(11) NULL DEFAULT NULL,
|
||||
`serverip` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`server_id` VARCHAR(50) NULL DEFAULT NULL COLLATE utf8mb4_general_ci,
|
||||
`bantype` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`reason` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`job` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
@@ -320,6 +326,7 @@ CREATE TABLE `karma` (
|
||||
`receiverspecial` text,
|
||||
`isnegative` tinyint(1) DEFAULT NULL,
|
||||
`spenderip` text NOT NULL,
|
||||
`server_id` TEXT NULL DEFAULT NULL,
|
||||
`time` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=73614 DEFAULT CHARSET=utf8mb4;
|
||||
@@ -374,6 +381,7 @@ CREATE TABLE `legacy_population` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`playercount` int(11) DEFAULT NULL,
|
||||
`admincount` int(11) DEFAULT NULL,
|
||||
`server_id` VARCHAR(50) NULL DEFAULT NULL,
|
||||
`time` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2550 DEFAULT CHARSET=utf8mb4;
|
||||
@@ -532,6 +540,7 @@ CREATE TABLE `connection_log` (
|
||||
`ckey` varchar(32) NOT NULL,
|
||||
`ip` varchar(32) NOT NULL,
|
||||
`computerid` varchar(32) NOT NULL,
|
||||
`server_id` VARCHAR(50) NULL DEFAULT NULL,
|
||||
`result` ENUM('ESTABLISHED','DROPPED - IPINTEL','DROPPED - BANNED','DROPPED - INVALID') NOT NULL DEFAULT 'ESTABLISHED' COLLATE 'utf8mb4_general_ci',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `ckey` (`ckey`),
|
||||
@@ -584,6 +593,7 @@ CREATE TABLE `round` (
|
||||
`shuttle_name` VARCHAR(64) NULL,
|
||||
`map_name` VARCHAR(32) NULL,
|
||||
`station_name` VARCHAR(80) NULL,
|
||||
`server_id` VARCHAR(50) NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
@@ -612,3 +622,14 @@ CREATE TABLE `pai_saves` (
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `ckey` (`ckey`) USING BTREE
|
||||
) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB;
|
||||
|
||||
--
|
||||
-- Table structure for table `instance_data_cache`
|
||||
--
|
||||
CREATE TABLE `instance_data_cache` (
|
||||
`server_id` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci',
|
||||
`key_name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci',
|
||||
`key_value` VARCHAR(12345) NOT NULL COLLATE 'utf8mb4_general_ci',
|
||||
`last_updated` TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`server_id`, `key_name`) USING HASH
|
||||
) COLLATE='utf8mb4_general_ci' ENGINE=MEMORY;
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Updates DB from 26 to 27 -AffectedArc07
|
||||
# Adds a new table for instance data caching, and server_id fields on other tables
|
||||
|
||||
CREATE TABLE `instance_data_cache` (
|
||||
`server_id` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci',
|
||||
`key_name` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_general_ci',
|
||||
`key_value` VARCHAR(12345) NOT NULL COLLATE 'utf8mb4_general_ci',
|
||||
`last_updated` TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`server_id`, `key_name`) USING HASH
|
||||
) COLLATE='utf8mb4_general_ci' ENGINE=MEMORY;
|
||||
|
||||
ALTER TABLE `ban`
|
||||
ADD COLUMN `server_id` VARCHAR(50) NULL DEFAULT NULL AFTER `serverip`;
|
||||
|
||||
ALTER TABLE `connection_log`
|
||||
ADD COLUMN `server_id` VARCHAR(50) NULL DEFAULT NULL AFTER `computerid`;
|
||||
|
||||
ALTER TABLE `death`
|
||||
ADD COLUMN `server_id` TEXT NULL AFTER `tod`;
|
||||
|
||||
ALTER TABLE `karma`
|
||||
ADD COLUMN `server_id` TEXT NULL AFTER `spenderip`;
|
||||
|
||||
ALTER TABLE `legacy_population`
|
||||
ADD COLUMN `server_id` VARCHAR(50) NULL DEFAULT NULL AFTER `admincount`;
|
||||
|
||||
# Notes already has a column for this
|
||||
ALTER TABLE `notes`
|
||||
CHANGE COLUMN `server` `server` VARCHAR(50) NULL COLLATE 'utf8mb4_general_ci' AFTER `edits`;
|
||||
|
||||
ALTER TABLE `round`
|
||||
ADD COLUMN `server_id` VARCHAR(50) NULL DEFAULT NULL AFTER `station_name`;
|
||||
@@ -0,0 +1,6 @@
|
||||
# Updates DB from 27 to 28 -dearmochi
|
||||
# Adds support for hair gradient
|
||||
ALTER TABLE `characters` ADD COLUMN `hair_gradient` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL;
|
||||
ALTER TABLE `characters` ADD COLUMN `hair_gradient_offset` varchar(7) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0,0';
|
||||
ALTER TABLE `characters` ADD COLUMN `hair_gradient_colour` varchar(7) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '#000000';
|
||||
ALTER TABLE `characters` ADD COLUMN `hair_gradient_alpha` tinyint(3) UNSIGNED NOT NULL DEFAULT '255'
|
||||
+10234
-11033
File diff suppressed because it is too large
Load Diff
@@ -3238,12 +3238,12 @@
|
||||
})
|
||||
"aiM" = (
|
||||
/obj/structure/rack,
|
||||
/obj/item/gun/energy/gun/advtaser{
|
||||
/obj/item/gun/energy/disabler{
|
||||
pixel_x = -3;
|
||||
pixel_y = 3
|
||||
},
|
||||
/obj/item/gun/energy/gun/advtaser,
|
||||
/obj/item/gun/energy/gun/advtaser{
|
||||
/obj/item/gun/energy/disabler,
|
||||
/obj/item/gun/energy/disabler{
|
||||
pixel_x = 3;
|
||||
pixel_y = -3
|
||||
},
|
||||
@@ -43751,7 +43751,7 @@
|
||||
name = "\improper Secure Lab"
|
||||
})
|
||||
"bPO" = (
|
||||
/obj/structure/foodcart,
|
||||
/obj/machinery/smartfridge/foodcart,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "showroomfloor"
|
||||
},
|
||||
|
||||
@@ -54,7 +54,10 @@
|
||||
/turf/simulated/floor/plating/asteroid/snow/atmosphere,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"al" = (
|
||||
/obj/effect/decal/cleanable/blood/oil,
|
||||
/obj/item/paper/crumpled/bloody/fluff/ruins/snowbiodome/cabin3,
|
||||
/obj/effect/decal/cleanable/blood,
|
||||
/obj/effect/decal/cleanable/blood/innards,
|
||||
/obj/item/organ/internal/heart,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"am" = (
|
||||
@@ -99,11 +102,12 @@
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"aw" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/reagent_containers/food/snacks/beans,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"ax" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/reagent_containers/food/snacks/beans,
|
||||
/obj/machinery/kitchen_machine/microwave,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"ay" = (
|
||||
@@ -150,7 +154,7 @@
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"aH" = (
|
||||
/mob/living/simple_animal/hostile/skeleton/eskimo,
|
||||
/mob/living/simple_animal/hostile/skeleton/arctic,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"aI" = (
|
||||
@@ -164,6 +168,7 @@
|
||||
"aK" = (
|
||||
/obj/structure/table/wood,
|
||||
/obj/item/key,
|
||||
/obj/item/paper/fluff/ruins/snowbiodome/cabin1,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"aL" = (
|
||||
@@ -211,6 +216,7 @@
|
||||
/obj/machinery/light/small{
|
||||
dir = 8
|
||||
},
|
||||
/obj/effect/decal/cleanable/blood/writing,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"bx" = (
|
||||
@@ -253,15 +259,14 @@
|
||||
/obj/machinery/light/small,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"eb" = (
|
||||
/obj/machinery/light/small{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/pod/dark,
|
||||
"dV" = (
|
||||
/obj/effect/decal/cleanable/blood/old,
|
||||
/obj/structure/sacrificealtar,
|
||||
/obj/item/kitchen/knife/combat/survival/bone,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"eg" = (
|
||||
/obj/machinery/vending/coffee,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/turf/simulated/wall/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"gh" = (
|
||||
/obj/machinery/light/small{
|
||||
@@ -280,6 +285,36 @@
|
||||
/obj/effect/mapping_helpers/no_lava,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"iA" = (
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"iE" = (
|
||||
/obj/effect/decal/cleanable/blood/writing{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/snow/atmosphere,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"jL" = (
|
||||
/obj/effect/decal/cleanable/blood/writing,
|
||||
/obj/effect/decal/cleanable/blood/writing,
|
||||
/obj/effect/decal/cleanable/blood/writing{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/plating/asteroid/snow/atmosphere,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"ks" = (
|
||||
/obj/effect/decal/cleanable/blood/drip,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"mh" = (
|
||||
/obj/effect/decal/cleanable/blood/drip,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"mt" = (
|
||||
/obj/effect/decal/cleanable/blood/drip,
|
||||
/turf/simulated/floor/plating/asteroid/snow/atmosphere,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"qt" = (
|
||||
/obj/machinery/door/airlock/silver,
|
||||
/obj/structure/fans/tiny,
|
||||
@@ -289,29 +324,57 @@
|
||||
/obj/effect/mapping_helpers/no_lava,
|
||||
/turf/simulated/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors/explored)
|
||||
"th" = (
|
||||
/obj/effect/decal/cleanable/blood/writing{
|
||||
dir = 8
|
||||
},
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"tl" = (
|
||||
/turf/simulated/floor/pod/light,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"tI" = (
|
||||
/obj/item/paper/fluff/ruins/snowbiodome/cabin2,
|
||||
/obj/effect/decal/cleanable/blood/writing,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"vf" = (
|
||||
/obj/machinery/door/airlock/multi_tile/glass,
|
||||
/obj/structure/fans/tiny,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"xU" = (
|
||||
/obj/machinery/light/small{
|
||||
dir = 8
|
||||
},
|
||||
/obj/item/storage/toolbox/mechanical,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"zT" = (
|
||||
/obj/machinery/door/airlock/silver,
|
||||
/obj/structure/fans/tiny,
|
||||
/turf/simulated/floor/plating,
|
||||
"zD" = (
|
||||
/obj/effect/mob_spawn/human/skeleton,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"zH" = (
|
||||
/obj/effect/decal/cleanable/blood,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"AJ" = (
|
||||
/obj/item/twohanded/required/chainsaw,
|
||||
/turf/simulated/floor/plating/asteroid/snow/atmosphere,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"AM" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/pen,
|
||||
/obj/item/paper,
|
||||
/obj/machinery/vending/coffee/free,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"BI" = (
|
||||
/obj/effect/spawner/window,
|
||||
/obj/structure/barricade/wooden/crude/snow,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/ruin/powered/snow_cabin)
|
||||
"CD" = (
|
||||
/obj/structure/closet/secure_closet/freezer/fridge/open,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Dd" = (
|
||||
/obj/structure/rack,
|
||||
/obj/item/clothing/suit/hooded/wintercoat/science,
|
||||
@@ -320,8 +383,8 @@
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Ef" = (
|
||||
/obj/structure/reagent_dispensers/fueltank,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/obj/structure/flora/rock/icy,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Ez" = (
|
||||
/obj/structure/fans/tiny,
|
||||
@@ -331,40 +394,47 @@
|
||||
"HP" = (
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"HR" = (
|
||||
/obj/structure/closet/secure_closet/freezer/fridge/open,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
"JB" = (
|
||||
/obj/structure/barricade/wooden,
|
||||
/obj/structure/barricade/wooden/crude/snow,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"JZ" = (
|
||||
/obj/structure/table,
|
||||
/obj/machinery/kitchen_machine/microwave,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"KS" = (
|
||||
/obj/structure/closet,
|
||||
/obj/machinery/light/small{
|
||||
dir = 4
|
||||
},
|
||||
/obj/item/twohanded/required/chainsaw,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
"LO" = (
|
||||
/obj/item/paper/fluff/ruins/snowbiodome/altar,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Mp" = (
|
||||
/obj/item/clothing/mask/balaclava,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"NO" = (
|
||||
/obj/effect/decal/cleanable/blood/drip,
|
||||
/obj/effect/decal/cleanable/blood/writing,
|
||||
/turf/simulated/floor/plating/asteroid/snow/atmosphere,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Oj" = (
|
||||
/obj/structure/table,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/obj/machinery/light{
|
||||
dir = 4
|
||||
},
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"PD" = (
|
||||
/obj/machinery/door/airlock/hatch,
|
||||
/obj/structure/fans/tiny,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"PI" = (
|
||||
/obj/effect/decal/cleanable/blood,
|
||||
/obj/effect/decal/cleanable/blood/footprints,
|
||||
/turf/simulated/floor/mineral/silver,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"PK" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/pen,
|
||||
/obj/item/paper_bin,
|
||||
/obj/item/paper/fluff/ruins/snowbiodome/entrance,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Qa" = (
|
||||
@@ -378,6 +448,8 @@
|
||||
"QK" = (
|
||||
/obj/structure/table,
|
||||
/obj/item/storage/fancy/cigarettes/cigpack_carp,
|
||||
/obj/item/paper,
|
||||
/obj/item/pen,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"QN" = (
|
||||
@@ -385,8 +457,7 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Sj" = (
|
||||
/obj/effect/decal/cleanable/blood/oil,
|
||||
/turf/simulated/floor/pod/dark,
|
||||
/turf/simulated/wall/mineral/wood/nonmetal,
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"Ub" = (
|
||||
/obj/structure/filingcabinet,
|
||||
@@ -441,7 +512,7 @@ Wg
|
||||
Wg
|
||||
Wg
|
||||
Dd
|
||||
gh
|
||||
xU
|
||||
HP
|
||||
tl
|
||||
gh
|
||||
@@ -478,7 +549,7 @@ HP
|
||||
tl
|
||||
PK
|
||||
gz
|
||||
HP
|
||||
iA
|
||||
Wg
|
||||
ak
|
||||
ak
|
||||
@@ -499,9 +570,9 @@ aa
|
||||
Wg
|
||||
Wg
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
Wg
|
||||
QN
|
||||
@@ -513,7 +584,7 @@ QN
|
||||
QN
|
||||
Wg
|
||||
ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -574,7 +645,7 @@ ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
aQ
|
||||
ak
|
||||
@@ -605,7 +676,7 @@ ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
aI
|
||||
@@ -674,7 +745,7 @@ ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -687,7 +758,7 @@ tb
|
||||
(10,1,1) = {"
|
||||
Wg
|
||||
Wg
|
||||
af
|
||||
CD
|
||||
Wg
|
||||
ak
|
||||
ak
|
||||
@@ -754,9 +825,9 @@ ad
|
||||
af
|
||||
ar
|
||||
bw
|
||||
at
|
||||
tI
|
||||
aD
|
||||
at
|
||||
mh
|
||||
aL
|
||||
aq
|
||||
ak
|
||||
@@ -783,12 +854,12 @@ tb
|
||||
(13,1,1) = {"
|
||||
Wg
|
||||
ae
|
||||
af
|
||||
ks
|
||||
aq
|
||||
au
|
||||
au
|
||||
aq
|
||||
at
|
||||
th
|
||||
bz
|
||||
aq
|
||||
ak
|
||||
@@ -814,7 +885,7 @@ tb
|
||||
"}
|
||||
(14,1,1) = {"
|
||||
Wg
|
||||
af
|
||||
ks
|
||||
al
|
||||
aq
|
||||
aq
|
||||
@@ -823,7 +894,7 @@ aE
|
||||
at
|
||||
at
|
||||
aq
|
||||
ak
|
||||
ap
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
@@ -855,7 +926,7 @@ at
|
||||
aH
|
||||
aM
|
||||
vf
|
||||
ap
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -917,7 +988,7 @@ ax
|
||||
aK
|
||||
aF
|
||||
at
|
||||
at
|
||||
mh
|
||||
aq
|
||||
ak
|
||||
aI
|
||||
@@ -953,8 +1024,8 @@ bz
|
||||
aq
|
||||
aR
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
NO
|
||||
jL
|
||||
ak
|
||||
ab
|
||||
ak
|
||||
@@ -986,7 +1057,7 @@ aq
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
az
|
||||
iE
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -1011,8 +1082,8 @@ af
|
||||
aq
|
||||
aq
|
||||
aq
|
||||
aq
|
||||
aq
|
||||
BI
|
||||
BI
|
||||
aq
|
||||
aq
|
||||
bD
|
||||
@@ -1049,7 +1120,7 @@ ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
mt
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
@@ -1080,12 +1151,12 @@ ak
|
||||
ap
|
||||
ak
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
ak
|
||||
mt
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
aI
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -1114,11 +1185,11 @@ ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
aQ
|
||||
iE
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
aC
|
||||
ak
|
||||
aI
|
||||
ak
|
||||
@@ -1137,7 +1208,7 @@ aa
|
||||
Wg
|
||||
Wg
|
||||
ak
|
||||
ak
|
||||
AJ
|
||||
aB
|
||||
ak
|
||||
ak
|
||||
@@ -1145,12 +1216,12 @@ aC
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
eg
|
||||
ak
|
||||
aI
|
||||
ak
|
||||
ap
|
||||
ak
|
||||
iE
|
||||
ak
|
||||
eg
|
||||
aC
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -1177,13 +1248,13 @@ ak
|
||||
aQ
|
||||
ak
|
||||
ak
|
||||
Ef
|
||||
mt
|
||||
JZ
|
||||
ak
|
||||
aI
|
||||
aB
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
aQ
|
||||
JZ
|
||||
ak
|
||||
ak
|
||||
aB
|
||||
@@ -1207,19 +1278,19 @@ az
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
bB
|
||||
JZ
|
||||
bM
|
||||
Sj
|
||||
Sj
|
||||
JB
|
||||
Sj
|
||||
Sj
|
||||
bD
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
bB
|
||||
ak
|
||||
ak
|
||||
az
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
Wg
|
||||
@@ -1239,15 +1310,15 @@ ak
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
Wg
|
||||
QN
|
||||
QN
|
||||
QN
|
||||
zT
|
||||
QN
|
||||
QN
|
||||
QN
|
||||
Wg
|
||||
aC
|
||||
eg
|
||||
Sj
|
||||
JZ
|
||||
PI
|
||||
zD
|
||||
Sj
|
||||
eg
|
||||
aC
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
@@ -1270,16 +1341,16 @@ Wg
|
||||
Wg
|
||||
ak
|
||||
bB
|
||||
JZ
|
||||
ak
|
||||
Wg
|
||||
eg
|
||||
HP
|
||||
tl
|
||||
tl
|
||||
tl
|
||||
aB
|
||||
Sj
|
||||
xU
|
||||
Wg
|
||||
zD
|
||||
dV
|
||||
LO
|
||||
Sj
|
||||
ak
|
||||
ak
|
||||
ak
|
||||
bB
|
||||
ak
|
||||
@@ -1304,13 +1375,13 @@ Wg
|
||||
Wg
|
||||
Wg
|
||||
Wg
|
||||
HR
|
||||
eb
|
||||
gz
|
||||
JZ
|
||||
Sj
|
||||
zH
|
||||
Oj
|
||||
JZ
|
||||
KS
|
||||
Ef
|
||||
Sj
|
||||
ap
|
||||
Wg
|
||||
Wg
|
||||
Wg
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
/turf/simulated/floor/mineral/titanium/blue/airless,
|
||||
/area/ruin/powered)
|
||||
"i" = (
|
||||
/obj/machinery/computer/shuttle,
|
||||
/obj/machinery/computer{
|
||||
name = "shuttle control console"
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue/airless,
|
||||
/area/ruin/powered)
|
||||
"j" = (
|
||||
@@ -46,7 +48,9 @@
|
||||
/turf/simulated/floor/mineral/titanium/blue/airless,
|
||||
/area/ruin/powered)
|
||||
"n" = (
|
||||
/obj/machinery/computer/mecha,
|
||||
/obj/machinery/computer{
|
||||
name = "exosuit control console"
|
||||
},
|
||||
/turf/simulated/floor/mineral/titanium/blue/airless,
|
||||
/area/ruin/powered)
|
||||
"p" = (
|
||||
|
||||
@@ -515,9 +515,6 @@
|
||||
"bm" = (
|
||||
/turf/simulated/wall/mineral/titanium/nodecon/nodiagonal,
|
||||
/area/derelict/crew_quarters)
|
||||
"bn" = (
|
||||
/turf/simulated/wall/mineral/titanium/nodecon/nodiagonal,
|
||||
/area/derelict/arrival)
|
||||
"bo" = (
|
||||
/obj/structure/cable{
|
||||
d2 = 4;
|
||||
@@ -3752,11 +3749,6 @@
|
||||
icon_state = "dark"
|
||||
},
|
||||
/area/derelict/crew_quarters)
|
||||
"hU" = (
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
},
|
||||
/area/derelict/crew_quarters)
|
||||
"hV" = (
|
||||
/obj/structure/table,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
@@ -7143,14 +7135,6 @@
|
||||
icon_state = "hydrofloor"
|
||||
},
|
||||
/area/derelict/crew_quarters)
|
||||
"pg" = (
|
||||
/obj/structure/closet/walllocker{
|
||||
pixel_y = -32
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "orangefull"
|
||||
},
|
||||
/area/derelict/crew_quarters)
|
||||
"ph" = (
|
||||
/obj/structure/holohoop{
|
||||
dir = 1
|
||||
@@ -8002,7 +7986,6 @@
|
||||
},
|
||||
/area/derelict/crew_quarters)
|
||||
"rn" = (
|
||||
/obj/structure/closet/medical_wall,
|
||||
/turf/simulated/wall/mineral/titanium/nodecon/nodiagonal,
|
||||
/area/derelict/arrival)
|
||||
"ro" = (
|
||||
@@ -9173,12 +9156,12 @@ ac
|
||||
ac
|
||||
ac
|
||||
QN
|
||||
bn
|
||||
rn
|
||||
jm
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
lu
|
||||
bn
|
||||
rn
|
||||
QN
|
||||
ac
|
||||
ac
|
||||
@@ -9264,14 +9247,14 @@ ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
bn
|
||||
rn
|
||||
iS
|
||||
jn
|
||||
jS
|
||||
kL
|
||||
hY
|
||||
lK
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -9354,17 +9337,17 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
iT
|
||||
hY
|
||||
jT
|
||||
kM
|
||||
lv
|
||||
lL
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -9442,10 +9425,10 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
gJ
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
hI
|
||||
hX
|
||||
iv
|
||||
@@ -9458,8 +9441,8 @@ hY
|
||||
me
|
||||
mu
|
||||
mG
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
mG
|
||||
aW
|
||||
ac
|
||||
@@ -9531,8 +9514,8 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
dO
|
||||
gq
|
||||
gK
|
||||
@@ -9549,12 +9532,12 @@ lw
|
||||
hY
|
||||
mf
|
||||
mv
|
||||
bn
|
||||
rn
|
||||
mR
|
||||
ni
|
||||
nw
|
||||
mG
|
||||
bn
|
||||
rn
|
||||
mG
|
||||
aW
|
||||
ac
|
||||
@@ -9622,7 +9605,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
ff
|
||||
fA
|
||||
dL
|
||||
@@ -9712,16 +9695,16 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
de
|
||||
do
|
||||
do
|
||||
do
|
||||
do
|
||||
hb
|
||||
bn
|
||||
rn
|
||||
hK
|
||||
hY
|
||||
ix
|
||||
@@ -9905,7 +9888,7 @@ do
|
||||
do
|
||||
gM
|
||||
hc
|
||||
bn
|
||||
rn
|
||||
hM
|
||||
ia
|
||||
iz
|
||||
@@ -9985,7 +9968,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
dP
|
||||
dV
|
||||
dV
|
||||
@@ -9997,19 +9980,19 @@ fY
|
||||
do
|
||||
gN
|
||||
hd
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
jr
|
||||
ka
|
||||
kT
|
||||
ly
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
mV
|
||||
nm
|
||||
mS
|
||||
@@ -10075,9 +10058,9 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
dQ
|
||||
do
|
||||
do
|
||||
@@ -10088,21 +10071,21 @@ fE
|
||||
fZ
|
||||
gs
|
||||
dO
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
kb
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
mG
|
||||
ny
|
||||
nK
|
||||
@@ -10166,7 +10149,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
dm
|
||||
dA
|
||||
dL
|
||||
@@ -10174,10 +10157,10 @@ do
|
||||
do
|
||||
do
|
||||
eo
|
||||
bn
|
||||
rn
|
||||
fh
|
||||
fF
|
||||
bn
|
||||
rn
|
||||
fG
|
||||
aW
|
||||
ac
|
||||
@@ -10257,7 +10240,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
dd
|
||||
dn
|
||||
do
|
||||
@@ -10266,8 +10249,8 @@ do
|
||||
do
|
||||
ee
|
||||
ep
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
fG
|
||||
aW
|
||||
ac
|
||||
@@ -10348,7 +10331,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
cL
|
||||
de
|
||||
do
|
||||
@@ -10358,7 +10341,7 @@ do
|
||||
do
|
||||
ef
|
||||
eq
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -10439,9 +10422,9 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
df
|
||||
dp
|
||||
dB
|
||||
@@ -10530,10 +10513,10 @@ ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
bn
|
||||
rn
|
||||
cl
|
||||
cz
|
||||
bn
|
||||
rn
|
||||
de
|
||||
dq
|
||||
dC
|
||||
@@ -10721,7 +10704,7 @@ cN
|
||||
cB
|
||||
dr
|
||||
dE
|
||||
bn
|
||||
rn
|
||||
dS
|
||||
ac
|
||||
ac
|
||||
@@ -10804,7 +10787,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
bn
|
||||
rn
|
||||
bF
|
||||
bT
|
||||
co
|
||||
@@ -10812,7 +10795,7 @@ cA
|
||||
cM
|
||||
dg
|
||||
ds
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -10858,7 +10841,7 @@ mS
|
||||
qC
|
||||
mU
|
||||
qY
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -10896,12 +10879,12 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
bG
|
||||
bU
|
||||
cp
|
||||
cC
|
||||
bn
|
||||
rn
|
||||
dh
|
||||
dt
|
||||
dF
|
||||
@@ -10942,7 +10925,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
ag
|
||||
bn
|
||||
rn
|
||||
pT
|
||||
mU
|
||||
mU
|
||||
@@ -11035,15 +11018,15 @@ aj
|
||||
ac
|
||||
ag
|
||||
aW
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
qh
|
||||
qs
|
||||
qD
|
||||
qL
|
||||
bn
|
||||
rn
|
||||
ro
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -11128,7 +11111,7 @@ ag
|
||||
ag
|
||||
ag
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
qi
|
||||
qt
|
||||
ka
|
||||
@@ -11136,7 +11119,7 @@ hY
|
||||
ra
|
||||
qy
|
||||
rw
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -11505,7 +11488,7 @@ re
|
||||
qM
|
||||
hY
|
||||
qw
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -11598,7 +11581,7 @@ hY
|
||||
hY
|
||||
qy
|
||||
rJ
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -11683,7 +11666,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
qN
|
||||
rf
|
||||
hY
|
||||
@@ -11966,7 +11949,7 @@ hY
|
||||
hY
|
||||
rk
|
||||
rN
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -12059,7 +12042,7 @@ rq
|
||||
hY
|
||||
rO
|
||||
rZ
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -12142,7 +12125,7 @@ if
|
||||
if
|
||||
if
|
||||
if
|
||||
bn
|
||||
rn
|
||||
qy
|
||||
qR
|
||||
ri
|
||||
@@ -12242,9 +12225,9 @@ rs
|
||||
rz
|
||||
qu
|
||||
rQ
|
||||
bn
|
||||
bn
|
||||
bn
|
||||
rn
|
||||
rn
|
||||
rn
|
||||
sh
|
||||
ac
|
||||
kJ
|
||||
@@ -12326,7 +12309,7 @@ if
|
||||
if
|
||||
if
|
||||
if
|
||||
bn
|
||||
rn
|
||||
qw
|
||||
qS
|
||||
rk
|
||||
@@ -12419,7 +12402,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
qv
|
||||
hY
|
||||
ru
|
||||
@@ -12427,7 +12410,7 @@ ru
|
||||
hY
|
||||
rS
|
||||
rZ
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -12518,7 +12501,7 @@ hY
|
||||
hY
|
||||
rk
|
||||
rT
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -12787,7 +12770,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
qN
|
||||
qt
|
||||
hY
|
||||
@@ -12886,7 +12869,7 @@ hY
|
||||
hY
|
||||
qy
|
||||
rX
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -12977,7 +12960,7 @@ hY
|
||||
hY
|
||||
hY
|
||||
rG
|
||||
bn
|
||||
rn
|
||||
aW
|
||||
ac
|
||||
ac
|
||||
@@ -13336,7 +13319,7 @@ ac
|
||||
ag
|
||||
ag
|
||||
aW
|
||||
bn
|
||||
rn
|
||||
qm
|
||||
qz
|
||||
jn
|
||||
@@ -13344,7 +13327,7 @@ hY
|
||||
rl
|
||||
rv
|
||||
rD
|
||||
bn
|
||||
rn
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -14342,7 +14325,7 @@ ok
|
||||
oB
|
||||
ok
|
||||
pb
|
||||
pg
|
||||
nV
|
||||
bm
|
||||
py
|
||||
dJ
|
||||
@@ -14690,16 +14673,16 @@ go
|
||||
gV
|
||||
hn
|
||||
aV
|
||||
hU
|
||||
hU
|
||||
pC
|
||||
pC
|
||||
hT
|
||||
jf
|
||||
hU
|
||||
pC
|
||||
kC
|
||||
ll
|
||||
hU
|
||||
hU
|
||||
hU
|
||||
pC
|
||||
pC
|
||||
pC
|
||||
hT
|
||||
bm
|
||||
ng
|
||||
@@ -14783,16 +14766,16 @@ gW
|
||||
gH
|
||||
hH
|
||||
hT
|
||||
hU
|
||||
pC
|
||||
iL
|
||||
eD
|
||||
jI
|
||||
kD
|
||||
lm
|
||||
eD
|
||||
hU
|
||||
hU
|
||||
hU
|
||||
pC
|
||||
pC
|
||||
pC
|
||||
mQ
|
||||
ng
|
||||
ng
|
||||
|
||||
@@ -3487,7 +3487,6 @@
|
||||
"jx" = (
|
||||
/obj/structure/table,
|
||||
/obj/structure/window/reinforced,
|
||||
/obj/item/batterer,
|
||||
/turf/simulated/floor/plasteel/airless{
|
||||
dir = 4;
|
||||
icon_state = "whitered"
|
||||
|
||||
@@ -2091,19 +2091,8 @@
|
||||
name = "Syndicate Outpost"
|
||||
})
|
||||
"dr" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective_locked";
|
||||
name = "personal closet";
|
||||
req_access_txt = "150"
|
||||
},
|
||||
/obj/item/ammo_box/magazine/m10mm,
|
||||
/obj/item/ammo_box/magazine/m10mm,
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/suppressor,
|
||||
/turf/simulated/floor/plasteel/airless{
|
||||
dir = 8;
|
||||
@@ -2114,18 +2103,7 @@
|
||||
name = "Syndicate Outpost"
|
||||
})
|
||||
"ds" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "150"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/stack/spacecash/c50,
|
||||
/turf/simulated/floor/wood,
|
||||
/area/awaycontent/a4{
|
||||
@@ -3954,16 +3932,6 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a7)
|
||||
"gj" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/obj/item/reagent_containers/spray/pepper,
|
||||
/obj/item/grenade/flashbang,
|
||||
@@ -3977,6 +3945,7 @@
|
||||
pixel_y = 23;
|
||||
req_access = null
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 1;
|
||||
icon_state = "red"
|
||||
@@ -5142,18 +5111,8 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"hX" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secureresbroken";
|
||||
icon_closed = "secureres";
|
||||
icon_locked = "secureres1";
|
||||
icon_off = "secureresoff";
|
||||
icon_opened = "secureresopen";
|
||||
icon_state = "secureres";
|
||||
locked = 0;
|
||||
name = "scientist's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/item/clothing/suit/storage/labcoat,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a2{
|
||||
name = "MO19 Research"
|
||||
@@ -5392,20 +5351,11 @@
|
||||
})
|
||||
"iq" = (
|
||||
/obj/structure/window/reinforced,
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secureresbroken";
|
||||
icon_closed = "secureres";
|
||||
icon_locked = "secureres1";
|
||||
icon_off = "secureresoff";
|
||||
icon_opened = "secureresopen";
|
||||
icon_state = "secureres1";
|
||||
name = "scientist's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/item/clothing/suit/storage/labcoat,
|
||||
/obj/item/tank/internals/air,
|
||||
/obj/item/clothing/mask/gas,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a2{
|
||||
name = "MO19 Research"
|
||||
@@ -5961,18 +5911,9 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"jr" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "rdsecurebroken";
|
||||
icon_closed = "rdsecure";
|
||||
icon_locked = "rdsecure1";
|
||||
icon_off = "rdsecureoff";
|
||||
icon_opened = "rdsecureopen";
|
||||
icon_state = "rdsecure1";
|
||||
name = "research director's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/item/storage/backpack/satchel_tox,
|
||||
/obj/item/clothing/gloves/color/latex,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 5;
|
||||
icon_state = "cafeteria"
|
||||
@@ -8696,18 +8637,7 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"oA" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/suit_jacket/navy,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a1{
|
||||
@@ -8817,21 +8747,11 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"oK" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "fridgebroken";
|
||||
icon_closed = "fridge";
|
||||
icon_locked = "fridge1";
|
||||
icon_off = "fridgeoff";
|
||||
icon_opened = "fridgeopen";
|
||||
icon_state = "fridge";
|
||||
locked = 0;
|
||||
name = "meat fridge";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/structure/closet/secure_closet/freezer/meat,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "showroomfloor";
|
||||
temperature = 273.15
|
||||
@@ -8841,7 +8761,6 @@
|
||||
})
|
||||
"oL" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_state = "secure";
|
||||
locked = 0;
|
||||
name = "kitchen Cabinet";
|
||||
req_access_txt = "271"
|
||||
@@ -8858,21 +8777,11 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"oM" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "fridgebroken";
|
||||
icon_closed = "fridge";
|
||||
icon_locked = "fridge1";
|
||||
icon_off = "fridgeoff";
|
||||
icon_opened = "fridgeopen";
|
||||
icon_state = "fridge";
|
||||
locked = 0;
|
||||
name = "refrigerator";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/storage/fancy/egg_box,
|
||||
/obj/structure/closet/secure_closet/freezer/fridge,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "showroomfloor";
|
||||
temperature = 273.15
|
||||
@@ -8981,18 +8890,7 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"oZ" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/assistantformal,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a1{
|
||||
@@ -9015,18 +8913,7 @@
|
||||
name = "MO19 Arrivals"
|
||||
})
|
||||
"pg" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/suit_jacket/burgundy,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a1{
|
||||
|
||||
@@ -196,18 +196,7 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/plaza)
|
||||
"aF" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/suit_jacket/female,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/plaza)
|
||||
@@ -420,18 +409,7 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/plaza)
|
||||
"bh" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/plaza)
|
||||
"bi" = (
|
||||
@@ -752,18 +730,7 @@
|
||||
/area/awaymission/UO71/plaza)
|
||||
"ci" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/pj/blue,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/plaza)
|
||||
@@ -1217,17 +1184,7 @@
|
||||
},
|
||||
/area/awaymission/UO71/plaza)
|
||||
"ds" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "hydrosecurebroken";
|
||||
icon_closed = "hydrosecure";
|
||||
icon_locked = "hydrosecure1";
|
||||
icon_off = "hydrosecureoff";
|
||||
icon_opened = "hydrosecureopen";
|
||||
icon_state = "hydrosecure";
|
||||
locked = 0;
|
||||
name = "botanist's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/obj/item/plant_analyzer,
|
||||
/obj/item/clothing/mask/bandana,
|
||||
/obj/item/hatchet,
|
||||
@@ -1257,16 +1214,7 @@
|
||||
},
|
||||
/area/awaymission/UO71/plaza)
|
||||
"dw" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/obj/item/storage/belt/security,
|
||||
/obj/item/flash,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
@@ -1372,17 +1320,7 @@
|
||||
},
|
||||
/area/awaymission/UO71/plaza)
|
||||
"dK" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "hydrosecurebroken";
|
||||
icon_closed = "hydrosecure";
|
||||
icon_locked = "hydrosecure1";
|
||||
icon_off = "hydrosecureoff";
|
||||
icon_opened = "hydrosecureopen";
|
||||
icon_state = "hydrosecure";
|
||||
locked = 0;
|
||||
name = "botanist's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/obj/item/clothing/suit/apron,
|
||||
/obj/item/clothing/mask/bandana,
|
||||
/turf/simulated/floor/plasteel{
|
||||
@@ -2200,17 +2138,7 @@
|
||||
},
|
||||
/area/awaymission/UO71/centralhall)
|
||||
"fH" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "fridgebroken";
|
||||
icon_closed = "fridge";
|
||||
icon_locked = "fridge1";
|
||||
icon_off = "fridgeoff";
|
||||
icon_opened = "fridgeopen";
|
||||
icon_state = "fridge";
|
||||
locked = 0;
|
||||
name = "meat fridge";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet/freezer/meat,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
@@ -3316,17 +3244,7 @@
|
||||
},
|
||||
/area/awaymission/UO71/centralhall)
|
||||
"ir" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "fridgebroken";
|
||||
icon_closed = "fridge";
|
||||
icon_locked = "fridge1";
|
||||
icon_off = "fridgeoff";
|
||||
icon_opened = "fridgeopen";
|
||||
icon_state = "fridge";
|
||||
locked = 0;
|
||||
name = "refrigerator";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet/freezer/fridge,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
@@ -3524,7 +3442,6 @@
|
||||
/area/awaymission/UO71/centralhall)
|
||||
"iX" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_state = "secure";
|
||||
locked = 0;
|
||||
name = "kitchen Cabinet";
|
||||
req_access_txt = "271"
|
||||
@@ -5271,18 +5188,7 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/centralhall)
|
||||
"mF" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/pj/red,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/centralhall)
|
||||
@@ -5464,16 +5370,7 @@
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaymission/UO71/science)
|
||||
"mX" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "rdsecurebroken";
|
||||
icon_closed = "rdsecure";
|
||||
icon_locked = "rdsecure1";
|
||||
icon_off = "rdsecureoff";
|
||||
icon_opened = "rdsecureopen";
|
||||
icon_state = "rdsecure1";
|
||||
name = "research director's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/obj/item/storage/backpack/satchel_tox,
|
||||
/obj/item/clothing/gloves/color/latex,
|
||||
/obj/item/clothing/suit/storage/labcoat/science,
|
||||
@@ -5589,18 +5486,7 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/centralhall)
|
||||
"nj" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/obj/item/clothing/under/suit_jacket/navy,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/centralhall)
|
||||
@@ -6700,16 +6586,7 @@
|
||||
},
|
||||
/area/awaymission/UO71/science)
|
||||
"pb" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/obj/item/flash,
|
||||
/obj/item/reagent_containers/spray/pepper,
|
||||
/obj/item/restraints/handcuffs,
|
||||
@@ -7644,15 +7521,8 @@
|
||||
},
|
||||
/area/awaymission/UO71/eng)
|
||||
"qY" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secureengbroken";
|
||||
icon_closed = "secureeng";
|
||||
icon_locked = "secureeng1";
|
||||
icon_off = "secureengoff";
|
||||
icon_opened = "secureengopen";
|
||||
icon_state = "secureeng1";
|
||||
name = "engineer's locker";
|
||||
req_access_txt = "271"
|
||||
/obj/structure/closet/secure_closet/engineering_personal{
|
||||
req_access = list(271)
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
@@ -9557,16 +9427,7 @@
|
||||
pixel_y = 6;
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/secure_closet,
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/obj/item/clothing/head/helmet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
@@ -10743,18 +10604,7 @@
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/mining)
|
||||
"xj" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/mining)
|
||||
"xk" = (
|
||||
@@ -11063,18 +10913,7 @@
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/on{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/mining)
|
||||
"xQ" = (
|
||||
@@ -11091,15 +10930,7 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/closet/secure_closet/engineering_personal{
|
||||
icon_broken = "miningsecbroken";
|
||||
icon_closed = "miningsec";
|
||||
icon_locked = "miningsec1";
|
||||
icon_off = "miningsecoff";
|
||||
icon_opened = "miningsecopen";
|
||||
icon_state = "miningsec";
|
||||
locked = 0;
|
||||
name = "miner's equipment";
|
||||
/obj/structure/closet/secure_closet/miner{
|
||||
req_access = list(271)
|
||||
},
|
||||
/obj/item/storage/backpack/satchel_eng,
|
||||
@@ -11689,18 +11520,7 @@
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaymission/UO71/queen)
|
||||
"zn" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaymission/UO71/loot)
|
||||
"zo" = (
|
||||
|
||||
@@ -192,8 +192,8 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"aE" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
},
|
||||
@@ -258,11 +258,11 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"aL" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/sign/poster/official/safety_internals{
|
||||
pixel_x = -32
|
||||
},
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
},
|
||||
@@ -1082,8 +1082,8 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"cw" = (
|
||||
/obj/structure/closet,
|
||||
/obj/item/storage/box/lights/mixed,
|
||||
/obj/structure/closet,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -1119,19 +1119,8 @@
|
||||
})
|
||||
"cz" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/under/pj/blue,
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -1141,19 +1130,8 @@
|
||||
dir = 8;
|
||||
initialize_directions = 7
|
||||
},
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/under/suit_jacket/female,
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -1196,8 +1174,8 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"cE" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -1434,8 +1412,8 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
|
||||
dir = 5
|
||||
},
|
||||
/obj/structure/closet,
|
||||
/obj/item/poster/random_contraband,
|
||||
/obj/structure/closet,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -1801,20 +1779,10 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"dM" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "hydrosecurebroken";
|
||||
icon_closed = "hydrosecure";
|
||||
icon_locked = "hydrosecure1";
|
||||
icon_off = "hydrosecureoff";
|
||||
icon_opened = "hydrosecureopen";
|
||||
icon_state = "hydrosecure";
|
||||
locked = 0;
|
||||
name = "botanist's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/plant_analyzer,
|
||||
/obj/item/clothing/mask/bandana,
|
||||
/obj/item/hatchet,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 4;
|
||||
icon_state = "vault"
|
||||
@@ -1861,19 +1829,10 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"dQ" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/storage/belt/security,
|
||||
/obj/item/flash,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 9;
|
||||
icon_state = "red"
|
||||
@@ -2009,20 +1968,10 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"ee" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "hydrosecurebroken";
|
||||
icon_closed = "hydrosecure";
|
||||
icon_locked = "hydrosecure1";
|
||||
icon_off = "hydrosecureoff";
|
||||
icon_opened = "hydrosecureopen";
|
||||
icon_state = "hydrosecure";
|
||||
locked = 0;
|
||||
name = "botanist's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/suit/apron,
|
||||
/obj/item/clothing/mask/bandana,
|
||||
/obj/item/cultivator,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 4;
|
||||
icon_state = "vault"
|
||||
@@ -2475,7 +2424,6 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"eW" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/sign/securearea{
|
||||
desc = "A warning sign which reads 'EXTERNAL AIRLOCK'";
|
||||
@@ -2749,11 +2697,11 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"fu" = (
|
||||
/obj/structure/closet/crate/hydroponics,
|
||||
/obj/item/shovel/spade,
|
||||
/obj/item/wrench,
|
||||
/obj/item/screwdriver,
|
||||
/obj/item/reagent_containers/glass/bucket,
|
||||
/obj/structure/closet/crate/hydroponics,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
},
|
||||
@@ -3211,13 +3159,13 @@
|
||||
name = "UO45 Crew Quarters"
|
||||
})
|
||||
"gn" = (
|
||||
/obj/item/storage/box/mousetraps,
|
||||
/obj/item/clothing/under/waiter,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/crate{
|
||||
desc = "It's a storage unit for kitchen clothes and equipment.";
|
||||
name = "Kitchen Crate"
|
||||
},
|
||||
/obj/item/storage/box/mousetraps,
|
||||
/obj/item/clothing/under/waiter,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "showroomfloor"
|
||||
},
|
||||
@@ -3225,21 +3173,11 @@
|
||||
name = "UO45 Crew Quarters"
|
||||
})
|
||||
"go" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "fridgebroken";
|
||||
icon_closed = "fridge";
|
||||
icon_locked = "fridge1";
|
||||
icon_off = "fridgeoff";
|
||||
icon_opened = "fridgeopen";
|
||||
icon_state = "fridge";
|
||||
locked = 0;
|
||||
name = "meat fridge";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/item/reagent_containers/food/snacks/meat/monkey,
|
||||
/obj/structure/closet/secure_closet/freezer/meat,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "showroomfloor"
|
||||
},
|
||||
@@ -3867,12 +3805,12 @@
|
||||
name = "UO45 Gateway"
|
||||
})
|
||||
"hz" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/sign/poster/official/safety_internals{
|
||||
pixel_y = 32
|
||||
},
|
||||
/obj/effect/landmark/burnturf,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a2{
|
||||
name = "UO45 Crew Quarters"
|
||||
@@ -4229,8 +4167,8 @@
|
||||
name = "UO45 Gateway"
|
||||
})
|
||||
"if" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a6{
|
||||
name = "UO45 Gateway"
|
||||
@@ -4569,22 +4507,12 @@
|
||||
name = "UO45 Crew Quarters"
|
||||
})
|
||||
"iM" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "fridgebroken";
|
||||
icon_closed = "fridge";
|
||||
icon_locked = "fridge1";
|
||||
icon_off = "fridgeoff";
|
||||
icon_opened = "fridgeopen";
|
||||
icon_state = "fridge";
|
||||
locked = 0;
|
||||
name = "refrigerator";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/reagent_containers/food/condiment/milk,
|
||||
/obj/item/storage/fancy/egg_box,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet/freezer/fridge,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 5;
|
||||
icon_state = "cafeteria"
|
||||
@@ -4611,9 +4539,9 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"iO" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/effect/landmark/damageturf,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -4664,8 +4592,8 @@
|
||||
name = "UO45 Gateway"
|
||||
})
|
||||
"iT" = (
|
||||
/obj/structure/closet/l3closet/scientist,
|
||||
/obj/effect/decal/warning_stripes/north,
|
||||
/obj/structure/closet/l3closet/scientist,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a6{
|
||||
name = "UO45 Gateway"
|
||||
@@ -4821,16 +4749,15 @@
|
||||
name = "UO45 Crew Quarters"
|
||||
})
|
||||
"jg" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_state = "secure";
|
||||
locked = 0;
|
||||
name = "kitchen Cabinet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/reagent_containers/food/condiment/flour,
|
||||
/obj/item/reagent_containers/food/condiment/flour,
|
||||
/obj/item/reagent_containers/food/condiment/sugar,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet{
|
||||
locked = 0;
|
||||
name = "kitchen Cabinet";
|
||||
req_access_txt = "271"
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 5;
|
||||
icon_state = "cafeteria"
|
||||
@@ -4849,8 +4776,8 @@
|
||||
name = "UO45 Gateway"
|
||||
})
|
||||
"ji" = (
|
||||
/obj/structure/closet/l3closet/scientist,
|
||||
/obj/effect/decal/warning_stripes/northeast,
|
||||
/obj/structure/closet/l3closet/scientist,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a6{
|
||||
name = "UO45 Gateway"
|
||||
@@ -5091,17 +5018,6 @@
|
||||
name = "UO45 Central Hall"
|
||||
})
|
||||
"jG" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secureresbroken";
|
||||
icon_closed = "secureres";
|
||||
icon_locked = "secureres1";
|
||||
icon_off = "secureresoff";
|
||||
icon_opened = "secureresopen";
|
||||
icon_state = "secureres";
|
||||
locked = 0;
|
||||
name = "scientist's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/tank/internals/air,
|
||||
/obj/item/clothing/mask/gas,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
@@ -5115,17 +5031,6 @@
|
||||
/obj/machinery/light/small{
|
||||
dir = 1
|
||||
},
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secureresbroken";
|
||||
icon_closed = "secureres";
|
||||
icon_locked = "secureres1";
|
||||
icon_off = "secureresoff";
|
||||
icon_opened = "secureresopen";
|
||||
icon_state = "secureres";
|
||||
locked = 0;
|
||||
name = "scientist's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/gloves/color/latex,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "white"
|
||||
@@ -5629,13 +5534,13 @@
|
||||
name = "UO45 Research"
|
||||
})
|
||||
"kx" = (
|
||||
/obj/structure/closet/crate,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/item/storage/toolbox/mechanical{
|
||||
pixel_x = -2;
|
||||
pixel_y = -1
|
||||
},
|
||||
/obj/item/multitool,
|
||||
/obj/structure/closet/crate,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a1{
|
||||
name = "UO45 Central Hall"
|
||||
@@ -6729,7 +6634,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"lZ" = (
|
||||
/obj/structure/closet/crate,
|
||||
/obj/item/stack/sheet/mineral/plasma{
|
||||
amount = 26
|
||||
},
|
||||
@@ -6742,6 +6646,7 @@
|
||||
maxcharge = 15000
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/crate,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a3{
|
||||
name = "UO45 Engineering"
|
||||
@@ -6876,12 +6781,12 @@
|
||||
name = "UO45 Research"
|
||||
})
|
||||
"mm" = (
|
||||
/obj/structure/closet/firecloset,
|
||||
/obj/machinery/light/small,
|
||||
/obj/structure/sign/securearea{
|
||||
pixel_y = -32
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/firecloset,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "warnwhite"
|
||||
},
|
||||
@@ -6987,19 +6892,8 @@
|
||||
name = "UO45 Crew Quarters"
|
||||
})
|
||||
"mw" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/under/pj/red,
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a2{
|
||||
name = "UO45 Crew Quarters"
|
||||
@@ -7051,7 +6945,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"mB" = (
|
||||
/obj/structure/closet/crate,
|
||||
/obj/item/stack/sheet/metal{
|
||||
amount = 50
|
||||
},
|
||||
@@ -7061,6 +6954,7 @@
|
||||
/obj/item/stack/rods{
|
||||
amount = 50
|
||||
},
|
||||
/obj/structure/closet/crate,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a3{
|
||||
name = "UO45 Engineering"
|
||||
@@ -7135,20 +7029,11 @@
|
||||
name = "UO45 Gateway"
|
||||
})
|
||||
"mI" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "rdsecurebroken";
|
||||
icon_closed = "rdsecure";
|
||||
icon_locked = "rdsecure1";
|
||||
icon_off = "rdsecureoff";
|
||||
icon_opened = "rdsecureopen";
|
||||
icon_state = "rdsecure1";
|
||||
name = "research director's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/storage/backpack/satchel_tox,
|
||||
/obj/item/clothing/gloves/color/latex,
|
||||
/obj/item/clothing/suit/storage/labcoat/science,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 5;
|
||||
icon_state = "cafeteria"
|
||||
@@ -7334,19 +7219,8 @@
|
||||
name = "UO45 Crew Quarters"
|
||||
})
|
||||
"mZ" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/under/suit_jacket/navy,
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a2{
|
||||
name = "UO45 Crew Quarters"
|
||||
@@ -7657,6 +7531,7 @@
|
||||
})
|
||||
"nz" = (
|
||||
/obj/machinery/vending/coffee,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "dark"
|
||||
},
|
||||
@@ -8474,6 +8349,7 @@
|
||||
pixel_x = -30
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 8;
|
||||
icon_state = "red"
|
||||
@@ -8893,16 +8769,6 @@
|
||||
name = "UO45 Research"
|
||||
})
|
||||
"pi" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/on,
|
||||
/obj/item/restraints/handcuffs,
|
||||
/obj/item/flash,
|
||||
@@ -9369,7 +9235,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"qa" = (
|
||||
/obj/structure/closet/crate,
|
||||
/obj/item/storage/box/lights/mixed,
|
||||
/obj/item/poster/random_contraband,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
@@ -9553,6 +9418,7 @@
|
||||
})
|
||||
"qq" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/l3closet/general,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 8;
|
||||
icon_state = "whitehall"
|
||||
@@ -9729,13 +9595,13 @@
|
||||
dir = 4;
|
||||
layer = 2.9
|
||||
},
|
||||
/obj/structure/closet/secure_closet/engineering_personal{
|
||||
req_access = list(201)
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/purple{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/closet/secure_closet/engineering_personal{
|
||||
req_access = list(271)
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 1;
|
||||
icon_state = "yellow"
|
||||
@@ -9759,16 +9625,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"qH" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secureengbroken";
|
||||
icon_closed = "secureeng";
|
||||
icon_locked = "secureeng1";
|
||||
icon_off = "secureengoff";
|
||||
icon_opened = "secureengopen";
|
||||
icon_state = "secureeng1";
|
||||
name = "engineer's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
},
|
||||
@@ -9779,6 +9635,9 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/visible/purple{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/closet/secure_closet/engineering_personal{
|
||||
req_access = list(271)
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 1;
|
||||
icon_state = "yellow"
|
||||
@@ -10989,7 +10848,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"sr" = (
|
||||
/obj/structure/closet/l3closet/general,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 1;
|
||||
@@ -11045,7 +10903,6 @@
|
||||
name = "UO45 Research"
|
||||
})
|
||||
"sw" = (
|
||||
/obj/structure/closet/l3closet/general,
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 1;
|
||||
@@ -11355,9 +11212,9 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"sU" = (
|
||||
/obj/structure/closet,
|
||||
/obj/item/storage/belt/utility,
|
||||
/obj/effect/landmark/burnturf,
|
||||
/obj/structure/closet,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a2{
|
||||
name = "UO45 Crew Quarters"
|
||||
@@ -11447,7 +11304,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"te" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/structure/sign/securearea{
|
||||
desc = "A warning sign which reads 'EXTERNAL AIRLOCK'";
|
||||
@@ -11733,7 +11589,6 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"tA" = (
|
||||
/obj/structure/closet/firecloset,
|
||||
/obj/effect/decal/warning_stripes/northwest,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a5{
|
||||
@@ -12057,18 +11912,9 @@
|
||||
pixel_y = 6;
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/structure/closet/secure_closet{
|
||||
icon_broken = "secbroken";
|
||||
icon_closed = "sec";
|
||||
icon_locked = "sec1";
|
||||
icon_off = "secoff";
|
||||
icon_opened = "secopen";
|
||||
icon_state = "sec1";
|
||||
name = "security officer's locker";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/item/clothing/suit/armor/vest,
|
||||
/obj/item/clothing/head/helmet,
|
||||
/obj/structure/closet/secure_closet,
|
||||
/turf/simulated/floor/plasteel{
|
||||
dir = 6;
|
||||
icon_state = "red"
|
||||
@@ -12256,6 +12102,7 @@
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/decal/warning_stripes/west,
|
||||
/obj/structure/closet/firecloset,
|
||||
/turf/simulated/floor/plating,
|
||||
/area/awaycontent/a5{
|
||||
name = "UO45 Research"
|
||||
@@ -12666,22 +12513,22 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"vc" = (
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/item/clothing/mask/breath,
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/decal/warning_stripes/yellow/hollow,
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a3{
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"vd" = (
|
||||
/obj/structure/closet/firecloset,
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/decal/warning_stripes/yellow/hollow,
|
||||
/obj/structure/closet/firecloset,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a3{
|
||||
name = "UO45 Engineering"
|
||||
@@ -12739,11 +12586,11 @@
|
||||
name = "UO45 Engineering"
|
||||
})
|
||||
"vi" = (
|
||||
/obj/structure/closet/firecloset,
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
|
||||
dir = 9
|
||||
},
|
||||
/obj/effect/decal/warning_stripes/yellow/hollow,
|
||||
/obj/structure/closet/firecloset,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a3{
|
||||
name = "UO45 Engineering"
|
||||
@@ -13138,10 +12985,10 @@
|
||||
dir = 1;
|
||||
pixel_y = -24
|
||||
},
|
||||
/obj/structure/closet/secure_closet/miner{
|
||||
req_access = list(201)
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/secure_closet/miner{
|
||||
req_access = list(271)
|
||||
},
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a4{
|
||||
name = "UO45 Mining"
|
||||
@@ -13428,18 +13275,7 @@
|
||||
name = "UO45 Mining"
|
||||
})
|
||||
"wq" = (
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a4{
|
||||
name = "UO45 Mining"
|
||||
@@ -13806,19 +13642,11 @@
|
||||
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/closet/secure_closet/engineering_personal{
|
||||
icon_broken = "miningsecbroken";
|
||||
icon_closed = "miningsec";
|
||||
icon_locked = "miningsec1";
|
||||
icon_off = "miningsecoff";
|
||||
icon_opened = "miningsecopen";
|
||||
icon_state = "miningsec";
|
||||
locked = 0;
|
||||
name = "miner's equipment";
|
||||
req_access = list(201)
|
||||
},
|
||||
/obj/item/storage/backpack/satchel_eng,
|
||||
/obj/item/clothing/gloves/fingerless,
|
||||
/obj/structure/closet/secure_closet/miner{
|
||||
req_access = list(271)
|
||||
},
|
||||
/turf/simulated/floor/plasteel{
|
||||
icon_state = "browncorner"
|
||||
},
|
||||
@@ -13848,18 +13676,7 @@
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/on{
|
||||
dir = 4
|
||||
},
|
||||
/obj/structure/closet/secure_closet{
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control.";
|
||||
icon_broken = "cabinetdetective_broken";
|
||||
icon_closed = "cabinetdetective";
|
||||
icon_locked = "cabinetdetective_locked";
|
||||
icon_off = "cabinetdetective_broken";
|
||||
icon_opened = "cabinetdetective_open";
|
||||
icon_state = "cabinetdetective";
|
||||
locked = 0;
|
||||
name = "personal closet";
|
||||
req_access_txt = "201"
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/carpet,
|
||||
/area/awaycontent/a4{
|
||||
name = "UO45 Mining"
|
||||
@@ -14045,7 +13862,6 @@
|
||||
dir = 4;
|
||||
initialize_directions = 11
|
||||
},
|
||||
/obj/structure/closet/crate,
|
||||
/obj/item/stack/sheet/metal{
|
||||
amount = 26
|
||||
},
|
||||
@@ -14053,6 +13869,7 @@
|
||||
amount = 19
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/structure/closet/crate,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a4{
|
||||
name = "UO45 Mining"
|
||||
@@ -14091,7 +13908,6 @@
|
||||
dir = 4;
|
||||
pixel_x = 24
|
||||
},
|
||||
/obj/structure/closet/crate,
|
||||
/obj/item/stack/sheet/mineral/plasma{
|
||||
amount = 6
|
||||
},
|
||||
@@ -14148,17 +13964,15 @@
|
||||
name = "UO45 Mining"
|
||||
})
|
||||
"xv" = (
|
||||
/obj/machinery/alarm/monitor{
|
||||
dir = 4;
|
||||
locked = 0;
|
||||
pixel_x = -23;
|
||||
req_access = null
|
||||
},
|
||||
/obj/structure/closet/emcloset,
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/turf/simulated/floor/plasteel,
|
||||
/area/awaycontent/a4{
|
||||
name = "UO45 Mining"
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/mineral/random/labormineral,
|
||||
/area/awaycontent/a7{
|
||||
always_unpowered = 1;
|
||||
name = "UO45 Caves";
|
||||
power_environ = 0;
|
||||
power_equip = 0;
|
||||
power_light = 0;
|
||||
poweralm = 0
|
||||
})
|
||||
"xw" = (
|
||||
/obj/structure/table,
|
||||
@@ -14512,15 +14326,10 @@
|
||||
poweralm = 0
|
||||
})
|
||||
"yn" = (
|
||||
/obj/structure/closet/crate,
|
||||
/turf/simulated/floor/plating/asteroid/airless,
|
||||
/area/awaycontent/a7{
|
||||
always_unpowered = 1;
|
||||
name = "UO45 Caves";
|
||||
power_environ = 0;
|
||||
power_equip = 0;
|
||||
power_light = 0;
|
||||
poweralm = 0
|
||||
/obj/structure/closet/emcloset,
|
||||
/turf/simulated/wall/r_wall/rust,
|
||||
/area/awaycontent/a4{
|
||||
name = "UO45 Mining"
|
||||
})
|
||||
"yo" = (
|
||||
/obj/structure/alien/weeds{
|
||||
@@ -24626,11 +24435,11 @@ aB
|
||||
aB
|
||||
aC
|
||||
aC
|
||||
xv
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
xv
|
||||
ac
|
||||
ac
|
||||
bQ
|
||||
@@ -25901,7 +25710,7 @@ yl
|
||||
fo
|
||||
fo
|
||||
fo
|
||||
yn
|
||||
fo
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
@@ -26044,7 +25853,7 @@ xG
|
||||
xO
|
||||
xn
|
||||
wx
|
||||
xv
|
||||
vy
|
||||
xB
|
||||
wx
|
||||
ev
|
||||
@@ -26496,7 +26305,7 @@ vJ
|
||||
vJ
|
||||
vJ
|
||||
vJ
|
||||
vJ
|
||||
yn
|
||||
yl
|
||||
fo
|
||||
fo
|
||||
@@ -29954,7 +29763,7 @@ ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
xv
|
||||
ac
|
||||
ac
|
||||
ac
|
||||
|
||||
+5090
-7352
File diff suppressed because it is too large
Load Diff
@@ -4044,9 +4044,9 @@
|
||||
/area/shuttle/gamma/space)
|
||||
"oC" = (
|
||||
/obj/structure/closet/secure_closet/guncabinet,
|
||||
/obj/item/gun/energy/sniperrifle,
|
||||
/obj/item/gun/energy/sniperrifle,
|
||||
/obj/item/gun/energy/sniperrifle,
|
||||
/obj/item/gun/energy/ionrifle,
|
||||
/obj/item/gun/energy/ionrifle,
|
||||
/obj/item/gun/energy/ionrifle,
|
||||
/obj/machinery/light/spot{
|
||||
dir = 4
|
||||
},
|
||||
@@ -4558,11 +4558,6 @@
|
||||
/obj/item/ammo_box/magazine/m45,
|
||||
/obj/item/ammo_box/magazine/m45,
|
||||
/obj/item/ammo_box/magazine/m45,
|
||||
/obj/structure/closet{
|
||||
icon_closed = "cabinet_closed";
|
||||
icon_opened = "cabinet_open";
|
||||
icon_state = "cabinet_closed"
|
||||
},
|
||||
/obj/item/clothing/head/helmet/space/deathsquad/beret,
|
||||
/obj/item/clothing/shoes/combat,
|
||||
/obj/item/clothing/under/syndicate/combat,
|
||||
@@ -4577,6 +4572,7 @@
|
||||
pixel_x = 6;
|
||||
pixel_y = -6
|
||||
},
|
||||
/obj/structure/closet/cabinet,
|
||||
/turf/simulated/floor/plasteel/grimy,
|
||||
/area/centcom/specops)
|
||||
"ql" = (
|
||||
|
||||
@@ -786,11 +786,11 @@
|
||||
/area/shuttle/administration)
|
||||
"PV" = (
|
||||
/obj/structure/rack,
|
||||
/obj/item/gun/energy/sniperrifle{
|
||||
/obj/item/gun/energy/ionrifle{
|
||||
pixel_y = -4
|
||||
},
|
||||
/obj/item/gun/energy/sniperrifle,
|
||||
/obj/item/gun/energy/sniperrifle{
|
||||
/obj/item/gun/energy/ionrifle,
|
||||
/obj/item/gun/energy/ionrifle{
|
||||
pixel_y = 3
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
@@ -882,11 +882,11 @@
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
},
|
||||
/obj/item/gun/energy/gun/advtaser{
|
||||
/obj/item/gun/energy/disabler{
|
||||
pixel_x = 3;
|
||||
pixel_y = -3
|
||||
},
|
||||
/obj/item/gun/energy/gun/advtaser,
|
||||
/obj/item/gun/energy/disabler,
|
||||
/turf/simulated/floor/mineral/plastitanium/red,
|
||||
/area/shuttle/administration)
|
||||
"WV" = (
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/// Version of RUST-G that this codebase wants
|
||||
#define RUST_G_VERSION "0.5.0-P"
|
||||
@@ -123,3 +123,7 @@
|
||||
#define COLOR_THEME_OPERATIVE "#B8221F"
|
||||
#define COLOR_THEME_GLASS "#75A4C4"
|
||||
#define COLOR_THEME_CLOCKWORK "#CFBA47"
|
||||
|
||||
// Color matrix utilities
|
||||
#define COLOR_MATRIX_ADD(C) list(COLOR_RED, COLOR_GREEN, COLOR_BLUE, C)
|
||||
#define COLOR_MATRIX_OVERLAY(C) list(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK, C)
|
||||
|
||||
@@ -181,7 +181,7 @@ GLOBAL_LIST_INIT(clawfootstep, list(
|
||||
'sound/effects/footstep/lava3.ogg'), 100, 0),
|
||||
FOOTSTEP_MEAT = list(list(
|
||||
'sound/effects/meatslap.ogg'), 100, 0),
|
||||
FOOTSTEP_GLASS = list(list(
|
||||
FOOTSTEP_GLASS_BAREFOOT = list(list(
|
||||
'sound/effects/footstep/glassbarefoot1.ogg',
|
||||
'sound/effects/footstep/glassbarefoot2.ogg',
|
||||
'sound/effects/footstep/glassbarefoot3.ogg'), 100, 1),
|
||||
|
||||
+25
-24
@@ -7,58 +7,59 @@
|
||||
|
||||
#define JOBCAT_ENGSEC (1<<0)
|
||||
|
||||
#define JOB_CAPTAIN (1<<0)
|
||||
#define JOB_HOS (1<<1)
|
||||
#define JOB_WARDEN (1<<2)
|
||||
#define JOB_CAPTAIN (1<<0)
|
||||
#define JOB_HOS (1<<1)
|
||||
#define JOB_WARDEN (1<<2)
|
||||
#define JOB_DETECTIVE (1<<3)
|
||||
#define JOB_OFFICER (1<<4)
|
||||
#define JOB_OFFICER (1<<4)
|
||||
#define JOB_CHIEF (1<<5)
|
||||
#define JOB_ENGINEER (1<<6)
|
||||
#define JOB_ATMOSTECH (1<<7)
|
||||
#define JOB_AI (1<<8)
|
||||
#define JOB_CYBORG (1<<9)
|
||||
#define JOB_CENTCOM (1<<10)
|
||||
#define JOB_AI (1<<8)
|
||||
#define JOB_CYBORG (1<<9)
|
||||
#define JOB_CENTCOM (1<<10)
|
||||
#define JOB_SYNDICATE (1<<11)
|
||||
#define JOB_JUDGE (1<<12)
|
||||
|
||||
#define JOBCAT_MEDSCI (1<<1)
|
||||
|
||||
#define JOB_RD (1<<0)
|
||||
#define JOB_RD (1<<0)
|
||||
#define JOB_SCIENTIST (1<<1)
|
||||
#define JOB_CHEMIST (1<<2)
|
||||
#define JOB_CMO (1<<3)
|
||||
#define JOB_DOCTOR (1<<4)
|
||||
#define JOB_GENETICIST (1<<5)
|
||||
#define JOB_VIROLOGIST (1<<6)
|
||||
#define JOB_CHEMIST (1<<2)
|
||||
#define JOB_CMO (1<<3)
|
||||
#define JOB_DOCTOR (1<<4)
|
||||
#define JOB_GENETICIST (1<<5)
|
||||
#define JOB_VIROLOGIST (1<<6)
|
||||
#define JOB_PSYCHIATRIST (1<<7)
|
||||
#define JOB_ROBOTICIST (1<<8)
|
||||
#define JOB_ROBOTICIST (1<<8)
|
||||
#define JOB_PARAMEDIC (1<<9)
|
||||
#define JOB_CORONER (1<<10)
|
||||
#define JOB_CORONER (1<<10)
|
||||
|
||||
|
||||
#define JOBCAT_SUPPORT (1<<2)
|
||||
|
||||
#define JOB_HOP (1<<0)
|
||||
#define JOB_HOP (1<<0)
|
||||
#define JOB_BARTENDER (1<<1)
|
||||
#define JOB_BOTANIST (1<<2)
|
||||
#define JOB_CHEF (1<<3)
|
||||
#define JOB_JANITOR (1<<4)
|
||||
#define JOB_JANITOR (1<<4)
|
||||
#define JOB_LIBRARIAN (1<<5)
|
||||
#define JOB_QUARTERMASTER (1<<6)
|
||||
#define JOB_CARGOTECH (1<<7)
|
||||
#define JOB_MINER (1<<8)
|
||||
#define JOB_LAWYER (1<<9)
|
||||
#define JOB_LAWYER (1<<9)
|
||||
#define JOB_CHAPLAIN (1<<10)
|
||||
#define JOB_CLOWN (1<<11)
|
||||
#define JOB_MIME (1<<12)
|
||||
#define JOB_CIVILIAN (1<<13)
|
||||
#define JOB_EXPLORER (1<<14)
|
||||
|
||||
#define JOBCAT_KARMA (1<<3)
|
||||
#define JOBCAT_KARMA (1<<3)
|
||||
|
||||
#define JOB_NANO (1<<0)
|
||||
#define JOB_BLUESHIELD (1<<1)
|
||||
#define JOB_BARBER (1<<3)
|
||||
#define JOB_BLUESHIELD (1<<1)
|
||||
#define JOB_BARBER (1<<3)
|
||||
// #define JOB_MECHANIC (1<<4) // AA07 2021-10-02 - Removed: Kept for history sake
|
||||
#define JOB_BRIGDOC (1<<5)
|
||||
#define JOB_JUDGE (1<<6)
|
||||
// #define JOB_PILOT (1<<7) // AA07 2021-10-02 - Removed: Kept for history sake
|
||||
#define JOB_BRIGDOC (1<<5)
|
||||
// #define JOB_JUDGE (1<<6) // AA07 2021-10-09 - Moved to ENGSEC (Non karma): Define kept for history sake
|
||||
// #define JOB_PILOT (1<<7) // AA07 2021-10-02 - Removed: Kept for history sake
|
||||
|
||||
@@ -365,7 +365,7 @@
|
||||
#define INVESTIGATE_BOMB "bombs"
|
||||
|
||||
// The SQL version required by this version of the code
|
||||
#define SQL_VERSION 26
|
||||
#define SQL_VERSION 28
|
||||
|
||||
// Vending machine stuff
|
||||
#define CAT_NORMAL 1
|
||||
@@ -496,3 +496,6 @@
|
||||
|
||||
// Runechat symbol types
|
||||
#define RUNECHAT_SYMBOL_EMOTE 1
|
||||
|
||||
/// Waits at a line of code until X is true
|
||||
#define UNTIL(X) while(!(X)) sleep(world.tick_lag)
|
||||
|
||||
+102
-41
@@ -1,80 +1,130 @@
|
||||
// rust_g.dm - DM API for rust_g extension library
|
||||
//
|
||||
// To configure, create a `rust_g.config.dm` and set what you care about from
|
||||
// the following options:
|
||||
//
|
||||
// #define RUST_G "path/to/rust_g"
|
||||
// Override the .dll/.so detection logic with a fixed path or with detection
|
||||
// logic of your own.
|
||||
//
|
||||
// #define RUSTG_OVERRIDE_BUILTINS
|
||||
// Enable replacement rust-g functions for certain builtins. Off by default.
|
||||
|
||||
#ifndef RUST_G
|
||||
/// Locator for the RUSTG DLL or SO depending on system type. Override if needed.
|
||||
#define RUST_G (world.system_type == UNIX ? "./librust_g.so" : "./rust_g.dll")
|
||||
// Default automatic RUST_G detection.
|
||||
// On Windows, looks in the standard places for `rust_g.dll`.
|
||||
// On Linux, looks in `.`, `$LD_LIBRARY_PATH`, and `~/.byond/bin` for either of
|
||||
// `librust_g.so` (preferred) or `rust_g` (old).
|
||||
|
||||
/* This comment bypasses grep checks */ /var/__rust_g
|
||||
|
||||
/proc/__detect_rust_g()
|
||||
if (world.system_type == UNIX)
|
||||
if (fexists("./librust_g.so"))
|
||||
// No need for LD_LIBRARY_PATH badness.
|
||||
return __rust_g = "./librust_g.so"
|
||||
else if (fexists("./rust_g"))
|
||||
// Old dumb filename.
|
||||
return __rust_g = "./rust_g"
|
||||
else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/rust_g"))
|
||||
// Old dumb filename in `~/.byond/bin`.
|
||||
return __rust_g = "rust_g"
|
||||
else
|
||||
// It's not in the current directory, so try others
|
||||
return __rust_g = "librust_g.so"
|
||||
else
|
||||
return __rust_g = "rust_g.dll"
|
||||
|
||||
#define RUST_G (__rust_g || __detect_rust_g())
|
||||
#endif
|
||||
|
||||
// Gets the version of RUSTG
|
||||
/// Gets the version of rust_g
|
||||
/proc/rustg_get_version() return call(RUST_G, "get_version")()
|
||||
|
||||
// Defines for internal job subsystem //
|
||||
#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
|
||||
#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
|
||||
#define RUSTG_JOB_ERROR "JOB PANICKED"
|
||||
// Cellular Noise Operations //
|
||||
|
||||
// DMI related operations //
|
||||
/**
|
||||
* This proc generates a cellular automata noise grid which can be used in procedural generation methods.
|
||||
*
|
||||
* Returns a single string that goes row by row, with values of 1 representing an alive cell, and a value of 0 representing a dead cell.
|
||||
*
|
||||
* Arguments:
|
||||
* * percentage: The chance of a turf starting closed
|
||||
* * smoothing_iterations: The amount of iterations the cellular automata simulates before returning the results
|
||||
* * birth_limit: If the number of neighboring cells is higher than this amount, a cell is born
|
||||
* * death_limit: If the number of neighboring cells is lower than this amount, a cell dies
|
||||
* * width: The width of the grid.
|
||||
* * height: The height of the grid.
|
||||
*/
|
||||
#define rustg_cnoise_generate(percentage, smoothing_iterations, birth_limit, death_limit, width, height) \
|
||||
call(RUST_G, "cnoise_generate")(percentage, smoothing_iterations, birth_limit, death_limit, width, height)
|
||||
|
||||
// DMI Operations //
|
||||
#define rustg_dmi_strip_metadata(fname) call(RUST_G, "dmi_strip_metadata")(fname)
|
||||
#define rustg_dmi_create_png(path, width, height, data) call(RUST_G, "dmi_create_png")(path, width, height, data)
|
||||
#define rustg_dmi_resize_png(path, width, height, resizetype) call(RUST_G, "dmi_resize_png")(path, width, height, resizetype)
|
||||
|
||||
// Noise related operations //
|
||||
#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y)
|
||||
|
||||
// File related operations //
|
||||
// File Operations //
|
||||
#define rustg_file_read(fname) call(RUST_G, "file_read")(fname)
|
||||
#define rustg_file_exists(fname) call(RUST_G, "file_exists")(fname)
|
||||
#define rustg_file_write(text, fname) call(RUST_G, "file_write")(text, fname)
|
||||
#define rustg_file_append(text, fname) call(RUST_G, "file_append")(text, fname)
|
||||
|
||||
#ifdef RUSTG_OVERRIDE_BUILTINS
|
||||
#define file2text(fname) rustg_file_read(fname)
|
||||
#define text2file(text, fname) rustg_file_append(text, fname)
|
||||
#define file2text(fname) rustg_file_read("[fname]")
|
||||
#define text2file(text, fname) rustg_file_append(text, "[fname]")
|
||||
#endif
|
||||
|
||||
// Git related operations //
|
||||
// Git Operations //
|
||||
#define rustg_git_revparse(rev) call(RUST_G, "rg_git_revparse")(rev)
|
||||
#define rustg_git_commit_date(rev) call(RUST_G, "rg_git_commit_date")(rev)
|
||||
|
||||
// Hash related operations //
|
||||
// Hashing Operations //
|
||||
#define rustg_hash_string(algorithm, text) call(RUST_G, "hash_string")(algorithm, text)
|
||||
#define rustg_hash_file(algorithm, fname) call(RUST_G, "hash_file")(algorithm, fname)
|
||||
#define rustg_hash_generate_totp(seed) call(RUST_G, "generate_totp")(seed)
|
||||
#define rustg_hash_generate_totp_tolerance(seed, tolerance) call(RUST_G, "generate_totp_tolerance")(seed, tolerance)
|
||||
|
||||
#define RUSTG_HASH_MD5 "md5"
|
||||
#define RUSTG_HASH_SHA1 "sha1"
|
||||
#define RUSTG_HASH_SHA256 "sha256"
|
||||
#define RUSTG_HASH_SHA512 "sha512"
|
||||
#define RUSTG_HASH_XXH64 "xxh64"
|
||||
#define RUSTG_HASH_BASE64 "base64"
|
||||
|
||||
#ifdef RUSTG_OVERRIDE_BUILTINS
|
||||
#define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing))
|
||||
#define md5(thing) (isfile(thing) ? rustg_hash_file(RUSTG_HASH_MD5, "[thing]") : rustg_hash_string(RUSTG_HASH_MD5, thing))
|
||||
#endif
|
||||
|
||||
// Logging stuff //
|
||||
#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text)
|
||||
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
|
||||
|
||||
// URL encoding stuff
|
||||
#define rustg_url_encode(text) call(RUST_G, "url_encode")(text)
|
||||
#define rustg_url_decode(text) call(RUST_G, "url_decode")(text)
|
||||
|
||||
#ifdef RUSTG_OVERRIDE_BUILTINS
|
||||
#define url_encode(text) rustg_url_encode(text)
|
||||
#define url_decode(text) rustg_url_decode(text)
|
||||
#endif
|
||||
|
||||
// HTTP library stuff //
|
||||
// HTTP Operations //
|
||||
#define RUSTG_HTTP_METHOD_GET "get"
|
||||
#define RUSTG_HTTP_METHOD_PUT "put"
|
||||
#define RUSTG_HTTP_METHOD_DELETE "delete"
|
||||
#define RUSTG_HTTP_METHOD_PATCH "patch"
|
||||
#define RUSTG_HTTP_METHOD_HEAD "head"
|
||||
#define RUSTG_HTTP_METHOD_POST "post"
|
||||
|
||||
// Commented out because this thing locks up the entire DD process when you use it
|
||||
// DO NOT USE FOR THE LOVE OF GOD
|
||||
// #define rustg_http_request_blocking(method, url, body, headers) call(RUST_G, "http_request_blocking")(method, url, body, headers)
|
||||
#define rustg_http_request_async(method, url, body, headers) call(RUST_G, "http_request_async")(method, url, body, headers)
|
||||
#define rustg_http_request_blocking(method, url, body, headers, options) call(RUST_G, "http_request_blocking")(method, url, body, headers, options)
|
||||
#define rustg_http_request_async(method, url, body, headers, options) call(RUST_G, "http_request_async")(method, url, body, headers, options)
|
||||
#define rustg_http_check_request(req_id) call(RUST_G, "http_check_request")(req_id)
|
||||
/proc/rustg_create_async_http_client() return call(RUST_G, "start_http_client")()
|
||||
/proc/rustg_close_async_http_client() return call(RUST_G, "shutdown_http_client")()
|
||||
|
||||
// SQL stuff //
|
||||
// Jobs Subsystem Operations //
|
||||
#define RUSTG_JOB_NO_RESULTS_YET "NO RESULTS YET"
|
||||
#define RUSTG_JOB_NO_SUCH_JOB "NO SUCH JOB"
|
||||
#define RUSTG_JOB_ERROR "JOB PANICKED"
|
||||
|
||||
// JSON Operations //
|
||||
#define rustg_json_is_valid(text) (call(RUST_G, "json_is_valid")(text) == "true")
|
||||
|
||||
// Logging Operations //
|
||||
#define rustg_log_write(fname, text) call(RUST_G, "log_write")(fname, text)
|
||||
/proc/rustg_log_close_all() return call(RUST_G, "log_close_all")()
|
||||
|
||||
// Noise Operations //
|
||||
#define rustg_noise_get_at_coordinates(seed, x, y) call(RUST_G, "noise_get_at_coordinates")(seed, x, y)
|
||||
|
||||
// SQL Opeartions //
|
||||
#define rustg_sql_connect_pool(options) call(RUST_G, "sql_connect_pool")(options)
|
||||
#define rustg_sql_query_async(handle, query, params) call(RUST_G, "sql_query_async")(handle, query, params)
|
||||
#define rustg_sql_query_blocking(handle, query, params) call(RUST_G, "sql_query_blocking")(handle, query, params)
|
||||
@@ -82,8 +132,19 @@
|
||||
#define rustg_sql_disconnect_pool(handle) call(RUST_G, "sql_disconnect_pool")(handle)
|
||||
#define rustg_sql_check_query(job_id) call(RUST_G, "sql_check_query")("[job_id]")
|
||||
|
||||
// toml2json stuff //
|
||||
#define rustg_toml2json(tomlfile) call(RUST_G, "toml2json")(tomlfile)
|
||||
// TOML Operations //
|
||||
#define rustg_read_toml_file(path) json_decode(call(RUST_G, "toml_file_to_json")(path) || "null")
|
||||
|
||||
// Unzip Operations //
|
||||
#define rustg_unzip_download_async(url, unzip_directory) call(RUST_G, "unzip_download_async")(url, unzip_directory)
|
||||
#define rustg_unzip_check(job_id) call(RUST_G, "unzip_check")("[job_id]")
|
||||
|
||||
// URL Encoder/Decoder Operations //
|
||||
#define rustg_url_encode(text) call(RUST_G, "url_encode")("[text]")
|
||||
#define rustg_url_decode(text) call(RUST_G, "url_decode")(text)
|
||||
|
||||
#ifdef RUSTG_OVERRIDE_BUILTINS
|
||||
#define url_encode(text) rustg_url_encode(text)
|
||||
#define url_decode(text) rustg_url_decode(text)
|
||||
#endif
|
||||
|
||||
// RUSTG Version //
|
||||
#define RUST_G_VERSION "0.4.5-P3"
|
||||
|
||||
@@ -34,8 +34,14 @@
|
||||
|
||||
#define STATUS_EFFECT_BLOODDRUNK /datum/status_effect/blooddrunk //Stun immunity and greatly reduced damage taken
|
||||
|
||||
|
||||
#define STATUS_EFFECT_SPEEDLEGS /datum/status_effect/speedlegs //Handles cling speed boost and chemical cost.
|
||||
|
||||
#define STATUS_EFFECT_BLOOD_SWELL /datum/status_effect/bloodswell //stun resistance and halved damage for gargantua vampires
|
||||
|
||||
#define STATUS_EFFECT_BLOOD_RUSH /datum/status_effect/blood_rush // speed boost for gargantua vampires
|
||||
|
||||
|
||||
/////////////
|
||||
// DEBUFFS //
|
||||
/////////////
|
||||
@@ -80,6 +86,8 @@
|
||||
|
||||
#define STATUS_EFFECT_HIGHFIVE /datum/status_effect/high_five
|
||||
|
||||
#define STATUS_EFFECT_CHARGING /datum/status_effect/charging
|
||||
|
||||
//#define STATUS_EFFECT_SIGILMARK /datum/status_effect/sigil_mark
|
||||
|
||||
#define STATUS_EFFECT_CRUSHERDAMAGETRACKING /datum/status_effect/crusher_damage //tracks total kinetic crusher damage on a target
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#define SUBCLASS_HEMOMANCER /datum/vampire_subclass/hemomancer
|
||||
#define SUBCLASS_GARGANTUA /datum/vampire_subclass/gargantua
|
||||
#define SUBCLASS_UMBRAE /datum/vampire_subclass/umbrae
|
||||
#define SUBCLASS_ANCIENT /datum/vampire_subclass/ancient
|
||||
|
||||
#define BLOOD_DRAIN_LIMIT 200 // the amount of blood a vampire can drain from a person.
|
||||
#define FULLPOWER_DRAINED_REQUIREMENT 8 // the number of people you need to suck to become full powered.
|
||||
#define FULLPOWER_BLOODTOTAL_REQUIREMENT 1000 // the amount of blood you need to suck to get full power.
|
||||
|
||||
#define VAMPIRE_NULLIFICATION_CAP 120 // the maximum amount a vampire can be nullified naturally.
|
||||
#define VAMPIRE_COMPLETE_NULLIFICATION 100 // the point of nullification where vampires can no longer use abilities.
|
||||
@@ -0,0 +1,40 @@
|
||||
// This file contains procs for interacting with the internal API
|
||||
|
||||
/**
|
||||
* Internal API Caller
|
||||
*
|
||||
* Makes calls to the internal Paradise API and returns a [/datum/http_response].
|
||||
*
|
||||
* Arguments:
|
||||
* * method - The relevant HTTP method to use
|
||||
* * path - The path of the API call. DO NOT USE A LEADING SLASH
|
||||
* * body - The request body, if applicable
|
||||
*/
|
||||
/proc/MakeAPICall(method, path, body)
|
||||
if(!method || !path)
|
||||
// Needs valid params
|
||||
return null
|
||||
if(!GLOB.configuration.system.api_host || !GLOB.configuration.system.api_key)
|
||||
// Needs these set in config
|
||||
return null
|
||||
|
||||
if(IsAdminAdvancedProcCall())
|
||||
// Admins shouldnt fuck with this
|
||||
to_chat(usr, "<span class='boldannounce'>API interaction blocked: Advanced ProcCall detected.</span>")
|
||||
message_admins("[key_name(usr)] attempted to interact with the internal API via advanced proc-call")
|
||||
log_admin("[key_name(usr)] attempted to interact with the internal API via advanced proc-call")
|
||||
return
|
||||
|
||||
var/datum/http_request/req = new()
|
||||
var/target_url = "[GLOB.configuration.system.api_host]/[path]"
|
||||
// You may be asking, "Hey AA, why is the above a var instead of just using it directly?"
|
||||
// Ill tell you why. This lets you breakpoint it in the debugger to see if the URL is
|
||||
// what you wanted or not, given how slashes and stuff can break it.
|
||||
req.prepare(method, target_url, body, list("AuthKey" = GLOB.configuration.system.api_key))
|
||||
req.begin_async()
|
||||
// Check if we are complete
|
||||
UNTIL(req.is_complete())
|
||||
var/datum/http_response/res = req.into_response()
|
||||
|
||||
return res
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/head_accessory, GLOB.head_accessory_styles_list)
|
||||
//hair
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair, GLOB.hair_styles_public_list, GLOB.hair_styles_male_list, GLOB.hair_styles_female_list, GLOB.hair_styles_full_list)
|
||||
//hair gradients
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/hair_gradient, GLOB.hair_gradients_list)
|
||||
//facial hair
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/facial_hair, GLOB.facial_hair_styles_list, GLOB.facial_hair_styles_male_list, GLOB.facial_hair_styles_female_list)
|
||||
//underwear
|
||||
|
||||
@@ -179,10 +179,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define TRAIT_NODECAY "no_decay"
|
||||
#define TRAIT_NOEXAMINE "no_examine"
|
||||
#define TRAIT_NOPAIN "no_pain"
|
||||
#define TRAIT_FORCE_DOORS "force_doors"
|
||||
|
||||
//***** ITEM TRAITS *****//
|
||||
/// Show what machine/door wires do when held.
|
||||
#define TRAIT_SHOW_WIRE_INFO "show_wire_info"
|
||||
#define TRAIT_BUTCHERS_HUMANS "butchers_humans"
|
||||
|
||||
//
|
||||
// common trait sources
|
||||
@@ -197,6 +199,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
#define CLOTHING_TRAIT "clothing"
|
||||
#define CULT_TRAIT "cult"
|
||||
#define INNATE_TRAIT "innate"
|
||||
#define VAMPIRE_TRAIT "vampire"
|
||||
|
||||
// unique trait sources
|
||||
#define STATUE_MUTE "statue"
|
||||
|
||||
@@ -2047,9 +2047,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
)
|
||||
return _list
|
||||
|
||||
/// Waits at a line of code until X is true
|
||||
#define UNTIL(X) while(!(X)) sleep(world.tick_lag)
|
||||
|
||||
// Check if the source atom contains another atom
|
||||
/atom/proc/contains(atom/location)
|
||||
if(!location)
|
||||
@@ -2061,11 +2058,12 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
|
||||
|
||||
/proc/log_connection(ckey, ip, cid, connection_type)
|
||||
ASSERT(connection_type in list(CONNECTION_TYPE_ESTABLISHED, CONNECTION_TYPE_DROPPED_IPINTEL, CONNECTION_TYPE_DROPPED_BANNED, CONNECTION_TYPE_DROPPED_INVALID))
|
||||
var/datum/db_query/query_accesslog = SSdbcore.NewQuery("INSERT INTO connection_log (`datetime`, `ckey`, `ip`, `computerid`, `result`) VALUES(Now(), :ckey, :ip, :cid, :result)", list(
|
||||
var/datum/db_query/query_accesslog = SSdbcore.NewQuery("INSERT INTO connection_log (`datetime`, `ckey`, `ip`, `computerid`, `result`, `server_id`) VALUES(Now(), :ckey, :ip, :cid, :result, :server_id)", list(
|
||||
"ckey" = ckey,
|
||||
"ip" = "[ip ? ip : ""]", // This is important. NULL is not the same as "", and if you directly open the `.dmb` file, you get a NULL IP.
|
||||
"cid" = cid,
|
||||
"result" = connection_type
|
||||
"result" = connection_type,
|
||||
"server_id" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
query_accesslog.warn_execute()
|
||||
qdel(query_accesslog)
|
||||
|
||||
@@ -11,7 +11,7 @@ GLOBAL_LIST_INIT(hair_styles_full_list, list()) //fluff hair styles
|
||||
GLOBAL_LIST_INIT(facial_hair_styles_list, list()) //stores /datum/sprite_accessory/facial_hair indexed by name
|
||||
GLOBAL_LIST_INIT(facial_hair_styles_male_list, list())
|
||||
GLOBAL_LIST_INIT(facial_hair_styles_female_list, list())
|
||||
GLOBAL_LIST_INIT(skin_styles_female_list, list()) //unused
|
||||
GLOBAL_LIST_EMPTY(hair_gradients_list) //stores /datum/sprite_accessory/hair_gradient indexed by name
|
||||
//Underwear
|
||||
GLOBAL_LIST_INIT(underwear_list, list()) //stores /datum/sprite_accessory/underwear indexed by name
|
||||
GLOBAL_LIST_INIT(underwear_m, list()) //stores only underwear name
|
||||
|
||||
@@ -60,10 +60,12 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_NOGERMS" = TRAIT_NOGERMS,
|
||||
"TRAIT_NODECAY" = TRAIT_NODECAY,
|
||||
"TRAIT_NOEXAMINE" = TRAIT_NOEXAMINE,
|
||||
"TRAIT_NOPAIN" = TRAIT_NOPAIN
|
||||
"TRAIT_NOPAIN" = TRAIT_NOPAIN,
|
||||
"TRAIT_FORCE_DOORS" = TRAIT_FORCE_DOORS,
|
||||
),
|
||||
/obj/item = list(
|
||||
"TRAIT_SHOW_WIRE_INFO" = TRAIT_SHOW_WIRE_INFO
|
||||
"TRAIT_SHOW_WIRE_INFO" = TRAIT_SHOW_WIRE_INFO,
|
||||
"TRAIT_BUTCHER_HUMANS" = TRAIT_BUTCHERS_HUMANS
|
||||
)
|
||||
))
|
||||
|
||||
|
||||
@@ -622,6 +622,13 @@ so as to remain in compliance with the most up-to-date laws."
|
||||
stone = null
|
||||
return ..()
|
||||
|
||||
/obj/screen/alert/notify_mapvote
|
||||
name = "Map Vote"
|
||||
desc = "Vote on which map you would like to play on next!"
|
||||
icon_state = "map_vote"
|
||||
|
||||
/obj/screen/alert/notify_mapvote/Click()
|
||||
SSvote.browse_to(usr.client)
|
||||
|
||||
//OBJECT-BASED
|
||||
|
||||
|
||||
@@ -192,17 +192,12 @@
|
||||
if(L.view_sized != C.view)
|
||||
L.update_o(C.view)
|
||||
|
||||
var/change_x
|
||||
var/change_y
|
||||
|
||||
if(L.absolute)
|
||||
L.offset_x = -(posobj.x - SSparallax.planet_x_offset) * L.speed
|
||||
L.offset_y = -(posobj.y - SSparallax.planet_y_offset) * L.speed
|
||||
else
|
||||
change_x = offset_x * L.speed
|
||||
L.offset_x -= change_x
|
||||
change_y = offset_y * L.speed
|
||||
L.offset_y -= change_y
|
||||
L.offset_x -= offset_x * L.speed
|
||||
L.offset_y -= offset_y * L.speed
|
||||
|
||||
if(L.offset_x > 240)
|
||||
L.offset_x -= 480
|
||||
@@ -213,10 +208,6 @@
|
||||
if(L.offset_y < -240)
|
||||
L.offset_y += 480
|
||||
|
||||
if(!(areaobj.parallax_movedir && areaobj.moving) && C.dont_animate_parallax <= world.time && (offset_x || offset_y) && abs(offset_x) <= max(C.parallax_throttle/world.tick_lag+1,1) && abs(offset_y) <= max(C.parallax_throttle/world.tick_lag+1,1) && (round(abs(change_x)) > 1 || round(abs(change_y)) > 1))
|
||||
L.transform = matrix(1, 0, offset_x*L.speed, 0, 1, offset_y*L.speed)
|
||||
animate(L, transform=matrix(), time = last_delay)
|
||||
|
||||
L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]"
|
||||
|
||||
/atom/movable/proc/update_parallax_contents()
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
|
||||
else
|
||||
SEND_SIGNAL(M, COMSIG_ITEM_ATTACK)
|
||||
add_attack_logs(user, M, "Attacked with [name] ([uppertext(user.a_intent)]) ([uppertext(damtype)])", (M.ckey && force > 0 && damtype != STAMINA) ? null : ATKLOG_ALMOSTALL)
|
||||
if(hitsound)
|
||||
playsound(loc, hitsound, get_clamped_volume(), TRUE, extrarange = stealthy_audio ? SILENCED_SOUND_EXTRARANGE : -1, falloff_distance = 0)
|
||||
|
||||
@@ -81,8 +82,6 @@
|
||||
user.do_attack_animation(M)
|
||||
. = M.attacked_by(src, user, def_zone)
|
||||
|
||||
add_attack_logs(user, M, "Attacked with [name] ([uppertext(user.a_intent)]) ([uppertext(damtype)])", (M.ckey && force > 0 && damtype != STAMINA) ? null : ATKLOG_ALMOSTALL)
|
||||
|
||||
add_fingerprint(user)
|
||||
|
||||
|
||||
@@ -100,14 +99,22 @@
|
||||
return
|
||||
|
||||
/obj/attacked_by(obj/item/I, mob/living/user)
|
||||
var/damage = I.force
|
||||
if(I.force)
|
||||
user.visible_message("<span class='danger'>[user] has hit [src] with [I]!</span>", "<span class='danger'>You hit [src] with [I]!</span>")
|
||||
take_damage(I.force, I.damtype, MELEE, 1)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
damage += H.physiology.melee_bonus
|
||||
take_damage(damage, I.damtype, MELEE, 1)
|
||||
|
||||
/mob/living/attacked_by(obj/item/I, mob/living/user, def_zone)
|
||||
send_item_attack_message(I, user)
|
||||
if(I.force)
|
||||
apply_damage(I.force, I.damtype, def_zone)
|
||||
var/bonus_damage = 0
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
bonus_damage = H.physiology.melee_bonus
|
||||
apply_damage(I.force + bonus_damage, I.damtype, def_zone)
|
||||
if(I.damtype == BRUTE)
|
||||
if(prob(33))
|
||||
I.add_mob_blood(src)
|
||||
|
||||
@@ -46,6 +46,8 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new())
|
||||
var/datum/configuration_section/url_configuration/url
|
||||
/// Holder for the voting configuration datum
|
||||
var/datum/configuration_section/vote_configuration/vote
|
||||
/// Raw data. Stored here to avoid passing data between procs constantly
|
||||
var/list/raw_data = list()
|
||||
|
||||
|
||||
/datum/server_configuration/Destroy(force)
|
||||
@@ -53,6 +55,16 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new())
|
||||
// This is going to stay existing. I dont care.
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
/datum/server_configuration/vv_get_var(var_name)
|
||||
if(var_name == "raw_data") // NO!
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/datum/server_configuration/vv_edit_var(var_name, var_value)
|
||||
if(var_name == "raw_data") // NO!
|
||||
return FALSE
|
||||
. = ..()
|
||||
|
||||
/datum/server_configuration/CanProcCall(procname)
|
||||
return FALSE // No thanks
|
||||
|
||||
@@ -85,34 +97,66 @@ GLOBAL_DATUM_INIT(configuration, /datum/server_configuration, new())
|
||||
var/config_file = "config/config.toml"
|
||||
if(!fexists(config_file))
|
||||
config_file = "config/example/config.toml" // Fallback to example if user hasnt setup config properly
|
||||
var/raw_json = rustg_toml2json(config_file)
|
||||
var/list/raw_config_data = json_decode(raw_json)
|
||||
raw_data = rustg_read_toml_file(config_file)
|
||||
|
||||
// Now pass through all our stuff
|
||||
admin.load_data(raw_config_data["admin_configuration"])
|
||||
afk.load_data(raw_config_data["afk_configuration"])
|
||||
custom_sprites.load_data(raw_config_data["custom_sprites_configuration"])
|
||||
database.load_data(raw_config_data["database_configuration"])
|
||||
discord.load_data(raw_config_data["discord_configuration"])
|
||||
event.load_data(raw_config_data["event_configuration"])
|
||||
gamemode.load_data(raw_config_data["gamemode_configuration"])
|
||||
gateway.load_data(raw_config_data["gateway_configuration"])
|
||||
general.load_data(raw_config_data["general_configuration"])
|
||||
ipintel.load_data(raw_config_data["ipintel_configuration"])
|
||||
jobs.load_data(raw_config_data["job_configuration"])
|
||||
logging.load_data(raw_config_data["logging_configuration"])
|
||||
mc.load_data(raw_config_data["mc_configuration"])
|
||||
metrics.load_data(raw_config_data["metrics_configuration"])
|
||||
movement.load_data(raw_config_data["movement_configuration"])
|
||||
overflow.load_data(raw_config_data["overflow_configuration"])
|
||||
ruins.load_data(raw_config_data["ruin_configuration"])
|
||||
system.load_data(raw_config_data["system_configuration"])
|
||||
url.load_data(raw_config_data["url_configuration"])
|
||||
vote.load_data(raw_config_data["voting_configuration"])
|
||||
load_all_sections()
|
||||
|
||||
// Clear our list to save RAM
|
||||
raw_data = list()
|
||||
|
||||
// And report the load
|
||||
DIRECT_OUTPUT(world.log, "Config loaded in [stop_watch(start)]s")
|
||||
|
||||
/datum/server_configuration/proc/load_all_sections()
|
||||
safe_load(admin, "admin_configuration")
|
||||
safe_load(afk, "afk_configuration")
|
||||
safe_load(custom_sprites, "custom_sprites_configuration")
|
||||
safe_load(database, "database_configuration")
|
||||
safe_load(discord, "discord_configuration")
|
||||
safe_load(event, "event_configuration")
|
||||
safe_load(gamemode, "gamemode_configuration")
|
||||
safe_load(gateway, "gateway_configuration")
|
||||
safe_load(general, "general_configuration")
|
||||
safe_load(ipintel, "ipintel_configuration")
|
||||
safe_load(jobs, "job_configuration")
|
||||
safe_load(logging, "logging_configuration")
|
||||
safe_load(mc, "mc_configuration")
|
||||
safe_load(metrics, "metrics_configuration")
|
||||
safe_load(movement, "movement_configuration")
|
||||
safe_load(overflow, "overflow_configuration")
|
||||
safe_load(ruins, "ruin_configuration")
|
||||
safe_load(system, "system_configuration")
|
||||
safe_load(url, "url_configuration")
|
||||
safe_load(vote, "voting_configuration")
|
||||
|
||||
// Proc to load up instance-specific overrides
|
||||
/datum/server_configuration/proc/load_overrides()
|
||||
var/override_file = "config/overrides_[world.port].toml"
|
||||
if(!fexists(override_file))
|
||||
DIRECT_OUTPUT(world.log, "Overrides not found for this instance.")
|
||||
return
|
||||
|
||||
DIRECT_OUTPUT(world.log, "Overrides found for this instance. Loading them.")
|
||||
var/start = start_watch() // Time tracking
|
||||
|
||||
raw_data = rustg_read_toml_file(override_file)
|
||||
|
||||
// Now safely load our overrides.
|
||||
// Due to the nature of config wrappers, only vars that exist in the config file are applied to the config datums.
|
||||
// This means that an override missing a key doesnt null it out from the main server
|
||||
load_all_sections()
|
||||
|
||||
// Clear our list to save RAM
|
||||
raw_data = list()
|
||||
|
||||
// And report the load
|
||||
DIRECT_OUTPUT(world.log, "Config overrides loaded in [stop_watch(start)]s")
|
||||
|
||||
// Only loads the data for a config section if that key exists in the JSON
|
||||
/datum/server_configuration/proc/safe_load(datum/configuration_section/CS, section)
|
||||
if(!isnull(raw_data[section]))
|
||||
CS.load_data(raw_data[section])
|
||||
|
||||
/datum/configuration_section
|
||||
/// See __config_defines.dm
|
||||
|
||||
@@ -14,10 +14,16 @@
|
||||
var/is_production = FALSE
|
||||
/// If above is true, you can run a shell command
|
||||
var/shutdown_shell_command = null
|
||||
/// 2FA backend server host
|
||||
var/_2fa_auth_host = null
|
||||
/// Internal API host
|
||||
var/api_host = null
|
||||
/// Internal API key
|
||||
var/api_key = null
|
||||
/// List of IP addresses which bypass world topic rate limiting
|
||||
var/list/topic_ip_ratelimit_bypass = list()
|
||||
/// Server instance ID
|
||||
var/instance_id = "paradise_main"
|
||||
/// Server internal IP
|
||||
var/internal_ip = "127.0.0.1"
|
||||
|
||||
/datum/configuration_section/system_configuration/load_data(list/data)
|
||||
// Use the load wrappers here. That way the default isnt made 'null' if you comment out the config line
|
||||
@@ -28,6 +34,10 @@
|
||||
CONFIG_LOAD_STR(medal_hub_address, data["medal_hub_address"])
|
||||
CONFIG_LOAD_STR(medal_hub_password, data["medal_hub_password"])
|
||||
CONFIG_LOAD_STR(shutdown_shell_command, data["shutdown_shell_command"])
|
||||
CONFIG_LOAD_STR(_2fa_auth_host, data["_2fa_auth_host"])
|
||||
CONFIG_LOAD_STR(api_host, data["api_host"])
|
||||
CONFIG_LOAD_STR(api_key, data["api_key"])
|
||||
|
||||
CONFIG_LOAD_LIST(topic_ip_ratelimit_bypass, data["topic_ip_ratelimit_bypass"])
|
||||
|
||||
CONFIG_LOAD_STR(instance_id, data["instance_id"])
|
||||
CONFIG_LOAD_STR(internal_ip, data["internal_ip"])
|
||||
|
||||
@@ -62,7 +62,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
|
||||
/// For scheduling different subsystems for different stages of the round
|
||||
var/current_runlevel
|
||||
/// Do we want to sleep until players log in?
|
||||
var/sleep_offline_after_initializations = TRUE
|
||||
var/sleep_offline_after_initializations = FALSE // No we dont
|
||||
|
||||
var/static/restart_clear = 0
|
||||
var/static/restart_timeout = 0
|
||||
|
||||
@@ -287,8 +287,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
lakey = L.lastattackerckey
|
||||
|
||||
var/datum/db_query/deathquery = SSdbcore.NewQuery({"
|
||||
INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord)
|
||||
VALUES (:name, :key, :job, :special, :pod, NOW(), :laname, :lakey, :gender, :bruteloss, :fireloss, :brainloss, :oxyloss, :coord)"},
|
||||
INSERT INTO death (name, byondkey, job, special, pod, tod, laname, lakey, gender, bruteloss, fireloss, brainloss, oxyloss, coord, server_id)
|
||||
VALUES (:name, :key, :job, :special, :pod, NOW(), :laname, :lakey, :gender, :bruteloss, :fireloss, :brainloss, :oxyloss, :coord, :server_id)"},
|
||||
list(
|
||||
"name" = L.real_name,
|
||||
"key" = L.key,
|
||||
@@ -302,7 +302,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
"fireloss" = L.getFireLoss(),
|
||||
"brainloss" = L.getBrainLoss(),
|
||||
"oxyloss" = L.getOxyLoss(),
|
||||
"coord" = "[L.x], [L.y], [L.z]"
|
||||
"coord" = "[L.x], [L.y], [L.z]",
|
||||
"server_id" = GLOB.configuration.system.instance_id
|
||||
)
|
||||
)
|
||||
deathquery.warn_execute()
|
||||
|
||||
@@ -160,8 +160,8 @@ SUBSYSTEM_DEF(dbcore)
|
||||
if(!IsConnected())
|
||||
return
|
||||
var/datum/db_query/query_round_initialize = SSdbcore.NewQuery(
|
||||
"INSERT INTO round (initialize_datetime, server_ip, server_port) VALUES (Now(), INET_ATON(:internet_address), :port)",
|
||||
list("internet_address" = world.internet_address || "0", "port" = "[world.port]")
|
||||
"INSERT INTO round (initialize_datetime, server_ip, server_port, server_id) VALUES (Now(), INET_ATON(:internet_address), :port, :server_id)",
|
||||
list("internet_address" = world.internet_address || "0", "port" = "[world.port]", "server_id" = GLOB.configuration.system.instance_id)
|
||||
)
|
||||
query_round_initialize.Execute(async = FALSE)
|
||||
GLOB.round_id = "[query_round_initialize.last_insert_id]"
|
||||
|
||||
@@ -27,7 +27,7 @@ SUBSYSTEM_DEF(discord)
|
||||
webhook_urls = GLOB.configuration.discord.mentor_webhook_urls
|
||||
|
||||
var/datum/discord_webhook_payload/dwp = new()
|
||||
dwp.webhook_content = content
|
||||
dwp.webhook_content = "**\[[GLOB.configuration.system.instance_id]]** [content]"
|
||||
for(var/url in webhook_urls)
|
||||
SShttp.create_async_request(RUSTG_HTTP_METHOD_POST, url, dwp.serialize2json(), list("content-type" = "application/json"))
|
||||
|
||||
@@ -73,7 +73,7 @@ SUBSYSTEM_DEF(discord)
|
||||
var/message = "[content] [alerttext] [add_ping ? handle_administrator_ping() : ""]"
|
||||
|
||||
var/datum/discord_webhook_payload/dwp = new()
|
||||
dwp.webhook_content = message
|
||||
dwp.webhook_content = "**\[[GLOB.configuration.system.instance_id]]** [message]"
|
||||
for(var/url in GLOB.configuration.discord.admin_webhook_urls)
|
||||
SShttp.create_async_request(RUSTG_HTTP_METHOD_POST, url, dwp.serialize2json(), list("content-type" = "application/json"))
|
||||
|
||||
@@ -94,7 +94,7 @@ SUBSYSTEM_DEF(discord)
|
||||
var/message = "[content] [alerttext][add_ping ? handle_mentor_ping() : ""]"
|
||||
|
||||
var/datum/discord_webhook_payload/dwp = new()
|
||||
dwp.webhook_content = message
|
||||
dwp.webhook_content = "**\[[GLOB.configuration.system.instance_id]]** [message]"
|
||||
for(var/url in GLOB.configuration.discord.mentor_webhook_urls)
|
||||
SShttp.create_async_request(RUSTG_HTTP_METHOD_POST, url, dwp.serialize2json(), list("content-type" = "application/json"))
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
SUBSYSTEM_DEF(instancing)
|
||||
name = "Instancing"
|
||||
runlevels = RUNLEVEL_INIT | RUNLEVEL_LOBBY | RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
wait = 30 SECONDS
|
||||
flags = SS_KEEP_TIMING
|
||||
|
||||
/datum/controller/subsystem/instancing/Initialize(start_timeofday)
|
||||
// Dont even bother if we arent connected
|
||||
if(!SSdbcore.IsConnected())
|
||||
flags |= SS_NO_FIRE
|
||||
return ..()
|
||||
update_heartbeat() // Make sure you do this before announcing to peers, or no one will hear your announcement
|
||||
var/startup_msg = "The server <code>[GLOB.configuration.general.server_name]</code> is now starting up. The map is [SSmapping.map_datum.fluff_name] ([SSmapping.map_datum.technical_name]). You can connect with the <code>Switch Server</code> verb."
|
||||
message_all_peers(startup_msg)
|
||||
return ..()
|
||||
|
||||
/datum/controller/subsystem/instancing/fire(resumed)
|
||||
update_heartbeat()
|
||||
update_playercache()
|
||||
|
||||
/**
|
||||
* Playercache updater
|
||||
*
|
||||
* Updates the player cache in the DB. Different from heartbeat so we can force invoke it on player operations
|
||||
*/
|
||||
/datum/controller/subsystem/instancing/proc/update_playercache(optional_ckey)
|
||||
// You may be wondering, why the fuck is an "optional ckey" variable here
|
||||
// Well, this is invoked in client/New(), and needs to read from GLOB.clients
|
||||
// However, this proc sleeps, and if you sleep during client/New() once the client is in GLOB.clients, stuff breaks bad
|
||||
// (See my comment rambling in client/New())
|
||||
// By passing the ckey through, we can sleep in this proc and still get the data
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
// First iterate clients to get ckeys
|
||||
var/list/ckeys = list()
|
||||
for(var/client/C in GLOB.clients) // No code review. I am not doing the `as anything` bullshit, because we *do* need the type checks here to avoid null clients which do happen sometimes
|
||||
ckeys += C.ckey
|
||||
// Add our optional
|
||||
if(optional_ckey)
|
||||
ckeys += optional_ckey
|
||||
// Note: We dont have to sort the list here. The only time this is read for is a search,
|
||||
// and order doesnt matter for that.
|
||||
var/ckey_json = json_encode(ckeys)
|
||||
|
||||
// Yes I care about performance savings this much here to mass execute this shit
|
||||
var/list/datum/db_query/queries = list()
|
||||
queries += SSdbcore.NewQuery("UPDATE instance_data_cache SET key_value=:json WHERE key_name='playerlist' AND server_id=:sid", list(
|
||||
"json" = ckey_json,
|
||||
"sid" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
queries += SSdbcore.NewQuery("UPDATE instance_data_cache SET key_value=:count WHERE key_name='playercount' AND server_id=:sid", list(
|
||||
"count" = length(ckeys),
|
||||
"sid" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
|
||||
SSdbcore.MassExecute(queries, TRUE, TRUE, FALSE, FALSE)
|
||||
|
||||
/**
|
||||
* Heartbeat updater
|
||||
*
|
||||
* Updates the heartbeat in the DB. Used so other servers can see when this one was alive
|
||||
*/
|
||||
/datum/controller/subsystem/instancing/proc/update_heartbeat()
|
||||
// this could probably just go in fire() but clean code and profiler ease who cares
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("UPDATE instance_data_cache SET key_value=NOW() WHERE key_name='heartbeat' AND server_id=:sid", list(
|
||||
"sid" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
dbq.warn_execute()
|
||||
qdel(dbq)
|
||||
|
||||
/**
|
||||
* Seed data
|
||||
*
|
||||
* Seeds all our data into the DB for other servers to discover from.
|
||||
* This is called during world/New() instead of on initialize so it can be done *instantly*
|
||||
*/
|
||||
/datum/controller/subsystem/instancing/proc/seed_data()
|
||||
// We need to seed a lot of keys, so lets just use a key-value-pair-map to do this easily
|
||||
var/list/kvp_map = list()
|
||||
kvp_map["server_name"] = GLOB.configuration.general.server_name // Name of the server
|
||||
kvp_map["server_port"] = world.port // Server port (used for redirection and topics)
|
||||
kvp_map["topic_key"] = GLOB.configuration.system.topic_key // Server topic key (used for topics)
|
||||
kvp_map["internal_ip"] = GLOB.configuration.system.internal_ip // Server internal IP (used for topics)
|
||||
kvp_map["playercount"] = length(GLOB.clients) // Server client count (used for status info)
|
||||
kvp_map["playerlist"] = json_encode(list()) // Server client list. Used for dupe login checks. This gets filled in later
|
||||
kvp_map["heartbeat"] = SQLtime() // SQL timestamp for heartbeat purposes. Any server without a heartbeat in the last 60 seconds can be considered dead
|
||||
// Also note for above. You may say "But AA you dont need to JSON encode it, just use "\[]"."
|
||||
// Well to that I say, no. This is meant to be JSON regardless, and it should represent that. This proc is ran once during world/New()
|
||||
// An extra nanosecond of load will make zero difference.
|
||||
|
||||
for(var/key in kvp_map)
|
||||
var/datum/db_query/dbq = SSdbcore.NewQuery("INSERT INTO instance_data_cache (server_id, key_name, key_value) VALUES (:sid, :kn, :kv) ON DUPLICATE KEY UPDATE key_value=:kv2", // Is this necessary? Who knows!
|
||||
list(
|
||||
"sid" = GLOB.configuration.system.instance_id,
|
||||
"kn" = key,
|
||||
"kv" = "[kvp_map[key]]", // String encoding IS necessary since these tables use strings, not ints
|
||||
"kv2" = "[kvp_map[key]]", // Dont know if I need the second but better to be safe
|
||||
)
|
||||
)
|
||||
dbq.warn_execute(FALSE) // Do NOT async execute here because world/New() shouldnt sleep. EVER. You get issues if you do.
|
||||
qdel(dbq)
|
||||
|
||||
|
||||
/**
|
||||
* Message all peers
|
||||
*
|
||||
* Wrapper for [topic_all_peers] to format the input into a message topic. Will send a server-wide announcement to the other servers
|
||||
*
|
||||
* Arguments:
|
||||
* * message - Message to send to the other servers
|
||||
*/
|
||||
/datum/controller/subsystem/instancing/proc/message_all_peers(message)
|
||||
if(!SSdbcore.IsConnected())
|
||||
return
|
||||
var/topic_string = "instance_announce&msg=[url_encode(message)]"
|
||||
topic_all_peers(topic_string)
|
||||
|
||||
/**
|
||||
* Sends a topic to all peers
|
||||
*
|
||||
* Sends a raw topic to the other servers. WILL APPEND &key=[commskey] ON THE END. PLEASE ACCOUNT FOR THIS.
|
||||
*
|
||||
* Arguments:
|
||||
* * raw_topic - The raw topic to send to the other servers
|
||||
*/
|
||||
/datum/controller/subsystem/instancing/proc/topic_all_peers(raw_topic)
|
||||
// Someone here is going to say "AA you shouldnt put load on the DB server you can do sorting in BYOND"
|
||||
// Well let me put it this way. The DB server is an entirely different machine to BYOND, with this entire dataset being stored in its RAM, not even on disk
|
||||
// By making the DB server do the work, we can offload from BYOND, which is already strained
|
||||
var/datum/db_query/dbq1 = SSdbcore.NewQuery({"
|
||||
SELECT server_id, key_name, key_value FROM instance_data_cache WHERE server_id IN
|
||||
(SELECT server_id FROM instance_data_cache WHERE server_id !=:sid AND
|
||||
key_name='heartbeat' AND last_updated BETWEEN NOW() - INTERVAL 60 SECOND AND NOW())
|
||||
AND key_name IN ("topic_key", "internal_ip", "server_port")"}, list(
|
||||
"sid" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
if(!dbq1.warn_execute())
|
||||
qdel(dbq1)
|
||||
return
|
||||
|
||||
var/servers_outer = list()
|
||||
while(dbq1.NextRow())
|
||||
if(!servers_outer[dbq1.item[1]])
|
||||
servers_outer[dbq1.item[1]] = list()
|
||||
|
||||
servers_outer[dbq1.item[1]][dbq1.item[2]] = dbq1.item[3] // This should assoc load our data
|
||||
|
||||
qdel(dbq1)
|
||||
|
||||
for(var/server in servers_outer)
|
||||
var/server_data = servers_outer[server]
|
||||
world.Export("byond://[server_data["internal_ip"]]:[server_data["server_port"]]?[raw_topic]&key=[server_data["topic_key"]]")
|
||||
|
||||
|
||||
/**
|
||||
* Player checker
|
||||
*
|
||||
* Check all connected peers to see if a player exists in the player cache
|
||||
* This is used to make sure players dont log into 2 servers at once
|
||||
* Arguments:
|
||||
* ckey - The ckey to check if they are logged into another server
|
||||
*/
|
||||
/datum/controller/subsystem/instancing/proc/check_player(ckey)
|
||||
// Please see above rant on L127
|
||||
var/datum/db_query/dbq1 = SSdbcore.NewQuery({"
|
||||
SELECT server_id, key_value FROM instance_data_cache WHERE server_id IN
|
||||
(SELECT server_id FROM instance_data_cache WHERE server_id != :sid AND
|
||||
key_name='heartbeat' AND last_updated BETWEEN NOW() - INTERVAL 60 SECOND AND NOW())
|
||||
AND key_name IN ("playerlist")"}, list(
|
||||
"sid" = GLOB.configuration.system.instance_id
|
||||
))
|
||||
if(!dbq1.warn_execute())
|
||||
qdel(dbq1)
|
||||
return
|
||||
|
||||
while(dbq1.NextRow())
|
||||
var/list/other_server_cache = json_decode(dbq1.item[2])
|
||||
if(ckey in other_server_cache)
|
||||
var/target_server = dbq1.item[1] // Yes. This var is necessary.
|
||||
qdel(dbq1)
|
||||
return target_server
|
||||
|
||||
qdel(dbq1)
|
||||
return null // If we are here, it means we didnt find our player on another server
|
||||
@@ -28,6 +28,7 @@ SUBSYSTEM_DEF(metrics)
|
||||
out["elapsed_real"] = (REALTIMEOFDAY - world_init_time)
|
||||
out["client_count"] = length(GLOB.clients)
|
||||
out["round_id"] = text2num(GLOB.round_id) // This is so we can filter the metrics by a single round ID
|
||||
out["server_id"] = GLOB.configuration.system.instance_id // And this is so we can filter by instance ID
|
||||
|
||||
// Funnel in all SS metrics
|
||||
var/list/ss_data = list()
|
||||
|
||||
@@ -18,10 +18,11 @@ SUBSYSTEM_DEF(statistics)
|
||||
return
|
||||
else
|
||||
var/datum/db_query/statquery = SSdbcore.NewQuery(
|
||||
"INSERT INTO legacy_population (playercount, admincount, time) VALUES (:playercount, :admincount, NOW())",
|
||||
"INSERT INTO legacy_population (playercount, admincount, time, server_id) VALUES (:playercount, :admincount, NOW(), :server_id)",
|
||||
list(
|
||||
"playercount" = length(GLOB.clients),
|
||||
"admincount" = length(GLOB.admins)
|
||||
"admincount" = length(GLOB.admins),
|
||||
"server_id" = GLOB.configuration.system.instance_id
|
||||
)
|
||||
)
|
||||
statquery.warn_execute()
|
||||
|
||||
@@ -408,12 +408,65 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(player.mind.assigned_role != player.mind.special_role)
|
||||
SSjobs.AssignRank(player, player.mind.assigned_role, FALSE)
|
||||
SSjobs.EquipRank(player, player.mind.assigned_role, FALSE)
|
||||
EquipCustomItems(player)
|
||||
equip_cuis(player)
|
||||
|
||||
if(captainless)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M))
|
||||
to_chat(M, "Captainship not forced on anyone.")
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/equip_cuis(mob/living/carbon/human/H)
|
||||
if(!H.client)
|
||||
return // If they are spawning without a client (somehow), they *cant* have a CUI list
|
||||
for(var/datum/custom_user_item/cui in H.client.cui_entries)
|
||||
// Skip items with invalid character names
|
||||
if((cui.characer_name != H.real_name) && !cui.all_characters_allowed)
|
||||
continue
|
||||
|
||||
var/ok = FALSE
|
||||
|
||||
if(!cui.all_jobs_allowed)
|
||||
var/alt_blocked = FALSE
|
||||
if(H.mind.role_alt_title)
|
||||
if(!(H.mind.role_alt_title in cui.allowed_jobs))
|
||||
alt_blocked = TRUE
|
||||
if(!(H.mind.assigned_role in cui.allowed_jobs) || alt_blocked)
|
||||
continue
|
||||
|
||||
var/obj/item/I = new cui.object_typepath()
|
||||
var/name_override = cui.item_name_override
|
||||
var/desc_override = cui.item_desc_override
|
||||
|
||||
if(name_override)
|
||||
I.name = name_override
|
||||
if(desc_override)
|
||||
I.desc = desc_override
|
||||
|
||||
if(istype(H.back, /obj/item/storage)) // Try to place it in something on the mob's back
|
||||
var/obj/item/storage/S = H.back
|
||||
if(length(S.contents) < S.storage_slots)
|
||||
I.forceMove(H.back)
|
||||
ok = TRUE
|
||||
to_chat(H, "<span class='notice'>Your [I.name] has been added to your [H.back.name].</span>")
|
||||
|
||||
if(!ok)
|
||||
for(var/obj/item/storage/S in H.contents) // Try to place it in any item that can store stuff, on the mob.
|
||||
if(length(S.contents) < S.storage_slots)
|
||||
I.forceMove(S)
|
||||
ok = TRUE
|
||||
to_chat(H, "<span class='notice'>Your [I.name] has been added to your [S.name].</span>")
|
||||
break
|
||||
|
||||
if(!ok) // Finally, since everything else failed, place it on the ground
|
||||
var/turf/T = get_turf(H)
|
||||
if(T)
|
||||
I.forceMove(T)
|
||||
to_chat(H, "<span class='notice'>Your [I.name] is on the [T.name] below you.</span>")
|
||||
else
|
||||
to_chat(H, "<span class='notice'>Your [I.name] couldnt spawn anywhere on you or even on the floor below you. Please file a bug report.</span>")
|
||||
qdel(I)
|
||||
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/send_tip_of_the_round()
|
||||
var/m
|
||||
if(selected_tip)
|
||||
|
||||
@@ -266,8 +266,12 @@ SUBSYSTEM_DEF(vote)
|
||||
<a href='?src=[UID()];vote=open'>Click here or type vote to place your vote.</a>
|
||||
You have [GLOB.configuration.vote.vote_time / 10] seconds to vote.</font>"})
|
||||
switch(vote_type)
|
||||
if("crew transfer", "gamemode", "custom", "map")
|
||||
if("crew transfer", "gamemode", "custom")
|
||||
SEND_SOUND(world, sound('sound/ambience/alarm4.ogg'))
|
||||
if("map")
|
||||
SEND_SOUND(world, sound('sound/ambience/alarm4.ogg'))
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
M.throw_alert("Map Vote", /obj/screen/alert/notify_mapvote, timeout_override = GLOB.configuration.vote.vote_time)
|
||||
if(mode == "gamemode" && SSticker.ticker_going)
|
||||
SSticker.ticker_going = FALSE
|
||||
to_chat(world, "<font color='red'><b>Round start has been delayed.</b></font>")
|
||||
|
||||
@@ -423,6 +423,13 @@
|
||||
/datum/action/item_action/remove_badge
|
||||
name = "Remove Holobadge"
|
||||
|
||||
|
||||
// Clown Acrobat Shoes
|
||||
/datum/action/item_action/slipping
|
||||
name = "Tactical Slip"
|
||||
desc = "Activates the clown shoes' ankle-stimulating module, allowing the user to do a short slip forward going under anyone."
|
||||
button_icon_state = "clown"
|
||||
|
||||
// Jump boots
|
||||
/datum/action/item_action/bhop
|
||||
name = "Activate Jump Boots"
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* # Custom User Item
|
||||
*
|
||||
* Holder for CUIs
|
||||
*
|
||||
* This datum is a holder that is essentially a "model" of the `customuseritems`
|
||||
* database table, and is used for giving people their CUIs on spawn.
|
||||
* It is instanced as part of the client data loading framework on the client.
|
||||
*
|
||||
*/
|
||||
/datum/custom_user_item
|
||||
/// Can this be used on all characters?
|
||||
var/all_characters_allowed = FALSE
|
||||
/// Name of the character that can have this item.
|
||||
var/characer_name
|
||||
/// Are all jobs allowed?
|
||||
var/all_jobs_allowed = FALSE
|
||||
/// List of allowed jobs
|
||||
var/list/allowed_jobs = list()
|
||||
/// Custom item typepath
|
||||
var/object_typepath
|
||||
/// Custom item name override
|
||||
var/item_name_override
|
||||
/// Custom item description override
|
||||
var/item_desc_override
|
||||
/// Raw job mask
|
||||
var/raw_job_mask
|
||||
|
||||
|
||||
/**
|
||||
* CUI Info Parser
|
||||
*
|
||||
* Parses all the raw info into usable stuff, and also does validity checks
|
||||
* Returns TRUE if its a valid item, and FALSE if not
|
||||
*
|
||||
* Arguments:
|
||||
* * owning_ckey - Player who owns this item. Used for logging purposes.
|
||||
*/
|
||||
/datum/custom_user_item/proc/parse_info(owning_ckey)
|
||||
. = FALSE // Setting this here means it will return false even if it runtimes
|
||||
|
||||
// Sort path
|
||||
if(!object_typepath || !ispath(object_typepath))
|
||||
stack_trace("Incorrect database entry found in table 'customuseritems' path value is [object_typepath ? object_typepath : "(NULL)"], which doesnt exist. Ask the host to look at CUI entries for [owning_ckey]")
|
||||
return
|
||||
|
||||
// Sort job mask
|
||||
if(raw_job_mask == "*")
|
||||
all_jobs_allowed = TRUE
|
||||
else
|
||||
var/list/local_allowed_jobs = splittext(raw_job_mask, ",")
|
||||
for(var/i in 1 to length(local_allowed_jobs))
|
||||
if(istext(local_allowed_jobs[i]))
|
||||
local_allowed_jobs[i] = trim(local_allowed_jobs[i])
|
||||
|
||||
allowed_jobs = local_allowed_jobs
|
||||
|
||||
// Sort character name
|
||||
if(characer_name == "*")
|
||||
all_characters_allowed = TRUE
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/custom_user_item/vv_edit_var(var_name, var_value)
|
||||
return FALSE // fuck off
|
||||
@@ -49,6 +49,7 @@ Bonus
|
||||
healed += min(E.brute_dam, get_damage) + min(E.burn_dam, get_damage)
|
||||
E.heal_damage(get_damage, get_damage, 0, 0)
|
||||
M.adjustToxLoss(healed)
|
||||
M.UpdateAppearance()
|
||||
|
||||
|
||||
else
|
||||
@@ -56,6 +57,7 @@ Bonus
|
||||
M.adjustFireLoss(-get_damage)
|
||||
M.adjustBruteLoss(-get_damage)
|
||||
M.adjustToxLoss(get_damage)
|
||||
M.UpdateAppearance()
|
||||
else
|
||||
return
|
||||
|
||||
|
||||
+16
-3
@@ -19,6 +19,8 @@
|
||||
var/headers
|
||||
/// URL that the request is being sent to
|
||||
var/url
|
||||
/// If present, response body will be saved to this file.
|
||||
var/output_file
|
||||
/// The raw response, which will be decoeded into a [/datum/http_response]
|
||||
var/_raw_response
|
||||
/// Callback for executing after async requests. Will be called with an argument of [/datum/http_response] as first argument
|
||||
@@ -42,7 +44,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB
|
||||
* * _body - The body of the request, if applicable
|
||||
* * _headers - Associative list of HTTP headers to send, if applicab;e
|
||||
*/
|
||||
/datum/http_request/proc/prepare(_method, _url, _body = "", list/_headers)
|
||||
/datum/http_request/proc/prepare(_method, _url, _body = "", list/_headers, _output_file)
|
||||
if(!length(_headers))
|
||||
headers = ""
|
||||
else
|
||||
@@ -51,6 +53,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB
|
||||
method = _method
|
||||
url = _url
|
||||
body = _body
|
||||
output_file = _output_file
|
||||
|
||||
/**
|
||||
* Blocking executor
|
||||
@@ -60,7 +63,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB
|
||||
*/
|
||||
/datum/http_request/proc/execute_blocking()
|
||||
CRASH("Attempted to execute a blocking HTTP request")
|
||||
// _raw_response = rustg_http_request_blocking(method, url, body, headers)
|
||||
// _raw_response = rustg_http_request_blocking(method, url, body, headers, build_options())
|
||||
|
||||
/**
|
||||
* Async execution starter
|
||||
@@ -73,7 +76,7 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB
|
||||
if(in_progress)
|
||||
CRASH("Attempted to re-use a request object.")
|
||||
|
||||
id = rustg_http_request_async(method, url, body, headers)
|
||||
id = rustg_http_request_async(method, url, body, headers, build_options())
|
||||
|
||||
if(isnull(text2num(id)))
|
||||
_raw_response = "Proc error: [id]"
|
||||
@@ -81,6 +84,16 @@ THE METHODS IN THIS FILE ARE TO BE USED BY THE SUBSYSTEM AS A MANGEMENT HUB
|
||||
else
|
||||
in_progress = TRUE
|
||||
|
||||
/**
|
||||
* Options builder
|
||||
*
|
||||
* Builds options for if we want to download files with SShttp
|
||||
*/
|
||||
/datum/http_request/proc/build_options()
|
||||
if(output_file)
|
||||
return json_encode(list("output_filename" = output_file, "body_filename" = null))
|
||||
return null
|
||||
|
||||
/**
|
||||
* Async completion checker
|
||||
*
|
||||
|
||||
+6
-3
@@ -86,7 +86,7 @@
|
||||
return ..()
|
||||
|
||||
/datum/mind/proc/get_display_key()
|
||||
var/clientKey = current?.client.get_display_key()
|
||||
var/clientKey = current?.client?.get_display_key()
|
||||
return clientKey ? clientKey : key
|
||||
|
||||
/datum/mind/proc/transfer_to(mob/living/new_character)
|
||||
@@ -107,6 +107,8 @@
|
||||
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
|
||||
var/datum/antagonist/A = a
|
||||
A.on_body_transfer(old_current, current)
|
||||
if(vampire)
|
||||
vampire.update_owner(new_character)
|
||||
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
|
||||
transfer_actions(new_character)
|
||||
if(martial_art)
|
||||
@@ -1544,14 +1546,15 @@
|
||||
|
||||
SSticker.mode.equip_syndicate(current)
|
||||
|
||||
/datum/mind/proc/make_Vampire()
|
||||
/datum/mind/proc/make_vampire(ancient_vampire = FALSE)
|
||||
if(!(src in SSticker.mode.vampires))
|
||||
SSticker.mode.vampires += src
|
||||
SSticker.mode.grant_vampire_powers(current)
|
||||
special_role = SPECIAL_ROLE_VAMPIRE
|
||||
SSticker.mode.forge_vampire_objectives(src)
|
||||
SSticker.mode.greet_vampire(src)
|
||||
SSticker.mode.update_vampire_icons_added(src)
|
||||
if(!ancient_vampire)
|
||||
SSticker.mode.forge_vampire_objectives(src)
|
||||
|
||||
/datum/mind/proc/make_Changeling()
|
||||
if(!(src in SSticker.mode.changelings))
|
||||
|
||||
@@ -1103,21 +1103,15 @@
|
||||
|
||||
if(H.mind)
|
||||
if(!H.mind.vampire)
|
||||
H.make_vampire()
|
||||
if(H.mind.vampire)
|
||||
H.mind.vampire.bloodusable = 9999
|
||||
H.mind.vampire.bloodtotal = 9999
|
||||
H.mind.vampire.check_vampire_upgrade(0)
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shapeshift/bats)
|
||||
to_chat(H, "You have gained the ability to shapeshift into bat form. This is a weak form with no abilities, only useful for stealth.")
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shapeshift/hellhound)
|
||||
to_chat(H, "You have gained the ability to shapeshift into lesser hellhound form. This is a combat form with different abilities, tough but not invincible. It can regenerate itself over time by resting.")
|
||||
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/raise_vampires)
|
||||
to_chat(H, "You have gained the ability to Raise Vampires. This extremely powerful AOE ability affects all humans near you. Vampires/thralls are healed. Corpses are raised as vampires. Others are stunned, then brain damaged, then killed.")
|
||||
H.dna.SetSEState(GLOB.jumpblock, 1)
|
||||
singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED)
|
||||
H.update_mutations()
|
||||
H.gene_stability = 100
|
||||
H.mind.make_vampire(TRUE)
|
||||
H.mind.vampire.bloodusable = 9999
|
||||
H.mind.vampire.bloodtotal = 9999
|
||||
H.mind.offstation_role = TRUE
|
||||
H.mind.vampire.add_subclass(SUBCLASS_ANCIENT, FALSE)
|
||||
H.dna.SetSEState(GLOB.jumpblock, TRUE)
|
||||
singlemutcheck(H, GLOB.jumpblock, MUTCHK_FORCED)
|
||||
H.update_mutations()
|
||||
H.gene_stability = 100
|
||||
|
||||
/datum/outfit/admin/wizard
|
||||
name = "Blue Wizard"
|
||||
|
||||
+47
-7
@@ -131,6 +131,11 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
var/special_availability_check = 0//Whether the spell needs to bypass the action button's IsAvailable()
|
||||
|
||||
var/sound = null //The sound the spell makes when it is cast
|
||||
/// If the ability is for vampires
|
||||
var/vampire_ability = FALSE
|
||||
var/required_blood = 0
|
||||
var/gain_desc = null
|
||||
var/deduct_blood_on_cast = TRUE
|
||||
|
||||
/* Checks if the user can cast the spell
|
||||
* @param charge_check If the proc should do the cooldown check
|
||||
@@ -190,6 +195,8 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
charge_counter = charge_max
|
||||
else
|
||||
start_recharge()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You can now use [src]."
|
||||
|
||||
/obj/effect/proc_holder/spell/Destroy()
|
||||
QDEL_NULL(action)
|
||||
@@ -238,6 +245,9 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
action.UpdateButtonIcon()
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/before_cast(list/targets)
|
||||
if(vampire_ability)
|
||||
if(!before_cast_vampire(targets))
|
||||
return
|
||||
if(overlay)
|
||||
for(var/atom/target in targets)
|
||||
var/location
|
||||
@@ -594,25 +604,55 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/clothcheck = locate(/obj/effect/proc_holder/spell/noclothes) in user.mob_spell_list
|
||||
var/clothcheck2 = user.mind && (locate(/obj/effect/proc_holder/spell/noclothes) in user.mind.spell_list)
|
||||
if(clothes_req && !clothcheck && !clothcheck2) //clothes check
|
||||
if(clothes_req && !clothcheck && !clothcheck2 && !vampire_ability) //clothes check
|
||||
var/obj/item/clothing/robe = H.wear_suit
|
||||
var/obj/item/clothing/hat = H.head
|
||||
var/obj/item/clothing/shoes = H.shoes
|
||||
if(!robe || !hat || !shoes)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='notice'>Your outfit isn't complete, you should put on your robe and wizard hat, as well as sandals.</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(!robe.magical || !hat.magical || !shoes.magical)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='notice'>Your outfit isn't magical enough, you should put on your robe and wizard hat, as well as your sandals.</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
else
|
||||
if(clothes_req || human_req)
|
||||
if(clothes_req || human_req || vampire_ability)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='notice'>This spell can only be cast by humans!</span>")
|
||||
return 0
|
||||
return FALSE
|
||||
if(nonabstract_req && (isbrain(user) || ispAI(user)))
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='notice'>This spell can only be cast by physical beings!</span>")
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
|
||||
if(vampire_ability)
|
||||
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
|
||||
if(!vampire)
|
||||
return FALSE
|
||||
|
||||
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
|
||||
|
||||
if(user.stat >= DEAD)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>Not while you're dead!</span>")
|
||||
return FALSE
|
||||
|
||||
if(vampire.nullified >= VAMPIRE_COMPLETE_NULLIFICATION && !fullpower) // above 100 nullification vampire powers are useless
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>Something is blocking your powers!</span>")
|
||||
return FALSE
|
||||
if(vampire.bloodusable < required_blood)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>You require at least [required_blood] units of usable blood to do that!</span>")
|
||||
return FALSE
|
||||
//chapel check
|
||||
if(istype(get_area(user), /area/chapel) && !fullpower)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>Your powers are useless on this holy ground.</span>")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -12,16 +12,18 @@
|
||||
include_user = 1
|
||||
nonabstract_req = 1
|
||||
centcom_cancast = 0 //Prevent people from getting to centcom
|
||||
|
||||
var/sound1 = 'sound/magic/ethereal_enter.ogg'
|
||||
var/jaunt_duration = 50 //in deciseconds
|
||||
var/jaunt_in_time = 5
|
||||
var/jaunt_in_type = /obj/effect/temp_visual/wizard
|
||||
var/jaunt_out_type = /obj/effect/temp_visual/wizard/out
|
||||
var/jaunt_type_path = /obj/effect/dummy/spell_jaunt
|
||||
var/jaunt_water_effect = TRUE
|
||||
|
||||
action_icon_state = "jaunt"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets, mob/user = usr) //magnets, so mostly hardcoded
|
||||
playsound(get_turf(user), 'sound/magic/ethereal_enter.ogg', 50, 1, -1)
|
||||
playsound(get_turf(user), sound1, 50, 1, -1)
|
||||
for(var/mob/living/target in targets)
|
||||
if(!target.can_safely_leave_loc()) // No more brainmobs hopping out of their brains
|
||||
to_chat(target, "<span class='warning'>You are somehow too bound to your current location to abandon it.</span>")
|
||||
@@ -31,13 +33,14 @@
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
|
||||
target.notransform = 1
|
||||
var/turf/mobloc = get_turf(target)
|
||||
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt(mobloc)
|
||||
var/obj/effect/dummy/spell_jaunt/holder = new jaunt_type_path(mobloc)
|
||||
new jaunt_out_type(mobloc, target.dir)
|
||||
target.ExtinguishMob()
|
||||
target.forceMove(holder)
|
||||
target.reset_perspective(holder)
|
||||
target.notransform = 0 //mob is safely inside holder now, no need for protection.
|
||||
jaunt_steam(mobloc)
|
||||
if(jaunt_water_effect)
|
||||
jaunt_steam(mobloc)
|
||||
|
||||
sleep(jaunt_duration)
|
||||
|
||||
@@ -45,22 +48,28 @@
|
||||
qdel(holder)
|
||||
return
|
||||
mobloc = get_turf(target.loc)
|
||||
jaunt_steam(mobloc)
|
||||
if(jaunt_water_effect)
|
||||
jaunt_steam(mobloc)
|
||||
target.canmove = 0
|
||||
holder.reappearing = 1
|
||||
playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
|
||||
sleep(25 - jaunt_in_time)
|
||||
sleep(jaunt_in_time * 4)
|
||||
new jaunt_in_type(mobloc, holder.dir)
|
||||
target.setDir(holder.dir)
|
||||
sleep(jaunt_in_time)
|
||||
qdel(holder)
|
||||
if(!QDELETED(target))
|
||||
if(mobloc.density)
|
||||
if(is_blocked_turf(mobloc, TRUE))
|
||||
for(var/turf/T in orange(7))
|
||||
if(T)
|
||||
if(target.Move(T))
|
||||
break
|
||||
target.canmove = 1
|
||||
if(isspaceturf(T))
|
||||
continue
|
||||
if(target.Move(T))
|
||||
target.remove_CC()
|
||||
return
|
||||
for(var/turf/space/S in orange(7))
|
||||
if(target.Move(S))
|
||||
break
|
||||
target.remove_CC()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc)
|
||||
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
|
||||
@@ -90,14 +99,34 @@
|
||||
return
|
||||
var/turf/newLoc = get_step(src,direction)
|
||||
setDir(direction)
|
||||
if(!(newLoc.flags & NOJAUNT))
|
||||
if(can_move(newLoc))
|
||||
forceMove(newLoc)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Some strange aura is blocking the way!</span>")
|
||||
to_chat(user, "<span class='warning'>Something is blocking the way!</span>")
|
||||
movedelay = world.time + movespeed
|
||||
|
||||
/obj/effect/dummy/spell_jaunt/proc/can_move(turf/T)
|
||||
if(T.flags & NOJAUNT)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/dummy/spell_jaunt/ex_act(blah)
|
||||
return
|
||||
|
||||
/obj/effect/dummy/spell_jaunt/bullet_act(blah)
|
||||
return
|
||||
|
||||
/obj/effect/dummy/spell_jaunt/blood_pool
|
||||
name = "sanguine pool"
|
||||
desc = "a pool of living blood."
|
||||
movespeed = 1.5
|
||||
|
||||
/obj/effect/dummy/spell_jaunt/blood_pool/relaymove(mob/user, direction)
|
||||
..()
|
||||
new /obj/effect/decal/cleanable/blood(loc)
|
||||
|
||||
|
||||
/obj/effect/dummy/spell_jaunt/blood_pool/can_move(turf/T)
|
||||
if(isspaceturf(T) || T.density)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
@@ -93,11 +93,11 @@
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/mime/fingergun
|
||||
name = "Finger Gun"
|
||||
desc = "Shoot stunning, invisible bullets out of your fingers! 6 bullets available per cast. Use your fingers to holster them manually."
|
||||
desc = "Shoot stunning, invisible bullets out of your fingers! 3 bullets available per cast. Use your fingers to holster them manually."
|
||||
school = "mime"
|
||||
panel = "Mime"
|
||||
clothes_req = 0
|
||||
charge_max = 600
|
||||
charge_max = 300
|
||||
range = -1
|
||||
include_user = 1
|
||||
human_req = 1
|
||||
@@ -117,7 +117,7 @@
|
||||
revert_cast(user)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/mime/fingergun/fake
|
||||
desc = "Pretend you're shooting bullets out of your fingers! 6 bullets available per cast. Use your fingers to holster them manually."
|
||||
desc = "Pretend you're shooting bullets out of your fingers! 3 bullets available per cast. Use your fingers to holster them manually."
|
||||
gun = /obj/item/gun/projectile/revolver/fingergun/fake
|
||||
|
||||
// Mime Spellbooks
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
invocation = "none"
|
||||
invocation_type = "none"
|
||||
action_icon_state = "vampire_bats"
|
||||
gain_desc = "You have gained the ability to shapeshift into bat form. This is a weak form with no abilities, only useful for stealth."
|
||||
|
||||
shapeshift_type = /mob/living/simple_animal/hostile/scarybat/adminvampire
|
||||
current_shapes = list(/mob/living/simple_animal/hostile/scarybat/adminvampire)
|
||||
@@ -108,6 +109,7 @@
|
||||
invocation_type = "none"
|
||||
action_background_icon_state = "bg_demon"
|
||||
action_icon_state = "glare"
|
||||
gain_desc = "You have gained the ability to shapeshift into lesser hellhound form. This is a combat form with different abilities, tough but not invincible. It can regenerate itself over time by resting."
|
||||
|
||||
shapeshift_type = /mob/living/simple_animal/hostile/hellhound
|
||||
current_shapes = list(/mob/living/simple_animal/hostile/hellhound)
|
||||
|
||||
@@ -8,12 +8,16 @@
|
||||
|
||||
var/include_space = 0 //whether it includes space tiles in possible teleport locations
|
||||
var/include_dense = 0 //whether it includes dense tiles in possible teleport locations
|
||||
/// Whether the spell can teleport to light locations
|
||||
var/include_light_turfs = TRUE
|
||||
|
||||
var/sound1 = 'sound/weapons/zapbang.ogg'
|
||||
var/sound2 = 'sound/weapons/zapbang.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/turf_teleport/cast(list/targets,mob/living/user = usr)
|
||||
playsound(get_turf(user), sound1, 50,1)
|
||||
if(sound1)
|
||||
playsound(get_turf(user), sound1, 50,1)
|
||||
|
||||
for(var/mob/living/target in targets)
|
||||
var/list/turfs = new/list()
|
||||
for(var/turf/T in range(target,outer_tele_radius))
|
||||
@@ -22,6 +26,10 @@
|
||||
if(T.density && !include_dense) continue
|
||||
if(T.x>world.maxx-outer_tele_radius || T.x<outer_tele_radius) continue //putting them at the edge is dumb
|
||||
if(T.y>world.maxy-outer_tele_radius || T.y<outer_tele_radius) continue
|
||||
if(!include_light_turfs)
|
||||
var/lightingcount = T.get_lumcount() * 10
|
||||
if(lightingcount > 2)
|
||||
continue
|
||||
turfs += T
|
||||
|
||||
if(!turfs.len)
|
||||
@@ -37,4 +45,5 @@
|
||||
return
|
||||
|
||||
target.forceMove(picked)
|
||||
playsound(get_turf(user), sound2, 50,1)
|
||||
if(sound2)
|
||||
playsound(get_turf(user), sound2, 50,1)
|
||||
|
||||
@@ -134,6 +134,59 @@
|
||||
if(islist(owner.stun_absorption) && owner.stun_absorption["blooddrunk"])
|
||||
owner.stun_absorption -= "blooddrunk"
|
||||
|
||||
/datum/status_effect/bloodswell
|
||||
id = "bloodswell"
|
||||
duration = 30 SECONDS
|
||||
tick_interval = 0
|
||||
alert_type = /obj/screen/alert/status_effect/blood_swell
|
||||
var/bonus_damage_applied = FALSE
|
||||
|
||||
/obj/screen/alert/status_effect/blood_swell
|
||||
name = "Blood Swell"
|
||||
desc = "Your body has been infused with crimson magics, your resistance to attacks has greatly increased!"
|
||||
icon = 'icons/mob/actions/actions.dmi'
|
||||
icon_state = "blood_swell_status"
|
||||
|
||||
/datum/status_effect/bloodswell/on_apply()
|
||||
. = ..()
|
||||
if(!. || !ishuman(owner))
|
||||
return FALSE
|
||||
ADD_TRAIT(owner, TRAIT_CHUNKYFINGERS, VAMPIRE_TRAIT)
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.physiology.brute_mod *= 0.5
|
||||
H.physiology.burn_mod *= 0.8
|
||||
H.physiology.stamina_mod *= 0.5
|
||||
H.physiology.stun_mod *= 0.5
|
||||
if(owner.mind.vampire.get_ability(/datum/vampire_passive/blood_swell_upgrade))
|
||||
bonus_damage_applied = TRUE
|
||||
H.physiology.melee_bonus += 10
|
||||
H.dna.species.punchstunthreshold += 8 //higher chance to stun but not 100%
|
||||
|
||||
/datum/status_effect/bloodswell/on_remove()
|
||||
if(!ishuman(owner))
|
||||
return
|
||||
REMOVE_TRAIT(owner, TRAIT_CHUNKYFINGERS, VAMPIRE_TRAIT)
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.physiology.brute_mod /= 0.5
|
||||
H.physiology.burn_mod /= 0.8
|
||||
H.physiology.stamina_mod /= 0.5
|
||||
H.physiology.stun_mod /= 0.5
|
||||
if(bonus_damage_applied)
|
||||
bonus_damage_applied = FALSE
|
||||
H.physiology.melee_bonus -= 10
|
||||
H.dna.species.punchstunthreshold -= 8
|
||||
|
||||
/datum/status_effect/blood_rush
|
||||
alert_type = null
|
||||
duration = 10 SECONDS
|
||||
|
||||
/datum/status_effect/blood_rush/on_apply()
|
||||
ADD_TRAIT(owner, TRAIT_GOTTAGOFAST, VAMPIRE_TRAIT)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/blood_rush/on_remove()
|
||||
REMOVE_TRAIT(owner, TRAIT_GOTTAGOFAST, VAMPIRE_TRAIT)
|
||||
|
||||
/datum/status_effect/exercised
|
||||
id = "Exercised"
|
||||
duration = 1200
|
||||
|
||||
@@ -45,3 +45,7 @@
|
||||
|
||||
/datum/status_effect/high_five/on_remove()
|
||||
owner.visible_message("[owner] was left hanging....")
|
||||
|
||||
/datum/status_effect/charging
|
||||
id = "charging"
|
||||
alert_type = null
|
||||
|
||||
@@ -272,14 +272,6 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
|
||||
cost = 15
|
||||
containername = "laser crate"
|
||||
|
||||
/datum/supply_packs/security/taser
|
||||
name = "Stun Guns Crate"
|
||||
contains = list(/obj/item/gun/energy/gun/advtaser,
|
||||
/obj/item/gun/energy/gun/advtaser,
|
||||
/obj/item/gun/energy/gun/advtaser)
|
||||
cost = 15
|
||||
containername = "stun gun crate"
|
||||
|
||||
/datum/supply_packs/security/disabler
|
||||
name = "Disabler Crate"
|
||||
contains = list(/obj/item/gun/energy/disabler,
|
||||
@@ -507,7 +499,7 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
|
||||
/obj/item/reagent_containers/spray/pepper,
|
||||
/obj/item/flash,
|
||||
/obj/item/grenade/flashbang,
|
||||
/obj/item/storage/belt/security/sec,
|
||||
/obj/item/storage/belt/security,
|
||||
/obj/item/holosign_creator/security,
|
||||
/obj/item/clothing/mask/gas/sechailer,
|
||||
/obj/item/clothing/glasses/hud/security/sunglasses,
|
||||
@@ -1216,6 +1208,12 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
|
||||
containertype = /obj/structure/closet/critter/deer
|
||||
containername = "deer crate"
|
||||
|
||||
/datum/supply_packs/organic/bunny
|
||||
name = "Bunny Crate"
|
||||
cost = 20
|
||||
containertype = /obj/structure/closet/critter/bunny
|
||||
containername = "bunny crate"
|
||||
|
||||
////// hippy gear
|
||||
|
||||
/datum/supply_packs/organic/hydroponics // -- Skie
|
||||
@@ -1456,6 +1454,12 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
|
||||
containertype = /obj/structure/closet/crate/secure
|
||||
containername = "shaft miner starter kit"
|
||||
|
||||
/datum/supply_packs/misc/carpet
|
||||
name = "Carpet Crate"
|
||||
cost = 20
|
||||
contains = list(/obj/item/stack/tile/carpet/twenty)
|
||||
containername = "carpet crate"
|
||||
|
||||
|
||||
///////////// Paper Work
|
||||
|
||||
|
||||
+24
-21
@@ -167,18 +167,19 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
//Clown
|
||||
/datum/uplink_item/jobspecific/clowngrenade
|
||||
name = "Banana Grenade"
|
||||
desc = "A grenade that explodes into HONK! brand banana peels that are genetically modified to be extra slippery and extrude caustic acid when stepped on"
|
||||
desc = "A grenade that explodes into HONK! brand banana peels that are genetically modified to be extra slippery and extrude caustic acid when stepped on."
|
||||
reference = "BG"
|
||||
item = /obj/item/grenade/clown_grenade
|
||||
cost = 5
|
||||
job = list("Clown")
|
||||
|
||||
/datum/uplink_item/jobspecific/clownmagboots
|
||||
name = "Clown Magboots"
|
||||
desc = "A pair of modified clown shoes fitted with an advanced magnetic traction system. Look and sound exactly like regular clown shoes unless closely inspected."
|
||||
reference = "CM"
|
||||
item = /obj/item/clothing/shoes/magboots/clown
|
||||
/datum/uplink_item/jobspecific/clownslippers
|
||||
name = "Clown Acrobatic Shoes"
|
||||
desc = "A pair of modified clown shoes fitted with a built-in propulsion system that allows the user to perform a short slip below anyone. Turning on the waddle dampeners removes the slowdown on the shoes."
|
||||
reference = "CAS"
|
||||
item = /obj/item/clothing/shoes/clown_shoes/slippers
|
||||
cost = 3
|
||||
surplus = 75
|
||||
job = list("Clown")
|
||||
|
||||
/datum/uplink_item/jobspecific/trick_revolver
|
||||
@@ -560,13 +561,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
item = /obj/item/twohanded/chainsaw
|
||||
cost = 13
|
||||
|
||||
/datum/uplink_item/dangerous/batterer
|
||||
name = "Mind Batterer"
|
||||
desc = "A device that has a chance of knocking down people around you for a long amount of time. 50% chance per person. The user is unaffected. Has 5 charges."
|
||||
reference = "BTR"
|
||||
item = /obj/item/batterer
|
||||
cost = 5
|
||||
|
||||
// SUPPORT AND MECHAS
|
||||
|
||||
/datum/uplink_item/support
|
||||
@@ -707,12 +701,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
cost = 2
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/ammo/bullstun
|
||||
name = "Bulldog - 12g Stun Slug Magazine"
|
||||
desc = "An alternative 8-round stun slug magazine for use in the Bulldog shotgun. Saying that they're completely non-lethal would be lying."
|
||||
reference = "12SS"
|
||||
item = /obj/item/ammo_box/magazine/m12g/stun
|
||||
cost = 3
|
||||
/datum/uplink_item/ammo/bullmeteor
|
||||
name = "12g Meteorslug Shells"
|
||||
desc = "An alternative 8-round meteorslug magazine for use in the Bulldog shotgun. Great for blasting airlocks off their frames and knocking down enemies."
|
||||
reference = "12MS"
|
||||
item = /obj/item/ammo_box/magazine/m12g/meteor
|
||||
cost = 2
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/ammo/bulldragon
|
||||
@@ -876,6 +870,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
item = /obj/item/CQC_manual
|
||||
cost = 13
|
||||
cant_discount = TRUE
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/stealthy_weapons/cameraflash
|
||||
name = "Camera Flash"
|
||||
@@ -972,6 +967,14 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
cost = 5
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/stealthy_weapons/combat_minus
|
||||
name = "Experimental Krav Gloves"
|
||||
desc = "Experimental gloves with installed nanochips that teach you Krav Maga when worn, great as a cheap backup weapon. Warning, the nanochips will override any other fighting styles such as CQC. Do not look as fly as the Warden's"
|
||||
reference = "CGM"
|
||||
item = /obj/item/clothing/gloves/color/black/krav_maga
|
||||
cost = 10
|
||||
excludefrom = list(/datum/game_mode/nuclear)
|
||||
|
||||
// GRENADES AND EXPLOSIVES
|
||||
|
||||
/datum/uplink_item/explosives
|
||||
@@ -979,7 +982,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
|
||||
/datum/uplink_item/explosives/plastic_explosives
|
||||
name = "Composition C-4"
|
||||
desc = "C-4 is plastic explosive of the common variety Composition C. You can use it to breach walls or connect an assembly to its wiring to make it remotely detonable. It has a modifiable timer with a minimum setting of 10 seconds."
|
||||
desc = "C-4 is plastic explosive of the common variety Composition C. Reliably destroys the object it's placed on, assuming it isn't bomb resistant. Does not stick to crewmembers. Will only destroy station floors if placed directly on it. It has a modifiable timer with a minimum setting of 10 seconds."
|
||||
reference = "C4"
|
||||
item = /obj/item/grenade/plastic/c4
|
||||
cost = 1
|
||||
@@ -1004,7 +1007,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
|
||||
name = "Composition X-4"
|
||||
desc = "X-4 is a shaped charge designed to be safe to the user while causing maximum damage to the occupants of the room beach breached. It has a modifiable timer with a minimum setting of 10 seconds."
|
||||
reference = "X4"
|
||||
item = /obj/item/grenade/plastic/x4
|
||||
item = /obj/item/grenade/plastic/c4/x4
|
||||
cost = 2
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
|
||||
@@ -1371,8 +1371,8 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
|
||||
/area/security/brig/prison_break()
|
||||
for(var/obj/structure/closet/secure_closet/brig/temp_closet in src)
|
||||
temp_closet.locked = 0
|
||||
temp_closet.icon_state = temp_closet.icon_closed
|
||||
temp_closet.locked = FALSE
|
||||
temp_closet.close()
|
||||
for(var/obj/machinery/door_timer/temp_timer in src)
|
||||
temp_timer.releasetime = 1
|
||||
..()
|
||||
@@ -1391,7 +1391,8 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
|
||||
/area/security/prison/prison_break()
|
||||
for(var/obj/structure/closet/secure_closet/brig/temp_closet in src)
|
||||
temp_closet.locked = 0
|
||||
temp_closet.icon_state = temp_closet.icon_closed
|
||||
temp_closet.close()
|
||||
temp_closet.update_icon()
|
||||
for(var/obj/machinery/door_timer/temp_timer in src)
|
||||
temp_timer.releasetime = 1
|
||||
..()
|
||||
|
||||
@@ -501,7 +501,7 @@
|
||||
log_game("Teleport spell failed - no other teleport runes")
|
||||
return
|
||||
if(!is_level_reachable(user.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
|
||||
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
|
||||
log_game("Teleport spell failed - user in away mission")
|
||||
return
|
||||
|
||||
|
||||
@@ -139,6 +139,11 @@
|
||||
to_chat(user, "<span class='cultitalic'>The veil is not weak enough here to summon a cultist, you must be on station!</span>")
|
||||
return
|
||||
|
||||
if(ispath(rune, /obj/effect/rune/teleport))
|
||||
if(!is_level_reachable(user.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
|
||||
return
|
||||
|
||||
var/old_color = user.color // we'll temporarily redden the user for better feedback to fellow cultists. Store this to revert them back.
|
||||
if(narsie_rune)
|
||||
if(!narsie_rune_check(user, A))
|
||||
|
||||
@@ -461,7 +461,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
return
|
||||
|
||||
if(!is_level_reachable(user.z))
|
||||
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
|
||||
to_chat(user, "<span class='cultitalic'>You are too far away from the station to teleport!</span>")
|
||||
log_game("Teleport rune failed - user in away mission")
|
||||
fail_invoke()
|
||||
return
|
||||
|
||||
@@ -786,3 +786,24 @@
|
||||
/datum/AI_Module/large/cameracrack/upgrade(mob/living/silicon/ai/AI)
|
||||
if(AI.builtInCamera)
|
||||
QDEL_NULL(AI.builtInCamera)
|
||||
|
||||
/datum/AI_Module/large/engi_upgrade
|
||||
module_name = "Engineering Cyborg Emitter Upgrade"
|
||||
mod_pick_name = "emitter"
|
||||
description = "Downloads firmware that activates the built in emitter in all engineering cyborgs linked to you. Cyborgs built after this upgrade will have it pre-installed."
|
||||
cost = 50 // IDK look into this
|
||||
one_purchase = TRUE
|
||||
upgrade = TRUE
|
||||
unlock_text = "<span class='notice'>Firmware downloaded. Bugs removed. Built in emitters operating at 73% efficiency.</span>"
|
||||
unlock_sound = 'sound/items/rped.ogg'
|
||||
|
||||
/datum/AI_Module/large/engi_upgrade/upgrade(mob/living/silicon/ai/AI)
|
||||
AI.purchased_modules += /obj/item/robot_module/engineering
|
||||
log_game("[key_name(usr)] purchased emitters for all engineering cyborgs.")
|
||||
message_admins("<span class='notice'>[key_name_admin(usr)] purchased emitters for all engineering cyborgs!</span>")
|
||||
for(var/mob/living/silicon/robot/R in AI.connected_robots)
|
||||
if(!istype(R.module, /obj/item/robot_module/engineering))
|
||||
continue
|
||||
R.module.malfhacked = TRUE
|
||||
R.module.rebuild_modules()
|
||||
to_chat(R, "<span class='notice'>New firmware downloaded. Emitter is now online.</span>")
|
||||
|
||||
@@ -736,7 +736,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
|
||||
desc = "Contains secrets of the universe."
|
||||
icon_state = "abductor"
|
||||
icon_closed = "abductor"
|
||||
icon_opened = "abductoropen"
|
||||
icon_opened = "abductor_open"
|
||||
material_drop = /obj/item/stack/sheet/mineral/abductor
|
||||
|
||||
/obj/structure/door_assembly/door_assembly_abductor
|
||||
|
||||
@@ -42,19 +42,32 @@
|
||||
speed = 1
|
||||
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
|
||||
|
||||
var/essence = 75 //The resource of revenants. Max health is equal to three times this amount
|
||||
var/essence_regen_cap = 75 //The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
var/essence_regenerating = 1 //If the revenant regenerates essence or not; 1 for yes, 0 for no
|
||||
var/essence_regen_amount = 5 //How much essence regenerates
|
||||
var/essence_accumulated = 0 //How much essence the revenant has stolen
|
||||
var/revealed = 0 //If the revenant can take damage from normal sources.
|
||||
var/unreveal_time = 0 //How long the revenant is revealed for, is about 2 seconds times this var.
|
||||
var/unstun_time = 0 //How long the revenant is stunned for, is about 2 seconds times this var.
|
||||
var/inhibited = 0 //If the revenant's abilities are blocked by a chaplain's power.
|
||||
var/essence_drained = 0 //How much essence the revenant has drained.
|
||||
var/draining = 0 //If the revenant is draining someone.
|
||||
var/list/drained_mobs = list() //Cannot harvest the same mob twice
|
||||
var/perfectsouls = 0 //How many perfect, regen-cap increasing souls the revenant has.
|
||||
///The resource of revenants. Max health is equal to three times this amount
|
||||
var/essence = 75
|
||||
///The regeneration cap of essence (go figure); regenerates every Life() tick up to this amount.
|
||||
var/essence_regen_cap = 75
|
||||
///If the revenant regenerates essence or not; 1 for yes, 0 for no
|
||||
var/essence_regenerating = TRUE
|
||||
///How much essence regenerates
|
||||
var/essence_regen_amount = 5
|
||||
///How much essence the revenant has stolen
|
||||
var/essence_accumulated = 0
|
||||
///If the revenant can take damage from normal sources.
|
||||
var/revealed = FALSE
|
||||
///How long the revenant is revealed for, is about 2 seconds times this var.
|
||||
var/unreveal_time = 0
|
||||
///How long the revenant is stunned for, is about 2 seconds times this var.
|
||||
var/unstun_time = 0
|
||||
///If the revenant's abilities are blocked by a chaplain's power.
|
||||
var/inhibited = FALSE
|
||||
///How much essence the revenant has drained.
|
||||
var/essence_drained = 0
|
||||
///If the revenant is draining someone.
|
||||
var/draining = FALSE
|
||||
/// contains a list of UIDs of mobs who have been drained. cannot drain the same mob twice.
|
||||
var/list/drained_mobs = list()
|
||||
///How many perfect, regen-cap increasing souls the revenant has.
|
||||
var/perfectsouls = 0
|
||||
|
||||
|
||||
/mob/living/simple_animal/revenant/Life(seconds, times_fired)
|
||||
@@ -232,25 +245,21 @@
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/castcheck(essence_cost)
|
||||
if(!src)
|
||||
return
|
||||
if(holy_check(src))
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
if(istype(T, /turf/simulated/wall))
|
||||
to_chat(src, "<span class='revenwarning'>You cannot use abilities from inside of a wall.</span>")
|
||||
return 0
|
||||
if(src.inhibited)
|
||||
if(inhibited)
|
||||
to_chat(src, "<span class='revenwarning'>Your powers have been suppressed by nulling energy!</span>")
|
||||
return 0
|
||||
if(!src.change_essence_amount(essence_cost, 1))
|
||||
if(!change_essence_amount(essence_cost, 1))
|
||||
to_chat(src, "<span class='revenwarning'>You lack the essence to use that ability.</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = 0, source = null)
|
||||
if(!src)
|
||||
return
|
||||
if(essence + essence_amt <= 0)
|
||||
return
|
||||
essence = max(0, essence+essence_amt)
|
||||
@@ -264,8 +273,6 @@
|
||||
return 1
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/reveal(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
revealed = 1
|
||||
@@ -280,8 +287,6 @@
|
||||
update_spooky_icon()
|
||||
|
||||
/mob/living/simple_animal/revenant/proc/stun(time)
|
||||
if(!src)
|
||||
return
|
||||
if(time <= 0)
|
||||
return
|
||||
notransform = 1
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
if(draining)
|
||||
to_chat(src, "<span class='revenwarning'>You are already siphoning the essence of a soul!</span>")
|
||||
return
|
||||
if(target in drained_mobs)
|
||||
var/mob_UID = target.UID()
|
||||
if(mob_UID in drained_mobs)
|
||||
to_chat(src, "<span class='revenwarning'>[target]'s soul is dead and empty.</span>")
|
||||
return
|
||||
if(!target.stat)
|
||||
@@ -39,7 +40,7 @@
|
||||
if(prob(10))
|
||||
to_chat(target, "You feel as if you are being watched.")
|
||||
return
|
||||
draining = 1
|
||||
draining = TRUE
|
||||
essence_drained = rand(15, 20)
|
||||
to_chat(src, "<span class='revennotice'>You search for the soul of [target].</span>")
|
||||
if(do_after(src, 10, 0, target = target)) //did they get deleted in that second?
|
||||
@@ -65,7 +66,7 @@
|
||||
if(!target.stat)
|
||||
to_chat(src, "<span class='revenwarning'>They are now powerful enough to fight off your draining.</span>")
|
||||
to_chat(target, "<span class='boldannounce'>You feel something tugging across your body before subsiding.</span>")
|
||||
draining = 0
|
||||
draining = FALSE
|
||||
return //hey, wait a minute...
|
||||
to_chat(src, "<span class='revenminor'>You begin siphoning essence from [target]'s soul.</span>")
|
||||
if(target.stat != DEAD)
|
||||
@@ -84,7 +85,8 @@
|
||||
to_chat(src, "<span class='revennotice'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>")
|
||||
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
|
||||
"<span class='revenwarning'>Violets lights, dancing in your vision, getting clo--</span>")
|
||||
drained_mobs.Add(target)
|
||||
drained_mobs.Add(mob_UID)
|
||||
add_attack_logs(src, target, "revenant harvested soul")
|
||||
target.death(0)
|
||||
else
|
||||
to_chat(src, "<span class='revenwarning'>[target ? "[target] has":"They have"] been drawn out of your grasp. The link has been broken.</span>")
|
||||
@@ -96,10 +98,10 @@
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='revenwarning'>You are not close enough to siphon [target ? "[target]'s":"their"] soul. The link has been broken.</span>")
|
||||
draining = 0
|
||||
draining = FALSE
|
||||
essence_drained = 0
|
||||
return
|
||||
draining = 0
|
||||
draining = FALSE
|
||||
essence_drained = 0
|
||||
return
|
||||
|
||||
@@ -142,7 +144,7 @@
|
||||
name = "Report this to a coder"
|
||||
var/reveal = 80 //How long it reveals the revenant in deciseconds
|
||||
var/stun = 20 //How long it stuns the revenant in deciseconds
|
||||
var/locked = 1 //If it's locked and needs to be unlocked before use
|
||||
var/locked = TRUE //If it's locked and needs to be unlocked before use
|
||||
var/unlock_amount = 100 //How much essence it costs to unlock
|
||||
var/cast_amount = 50 //How much essence it costs to use
|
||||
|
||||
@@ -155,36 +157,36 @@
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, charge_check = TRUE, show_message = FALSE)
|
||||
if(user.inhibited)
|
||||
return 0
|
||||
return FALSE
|
||||
if(charge_counter < charge_max)
|
||||
return 0
|
||||
return FALSE
|
||||
if(locked)
|
||||
if(user.essence <= unlock_amount)
|
||||
return 0
|
||||
return FALSE
|
||||
if(user.essence <= cast_amount)
|
||||
return 0
|
||||
return 1
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/proc/attempt_cast(mob/living/simple_animal/revenant/user = usr)
|
||||
if(locked)
|
||||
if(!user.castcheck(-unlock_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
return FALSE
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
to_chat(user, "<span class='revennotice'>You have unlocked [initial(name)]!</span>")
|
||||
panel = "Revenant Abilities"
|
||||
locked = 0
|
||||
locked = FALSE
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
return FALSE
|
||||
if(!user.castcheck(-cast_amount))
|
||||
charge_counter = charge_max
|
||||
return 0
|
||||
return FALSE
|
||||
name = "[initial(name)] ([cast_amount]E)"
|
||||
user.reveal(reveal)
|
||||
user.stun(stun)
|
||||
if(action)
|
||||
action.UpdateButtonIcon()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload
|
||||
@@ -201,25 +203,29 @@
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/obj/machinery/light/L in T.contents)
|
||||
spawn(0)
|
||||
if(!L.on)
|
||||
return
|
||||
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
do_sparks(4, 0, L)
|
||||
new/obj/effect/temp_visual/revenant(L.loc)
|
||||
sleep(20)
|
||||
if(!L.on) //wait, wait, don't shock me
|
||||
return
|
||||
flick("[L.base_state]2", L)
|
||||
for(var/mob/living/M in view(shock_range, L))
|
||||
if(M == user)
|
||||
return
|
||||
M.Beam(L,icon_state="purple_lightning",icon='icons/effects/effects.dmi',time=5)
|
||||
M.electrocute_act(shock_damage, L, flags = SHOCK_NOGLOVES)
|
||||
do_sparks(4, 0, M)
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
select_lights(T, user)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/select_lights(turf/T, mob/living/simple_animal/revenant/user)
|
||||
for(var/obj/machinery/light/L in T.contents)
|
||||
INVOKE_ASYNC(src, .proc/shock_lights, L, user)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/shock_lights(obj/machinery/light/L, mob/living/simple_animal/revenant/user)
|
||||
if(!L.on)
|
||||
return
|
||||
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
|
||||
do_sparks(4, 0, L)
|
||||
new /obj/effect/temp_visual/revenant(L.loc)
|
||||
sleep(2 SECONDS)
|
||||
if(!L.on) //wait, wait, don't shock me
|
||||
return
|
||||
flick("[L.base_state]2", L)
|
||||
for(var/mob/living/M in view(shock_range, L))
|
||||
if(M == user)
|
||||
continue
|
||||
M.Beam(L, icon_state = "purple_lightning", icon = 'icons/effects/effects.dmi', time = 0.5 SECONDS)
|
||||
M.electrocute_act(shock_damage, L, flags = SHOCK_NOGLOVES)
|
||||
do_sparks(4, 0, M)
|
||||
playsound(M, 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
|
||||
|
||||
//Defile: Corrupts nearby stuff, unblesses floor tiles.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile
|
||||
@@ -232,46 +238,14 @@
|
||||
unlock_amount = 75
|
||||
cast_amount = 30
|
||||
action_icon_state = "defile"
|
||||
var/stamdamage= 25
|
||||
var/toxdamage = 5
|
||||
var/confusion = 20
|
||||
var/maxconfusion = 30
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
if(T.flags & NOJAUNT)
|
||||
T.flags -= NOJAUNT
|
||||
new/obj/effect/temp_visual/revenant(T)
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
to_chat(human, "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>")
|
||||
human.adjustStaminaLoss(stamdamage)
|
||||
human.adjustToxLoss(toxdamage)
|
||||
human.AdjustConfused(confusion, bound_lower = 0, bound_upper = maxconfusion)
|
||||
new/obj/effect/temp_visual/revenant(human.loc)
|
||||
if(!istype(T, /turf/simulated/wall/indestructible) && !istype(T, /turf/simulated/wall/rust) && !istype(T, /turf/simulated/wall/r_wall) && istype(T, /turf/simulated/wall) && prob(15))
|
||||
new/obj/effect/temp_visual/revenant(T)
|
||||
T.ChangeTurf(/turf/simulated/wall/rust)
|
||||
if(!istype(T, /turf/simulated/wall/r_wall/rust) && istype(T, /turf/simulated/wall/r_wall) && prob(15))
|
||||
new/obj/effect/temp_visual/revenant(T)
|
||||
T.ChangeTurf(/turf/simulated/wall/r_wall/rust)
|
||||
for(var/obj/structure/window/window in T.contents)
|
||||
window.take_damage(rand(30,80))
|
||||
if(window && window.fulltile)
|
||||
new/obj/effect/temp_visual/revenant/cracks(window.loc)
|
||||
for(var/obj/structure/closet/closet in T.contents)
|
||||
closet.open()
|
||||
|
||||
if(!istype(T, /turf/simulated/floor/plating) && !istype(T, /turf/simulated/floor/engine/cult) && istype(T, /turf/simulated/floor) && prob(15))
|
||||
var/turf/simulated/floor/floor = T
|
||||
if(floor.intact && floor.floor_tile)
|
||||
new floor.floor_tile(floor)
|
||||
floor.broken = 0
|
||||
floor.burnt = 0
|
||||
floor.make_plating(1)
|
||||
for(var/obj/machinery/light/light in T.contents)
|
||||
light.flicker(30) //spooky
|
||||
if(!attempt_cast(user))
|
||||
return
|
||||
for(var/turf/T in targets)
|
||||
T.defile()
|
||||
for(var/atom/A in T.contents)
|
||||
A.defile()
|
||||
|
||||
//Malfunction: Makes bad stuff happen to robots and machines.
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction
|
||||
@@ -287,29 +261,107 @@
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
|
||||
if(attempt_cast(user))
|
||||
for(var/turf/T in targets)
|
||||
spawn(0)
|
||||
for(var/mob/living/simple_animal/bot/bot in T.contents)
|
||||
if(!bot.emagged)
|
||||
new/obj/effect/temp_visual/revenant(bot.loc)
|
||||
bot.locked = 0
|
||||
bot.open = 1
|
||||
bot.emag_act(null)
|
||||
for(var/mob/living/carbon/human/human in T.contents)
|
||||
to_chat(human, "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
|
||||
new/obj/effect/temp_visual/revenant(human.loc)
|
||||
human.emp_act(1)
|
||||
for(var/obj/thing in T.contents)
|
||||
if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on dominators, SMES and APCs, to prevent kekkery
|
||||
continue
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
new/obj/effect/temp_visual/revenant(thing.loc)
|
||||
thing.emag_act(null)
|
||||
else
|
||||
if(!istype(thing, /obj/machinery/clonepod)) //I hate everything but mostly the fact there's no better way to do this without just not affecting it at all
|
||||
thing.emp_act(1)
|
||||
for(var/mob/living/silicon/robot/S in T.contents) //Only works on cyborgs, not AI
|
||||
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
|
||||
new/obj/effect/temp_visual/revenant(S.loc)
|
||||
S.spark_system.start()
|
||||
S.emp_act(1)
|
||||
INVOKE_ASYNC(src, .proc/effect, user, T)
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/proc/effect(mob/living/simple_animal/revenant/user, turf/T)
|
||||
T.rev_malfunction()
|
||||
for(var/atom/A in T.contents)
|
||||
A.rev_malfunction()
|
||||
|
||||
|
||||
/atom/proc/defile()
|
||||
return
|
||||
|
||||
/atom/proc/rev_malfunction()
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/rev_malfunction()
|
||||
to_chat(src, "<span class='warning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
emp_act(1)
|
||||
|
||||
/mob/living/simple_animal/bot/rev_malfunction()
|
||||
if(!emagged)
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
locked = FALSE
|
||||
open = TRUE
|
||||
emag_act(null)
|
||||
|
||||
/obj/rev_malfunction()
|
||||
if(prob(20))
|
||||
if(prob(50))
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
emag_act(null)
|
||||
|
||||
/obj/machinery/clonepod/rev_malfunction()
|
||||
emag_act(null)
|
||||
|
||||
/obj/machinery/power/apc/rev_malfunction()
|
||||
return
|
||||
|
||||
/obj/machinery/power/smes/rev_malfunction()
|
||||
return
|
||||
|
||||
/mob/living/silicon/robot/rev_malfunction()
|
||||
playsound(src, 'sound/machines/warning-buzzer.ogg', 50, 1)
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
spark_system.start()
|
||||
emp_act(1)
|
||||
|
||||
/turf/defile()
|
||||
if(flags & NOJAUNT)
|
||||
flags &= ~NOJAUNT
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/turf/simulated/wall/defile()
|
||||
..()
|
||||
if(prob(15))
|
||||
new/obj/effect/temp_visual/revenant(loc)
|
||||
ChangeTurf(/turf/simulated/wall/rust)
|
||||
|
||||
/turf/simulated/wall/indestructible/defile()
|
||||
return
|
||||
|
||||
/turf/simulated/wall/r_wall/defile()
|
||||
..()
|
||||
if(prob(15))
|
||||
new/obj/effect/temp_visual/revenant(loc)
|
||||
ChangeTurf(/turf/simulated/wall/r_wall/rust)
|
||||
|
||||
/mob/living/carbon/human/defile()
|
||||
to_chat(src, "<span class='warning'>You suddenly feel [pick("sick and tired", "tired and confused", "nauseated", "dizzy")].</span>")
|
||||
adjustStaminaLoss(25)
|
||||
adjustToxLoss(5)
|
||||
AdjustConfused(20, bound_lower = 0, bound_upper = 30)
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/obj/structure/window/defile()
|
||||
take_damage(rand(30,80))
|
||||
if(fulltile)
|
||||
new /obj/effect/temp_visual/revenant/cracks(loc)
|
||||
|
||||
/obj/structure/closet/defile()
|
||||
open()
|
||||
|
||||
/turf/simulated/floor/defile()
|
||||
..()
|
||||
if(prob(15))
|
||||
if(intact && floor_tile)
|
||||
new floor_tile(src)
|
||||
broken = 0
|
||||
burnt = 0
|
||||
make_plating(1)
|
||||
|
||||
/turf/simulated/floor/plating/defile()
|
||||
if(flags & NOJAUNT)
|
||||
flags &= ~NOJAUNT
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/turf/simulated/floor/engine/cult/defile()
|
||||
if(flags & NOJAUNT)
|
||||
flags &= ~NOJAUNT
|
||||
new /obj/effect/temp_visual/revenant(loc)
|
||||
|
||||
/obj/machinery/light/defile()
|
||||
flicker(30)
|
||||
|
||||
|
||||
@@ -115,6 +115,12 @@
|
||||
speed = 0
|
||||
boost = world.time + 60
|
||||
|
||||
// Midround slaughter demon, less tanky
|
||||
|
||||
/mob/living/simple_animal/slaughter/lesser
|
||||
maxHealth = 130
|
||||
health = 130
|
||||
|
||||
// Cult slaughter demon
|
||||
/mob/living/simple_animal/slaughter/cult //Summoned as part of the cult objective "Bring the Slaughter"
|
||||
name = "harbinger of the slaughter"
|
||||
|
||||
@@ -205,6 +205,15 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
/datum/objective/protect/mindslave //subytpe for mindslave implants
|
||||
|
||||
/datum/objective/protect/mindslave/on_target_cryo()
|
||||
if(owner?.current)
|
||||
to_chat(owner.current, "<BR><span class='userdanger'>You notice that your master has entered cryogenic storage, and revert to your normal self, until they return again. You are no longer a mindslave!</span>")
|
||||
SEND_SOUND(owner.current, sound('sound/ambience/alarm4.ogg'))
|
||||
owner.remove_antag_datum(/datum/antagonist/mindslave)
|
||||
SSticker.mode.implanted.Remove(owner)
|
||||
log_admin("[key_name(owner.current)]'s mindslave master has cryo'd, and is no longer a mindslave.")
|
||||
message_admins("[key_name_admin(owner.current)]'s mindslave master has cryo'd, and is no longer a mindslave.") //Since they were on antag hud earlier, this feels important to log
|
||||
qdel(src)
|
||||
|
||||
/datum/objective/hijack
|
||||
martyr_compatible = 0 //Technically you won't get both anyway.
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
|
||||
var/list/possible_traitors = get_players_for_role(ROLE_TRAITOR)
|
||||
|
||||
for(var/datum/mind/candidate in possible_traitors)
|
||||
if(candidate.special_role == SPECIAL_ROLE_VAMPIRE) // no traitor vampires
|
||||
possible_traitors.Remove(candidate)
|
||||
|
||||
// stop setup if no possible traitors
|
||||
if(!possible_traitors.len)
|
||||
return 0
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
/datum/game_mode/traitor/vampire/announce()
|
||||
to_chat(world, "<B>The current game mode is - Traitor+Vampire!</B>")
|
||||
to_chat(world, "<B>There is a Vampire from Space Transylvania on the station along with some syndicate operatives out for their own gain! Do not let the vampire and the traitors succeed!</B>")
|
||||
to_chat(world, "<B>There are Bluespace Vampires infesting your fellow crew on the station along with some syndicate operatives out for their own gain! Do not let the vampires and the traitors succeed!</B>")
|
||||
|
||||
|
||||
/datum/game_mode/traitor/vampire/pre_setup()
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
//This is the gamemode file for the ported goon gamemode vampires.
|
||||
//They get a traitor objective and a blood sucking objective
|
||||
/datum/game_mode
|
||||
var/list/datum/mind/vampires = list()
|
||||
var/list/datum/mind/vampire_enthralled = list() //those controlled by a vampire
|
||||
var/list/vampire_thralls = list() //vammpires controlling somebody
|
||||
var/list/vampire_thralls = list() //vampires controlling somebody
|
||||
|
||||
/datum/game_mode/vampire
|
||||
name = "vampire"
|
||||
@@ -36,7 +34,7 @@
|
||||
|
||||
/datum/game_mode/vampire/announce()
|
||||
to_chat(world, "<B>The current game mode is - Vampires!</B>")
|
||||
to_chat(world, "<B>There are Vampires from Space Transylvania on the station, keep your blood close and neck safe!</B>")
|
||||
to_chat(world, "<B>There are Bluespace Vampires infesting your fellow crewmates, keep your blood close and neck safe!</B>")
|
||||
|
||||
/datum/game_mode/vampire/pre_setup()
|
||||
|
||||
@@ -84,8 +82,8 @@
|
||||
text += "died"
|
||||
else
|
||||
text += "survived"
|
||||
if(vampire.current.real_name != vampire.name)
|
||||
text += " as [vampire.current.real_name]"
|
||||
if(vampire.vampire.subclass)
|
||||
text += " as a [vampire.vampire.subclass.name]"
|
||||
else
|
||||
text += "body destroyed"
|
||||
text += ")"
|
||||
@@ -120,15 +118,15 @@
|
||||
/datum/game_mode/proc/auto_declare_completion_enthralled()
|
||||
if(vampire_enthralled.len)
|
||||
var/text = "<FONT size = 2><B>The Enthralled were:</B></FONT>"
|
||||
for(var/datum/mind/Mind in vampire_enthralled)
|
||||
text += "<br>[Mind.key] was [Mind.name] ("
|
||||
if(Mind.current)
|
||||
if(Mind.current.stat == DEAD)
|
||||
for(var/datum/mind/mind in vampire_enthralled)
|
||||
text += "<br>[mind.key] was [mind.name] ("
|
||||
if(mind.current)
|
||||
if(mind.current.stat == DEAD)
|
||||
text += "died"
|
||||
else
|
||||
text += "survived"
|
||||
if(Mind.current.real_name != Mind.name)
|
||||
text += " as [Mind.current.real_name]"
|
||||
if(mind.current.real_name != mind.name)
|
||||
text += " as [mind.current.real_name]"
|
||||
else
|
||||
text += "body destroyed"
|
||||
text += ")"
|
||||
@@ -168,9 +166,18 @@
|
||||
return
|
||||
|
||||
/datum/game_mode/proc/grant_vampire_powers(mob/living/carbon/vampire_mob)
|
||||
if(!istype(vampire_mob))
|
||||
if(!istype(vampire_mob) || !vampire_mob.mind)
|
||||
return
|
||||
vampire_mob.make_vampire()
|
||||
var/datum/vampire/vamp
|
||||
if(!vampire_mob.mind.vampire)
|
||||
vamp = new /datum/vampire()
|
||||
vamp.owner = vampire_mob
|
||||
vampire_mob.mind.vampire = vamp
|
||||
else
|
||||
vamp = vampire_mob.mind.vampire
|
||||
QDEL_LIST(vamp.powers)
|
||||
|
||||
vamp.check_vampire_upgrade(FALSE)
|
||||
|
||||
/datum/game_mode/proc/greet_vampire(datum/mind/vampire, you_are=1)
|
||||
var/dat
|
||||
@@ -178,7 +185,7 @@
|
||||
SEND_SOUND(vampire.current, sound('sound/ambience/antag/vampalert.ogg'))
|
||||
dat = "<span class='danger'>You are a Vampire!</span><br>"
|
||||
dat += {"To bite someone, target the head and use harm intent with an empty hand. Drink blood to gain new powers.
|
||||
You are weak to holy things and starlight. Don't go into space and avoid the Chaplain, the chapel and especially Holy Water."}
|
||||
You are weak to holy things, starlight and fire. Don't go into space and avoid the Chaplain, the chapel and especially Holy Water."}
|
||||
to_chat(vampire.current, dat)
|
||||
to_chat(vampire.current, "<B>You must complete the following tasks:</B>")
|
||||
|
||||
@@ -195,42 +202,51 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
obj_count++
|
||||
to_chat(vampire.current, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Vampire)</span>")
|
||||
return
|
||||
|
||||
/datum/vampire
|
||||
var/bloodtotal = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
|
||||
var/bloodusable = 0 // CHANGE TO ZERO WHEN PLAYTESTING HAPPENS
|
||||
var/bloodtotal = 0
|
||||
var/bloodusable = 0
|
||||
/// the mob tied to the vampire
|
||||
var/mob/living/owner = null
|
||||
var/gender = FEMALE
|
||||
var/iscloaking = 0 // handles the vampire cloak toggle
|
||||
var/list/powers = list() // list of available powers and passives
|
||||
var/mob/living/carbon/human/draining // who the vampire is draining of blood
|
||||
var/nullified = 0 //Nullrod makes them useless for a short while.
|
||||
var/list/upgrade_tiers = list(
|
||||
/obj/effect/proc_holder/spell/vampire/self/rejuvenate = 0,
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise = 0,
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare = 0,
|
||||
/datum/vampire_passive/vision = 100,
|
||||
/obj/effect/proc_holder/spell/vampire/self/shapeshift = 100,
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak = 150,
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/disease = 150,
|
||||
/obj/effect/proc_holder/spell/vampire/bats = 200,
|
||||
/obj/effect/proc_holder/spell/vampire/self/screech = 200,
|
||||
/datum/vampire_passive/regen = 200,
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep = 250,
|
||||
/obj/effect/proc_holder/spell/vampire/self/jaunt = 300,
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall = 300,
|
||||
/datum/vampire_passive/full = 500)
|
||||
/// what vampire subclass the vampire is.
|
||||
var/datum/vampire_subclass/subclass
|
||||
/// handles the vampire cloak toggle
|
||||
var/iscloaking = FALSE
|
||||
/// list of available powers and passives
|
||||
var/list/powers = list()
|
||||
/// who the vampire is draining of blood
|
||||
var/mob/living/carbon/human/draining
|
||||
/// Nullrods and holywater make their abilities cost more
|
||||
var/nullified = 0
|
||||
/// a list of powers that all vampires unlock and at what blood level they unlock them, the rest of their powers are found in the vampire_subclass datum
|
||||
var/list/upgrade_tiers = list(/obj/effect/proc_holder/spell/self/vampire/rejuvenate = 0,
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare = 0,
|
||||
/datum/vampire_passive/vision = 100,
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize = 150,
|
||||
/datum/vampire_passive/regen = 200,
|
||||
/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step = 250)
|
||||
|
||||
/// list of the peoples UIDs that we have drained, and how much blood from each one
|
||||
var/list/drained_humans = list()
|
||||
|
||||
/datum/vampire/Destroy(force, ...)
|
||||
owner = null
|
||||
draining = null
|
||||
QDEL_NULL(subclass)
|
||||
QDEL_LIST(powers)
|
||||
return ..()
|
||||
|
||||
/datum/vampire/proc/adjust_nullification(base, extra)
|
||||
// First hit should give full nullification, while subsequent hits increase the value slower
|
||||
nullified = max(nullified + extra, base)
|
||||
|
||||
/datum/vampire/New(gend = FEMALE)
|
||||
gender = gend
|
||||
nullified = clamp(nullified + extra, base, VAMPIRE_NULLIFICATION_CAP)
|
||||
|
||||
/datum/vampire/proc/force_add_ability(path)
|
||||
var/spell = new path(owner)
|
||||
if(istype(spell, /obj/effect/proc_holder/spell))
|
||||
owner.mind.AddSpell(spell)
|
||||
if(istype(spell, /datum/vampire_passive))
|
||||
var/datum/vampire_passive/passive = spell
|
||||
passive.owner = owner
|
||||
powers += spell
|
||||
owner.update_sight() // Life updates conditionally, so we need to update sight here in case the vamp gets new vision based on his powers. Maybe one day refactor to be more OOP and on the vampire's ability datum.
|
||||
|
||||
@@ -256,20 +272,6 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(current.mind && current.mind.vampire && current.mind.vampire.owner && (current.mind.vampire.owner != current))
|
||||
current.mind.vampire.owner = current
|
||||
|
||||
/mob/proc/make_vampire()
|
||||
if(!mind)
|
||||
return
|
||||
var/datum/vampire/vamp
|
||||
if(!mind.vampire)
|
||||
vamp = new /datum/vampire(gender)
|
||||
vamp.owner = src
|
||||
mind.vampire = vamp
|
||||
else
|
||||
vamp = mind.vampire
|
||||
vamp.powers.Cut()
|
||||
|
||||
vamp.check_vampire_upgrade(0)
|
||||
|
||||
/datum/vampire/proc/remove_vampire_powers()
|
||||
for(var/P in powers)
|
||||
remove_ability(P)
|
||||
@@ -278,12 +280,14 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(hud.vampire_blood_display)
|
||||
hud.remove_vampire_hud()
|
||||
owner.alpha = 255
|
||||
REMOVE_TRAITS_IN(owner, "vampire")
|
||||
|
||||
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H)
|
||||
#define BLOOD_GAINED_MODIFIER 0.5
|
||||
|
||||
/datum/vampire/proc/handle_bloodsucking(mob/living/carbon/human/H, suck_rate = 5 SECONDS)
|
||||
draining = H
|
||||
var/unique_suck_id = H.UID()
|
||||
var/blood = 0
|
||||
var/old_bloodtotal = 0 //used to see if we increased our blood total
|
||||
var/old_bloodusable = 0 //used to see if we increased our blood usable
|
||||
var/blood_volume_warning = 9999 //Blood volume threshold for warnings
|
||||
if(owner.is_muzzled())
|
||||
to_chat(owner, "<span class='warning'>[owner.wear_mask] prevents you from biting [H]!</span>")
|
||||
@@ -295,25 +299,24 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
H.LAssailant = null
|
||||
else
|
||||
H.LAssailant = owner
|
||||
while(do_mob(owner, H, 50))
|
||||
while(do_mob(owner, H, suck_rate))
|
||||
if(!(owner.mind in SSticker.mode.vampires))
|
||||
to_chat(owner, "<span class='userdanger'>Your fangs have disappeared!</span>")
|
||||
return
|
||||
old_bloodtotal = bloodtotal
|
||||
old_bloodusable = bloodusable
|
||||
owner.do_attack_animation(H, ATTACK_EFFECT_BITE)
|
||||
if(unique_suck_id in drained_humans)
|
||||
if(drained_humans[unique_suck_id] >= BLOOD_DRAIN_LIMIT)
|
||||
to_chat(owner, "<span class='warning'>You have drained most of the life force from [H]'s blood, and you will get no more useable blood from them!</span>")
|
||||
H.blood_volume = max(H.blood_volume - 25, 0)
|
||||
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + 5))
|
||||
continue
|
||||
|
||||
|
||||
if(H.stat < DEAD)
|
||||
if(H.ckey || H.player_ghosted) //Requires ckey regardless if monkey or humanoid, or the body has been ghosted before it died
|
||||
blood = min(20, H.blood_volume) // if they have less than 20 blood, give them the remnant else they get 20 blood
|
||||
bloodtotal += blood / 2 //divide by 2 to counted the double suction since removing cloneloss -Melandor0
|
||||
bloodusable += blood / 2
|
||||
else
|
||||
if(H.ckey || H.player_ghosted)
|
||||
blood = min(5, H.blood_volume) // The dead only give 5 blood
|
||||
bloodtotal += blood
|
||||
if(old_bloodtotal != bloodtotal)
|
||||
if(H.ckey || H.player_ghosted) // Requires ckey regardless if monkey or human, and has not ghosted, otherwise no power
|
||||
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].</b></span>")
|
||||
check_vampire_upgrade()
|
||||
blood = min(20, H.blood_volume)
|
||||
adjust_blood(H, blood * BLOOD_GAINED_MODIFIER)
|
||||
to_chat(owner, "<span class='notice'><b>You have accumulated [bloodtotal] unit\s of blood, and have [bloodusable] left to use.</b></span>")
|
||||
H.blood_volume = max(H.blood_volume - 25, 0)
|
||||
//Blood level warnings (Code 'borrowed' from Fulp)
|
||||
if(H.blood_volume)
|
||||
@@ -325,20 +328,18 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
else
|
||||
to_chat(owner, "<span class='warning'>You have bled your victim dry!</span>")
|
||||
break
|
||||
|
||||
if(ishuman(owner))
|
||||
var/mob/living/carbon/human/V = owner
|
||||
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
|
||||
to_chat(V, "<span class='notice'><b>Feeding on [H] reduces your thirst, but you get no usable blood from them.</b></span>")
|
||||
V.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, V.nutrition + 5))
|
||||
else
|
||||
V.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, V.nutrition + (blood / 2)))
|
||||
|
||||
if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive
|
||||
to_chat(owner, "<span class='notice'><b>Feeding on [H] reduces your thirst, but you get no usable blood from them.</b></span>")
|
||||
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + 5))
|
||||
else
|
||||
owner.set_nutrition(min(NUTRITION_LEVEL_WELL_FED, owner.nutrition + (blood / 2)))
|
||||
|
||||
draining = null
|
||||
to_chat(owner, "<span class='notice'>You stop draining [H.name] of blood.</span>")
|
||||
|
||||
/datum/vampire/proc/check_vampire_upgrade(announce = 1)
|
||||
#undef BLOOD_GAINED_MODIFIER
|
||||
|
||||
/datum/vampire/proc/check_vampire_upgrade(announce = TRUE)
|
||||
var/list/old_powers = powers.Copy()
|
||||
|
||||
for(var/ptype in upgrade_tiers)
|
||||
@@ -346,18 +347,30 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
if(bloodtotal >= level)
|
||||
add_ability(ptype)
|
||||
|
||||
if(!subclass)
|
||||
return
|
||||
subclass.add_subclass_ability(src)
|
||||
|
||||
check_full_power_upgrade()
|
||||
|
||||
if(announce)
|
||||
announce_new_power(old_powers)
|
||||
|
||||
|
||||
/datum/vampire/proc/check_full_power_upgrade()
|
||||
if(length(drained_humans) >= FULLPOWER_DRAINED_REQUIREMENT && bloodtotal >= FULLPOWER_BLOODTOTAL_REQUIREMENT)
|
||||
subclass.add_full_power_abilities(src)
|
||||
|
||||
|
||||
/datum/vampire/proc/announce_new_power(list/old_powers)
|
||||
for(var/p in powers)
|
||||
if(!(p in old_powers))
|
||||
if(istype(p, /obj/effect/proc_holder/spell/vampire))
|
||||
var/obj/effect/proc_holder/spell/vampire/power = p
|
||||
to_chat(owner, "<span class='notice'>[power.gain_desc]</span>")
|
||||
if(istype(p, /obj/effect/proc_holder/spell))
|
||||
var/obj/effect/proc_holder/spell/power = p
|
||||
to_chat(owner, "<span class='boldnotice'>[power.gain_desc]</span>")
|
||||
else if(istype(p, /datum/vampire_passive))
|
||||
var/datum/vampire_passive/power = p
|
||||
to_chat(owner, "<span class='notice'>[power.gain_desc]</span>")
|
||||
to_chat(owner, "<span class='boldnotice'>[power.gain_desc]</span>")
|
||||
|
||||
/datum/game_mode/proc/remove_vampire(datum/mind/vampire_mind)
|
||||
if(vampire_mind in vampires)
|
||||
@@ -414,6 +427,9 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
|
||||
var/turf/T = locate(round(ax, 0.5), round(ay, 0.5), owner.z)
|
||||
|
||||
if(!T)
|
||||
return
|
||||
|
||||
if(T.x == 1 || T.x == world.maxx || T.y == 1 || T.y == world.maxy)
|
||||
break
|
||||
|
||||
@@ -427,6 +443,8 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
to_chat(owner, "<span class='userdanger'>Your body is turning to ash, get out of the light now!</span>")
|
||||
owner.adjustCloneLoss(10) //I'm melting!
|
||||
vamp_burn(85)
|
||||
if(owner.cloneloss >= 100)
|
||||
owner.dust()
|
||||
|
||||
/datum/vampire/proc/handle_vampire()
|
||||
if(owner.hud_used)
|
||||
@@ -440,31 +458,49 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
hud.show_hud(hud.hud_version)
|
||||
hud.vampire_blood_display.maptext = "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'><font face='Small Fonts' color='#ce0202'>[bloodusable]</font></div>"
|
||||
handle_vampire_cloak()
|
||||
if(istype(owner.loc, /turf/space))
|
||||
if(istype(get_turf(owner), /turf/space))
|
||||
check_sun()
|
||||
if(istype(owner.loc.loc, /area/chapel) && !get_ability(/datum/vampire_passive/full))
|
||||
if(istype(get_area(owner), /area/chapel) && !get_ability(/datum/vampire_passive/full))
|
||||
vamp_burn(7)
|
||||
nullified = max(0, nullified - 1)
|
||||
nullified = max(0, nullified - 2)
|
||||
|
||||
/datum/vampire/proc/handle_vampire_cloak()
|
||||
if(!ishuman(owner))
|
||||
owner.alpha = 255
|
||||
return
|
||||
var/turf/simulated/T = get_turf(owner)
|
||||
var/light_available = T.get_lumcount(0.5) * 10
|
||||
var/light_available = T.get_lumcount() * 10
|
||||
|
||||
if(!istype(T))
|
||||
return 0
|
||||
return
|
||||
|
||||
if(!iscloaking)
|
||||
if(!iscloaking || owner.on_fire)
|
||||
owner.alpha = 255
|
||||
return 0
|
||||
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
|
||||
return
|
||||
|
||||
if(light_available <= 2)
|
||||
owner.alpha = round((255 * 0.15))
|
||||
return 1
|
||||
else
|
||||
owner.alpha = round((255 * 0.80))
|
||||
owner.alpha = 38 // round(255 * 0.15)
|
||||
ADD_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
|
||||
return
|
||||
|
||||
REMOVE_TRAIT(owner, TRAIT_GOTTAGONOTSOFAST, VAMPIRE_TRAIT)
|
||||
owner.alpha = 204 // 255 * 0.80
|
||||
|
||||
/datum/vampire/proc/adjust_blood(mob/living/carbon/C, blood_amount = 0)
|
||||
if(C)
|
||||
var/unique_suck_id = C.UID()
|
||||
if(!(unique_suck_id in drained_humans))
|
||||
drained_humans[unique_suck_id] = 0
|
||||
if(drained_humans[unique_suck_id] >= BLOOD_DRAIN_LIMIT)
|
||||
return
|
||||
drained_humans[unique_suck_id] += blood_amount
|
||||
bloodtotal += blood_amount
|
||||
bloodusable += blood_amount
|
||||
check_vampire_upgrade(TRUE)
|
||||
for(var/obj/effect/proc_holder/spell/S in powers)
|
||||
if(S.action)
|
||||
S.action.UpdateButtonIcon()
|
||||
|
||||
/datum/vampire/proc/vamp_burn(burn_chance)
|
||||
if(prob(burn_chance) && owner.health >= 50)
|
||||
@@ -491,3 +527,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
|
||||
static_inventory -= vampire_blood_display
|
||||
QDEL_NULL(vampire_blood_display)
|
||||
show_hud(hud_version)
|
||||
|
||||
/datum/vampire/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
check_vampire_upgrade(TRUE)
|
||||
|
||||
@@ -1,611 +0,0 @@
|
||||
//This should hold all the vampire related powers
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
clothes_req = 0
|
||||
range = 1
|
||||
charge_max = 1800
|
||||
action_background_icon_state = "bg_vampire"
|
||||
holy_area_cancast = FALSE //Stops cult magic from working on holy ground eg: chapel
|
||||
var/required_blood = 0
|
||||
var/gain_desc = null
|
||||
var/deduct_blood_on_cast = TRUE //Do we want to take the blood when this is cast, or at a later point?
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/New()
|
||||
..()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You have gained \the [src] ability."
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
|
||||
if(!user.mind)
|
||||
return 0
|
||||
if(!ishuman(user))
|
||||
to_chat(user, "<span class='warning'>You are in too weak of a form to do this!</span>")
|
||||
return 0
|
||||
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
|
||||
if(!vampire)
|
||||
return 0
|
||||
|
||||
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
|
||||
|
||||
if(user.stat >= DEAD)
|
||||
to_chat(user, "<span class='warning'>Not when you're dead!</span>")
|
||||
return 0
|
||||
|
||||
if(vampire.nullified && !fullpower)
|
||||
to_chat(user, "<span class='warning'>Something is blocking your powers!</span>")
|
||||
return 0
|
||||
if(vampire.bloodusable < required_blood)
|
||||
to_chat(user, "<span class='warning'>You require at least [required_blood] units of usable blood to do that!</span>")
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
|
||||
if(!user.mind)
|
||||
return 0
|
||||
if(!ishuman(user))
|
||||
return 0
|
||||
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
|
||||
if(!vampire)
|
||||
return 0
|
||||
|
||||
var/fullpower = vampire.get_ability(/datum/vampire_passive/full)
|
||||
|
||||
if(user.stat >= DEAD)
|
||||
return 0
|
||||
|
||||
if(vampire.nullified && !fullpower)
|
||||
return 0
|
||||
if(vampire.bloodusable < required_blood)
|
||||
return 0
|
||||
if(istype(loc.loc, /area/chapel) && !fullpower)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/proc/affects(mob/target, mob/user = usr)
|
||||
//Other vampires aren't affected
|
||||
if(target.mind && target.mind.vampire)
|
||||
return 0
|
||||
//Vampires who have reached their full potential can affect nearly everything
|
||||
if(user.mind.vampire.get_ability(/datum/vampire_passive/full))
|
||||
return 1
|
||||
//Holy characters are resistant to vampire powers
|
||||
if(target.mind && target.mind.isholy)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/proc/can_reach(mob/M as mob)
|
||||
if(M.loc == usr.loc)
|
||||
return 1 //target and source are in the same thing
|
||||
return M in oview_or_orange(range, usr, selection_type)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/before_cast(list/targets)
|
||||
// sanity check before we cast
|
||||
if(!usr.mind || !usr.mind.vampire)
|
||||
targets.Cut()
|
||||
return
|
||||
|
||||
if(!required_blood)
|
||||
return
|
||||
|
||||
// enforce blood
|
||||
var/datum/vampire/vampire = usr.mind.vampire
|
||||
|
||||
if(required_blood <= vampire.bloodusable)
|
||||
if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
|
||||
return
|
||||
vampire.bloodusable -= required_blood
|
||||
else
|
||||
// stop!!
|
||||
targets.Cut()
|
||||
|
||||
if(targets.len)
|
||||
to_chat(usr, "<span class='notice'><b>You have [vampire.bloodusable] left to use.</b></span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/choose_targets(mob/user = usr)
|
||||
var/list/possible_targets[0]
|
||||
for(var/mob/living/carbon/C in oview_or_orange(range, user, selection_type))
|
||||
possible_targets += C
|
||||
var/mob/living/carbon/T = input(user, "Choose your victim.", name) as null|mob in possible_targets
|
||||
|
||||
if(!T || !can_reach(T))
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(list(T), user = user)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/choose_targets(mob/user = usr)
|
||||
perform(list(user))
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/choose_targets(mob/user = usr)
|
||||
var/list/targets[0]
|
||||
for(var/mob/living/carbon/C in oview_or_orange(range, user, selection_type))
|
||||
targets += C
|
||||
|
||||
if(!targets.len)
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(targets, user = user)
|
||||
|
||||
/datum/vampire_passive
|
||||
var/gain_desc
|
||||
|
||||
/datum/vampire_passive/New()
|
||||
..()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You have gained \the [src] ability."
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/rejuvenate
|
||||
name = "Rejuvenate"
|
||||
desc= "Use reserve blood to enliven your body, removing any incapacitating effects."
|
||||
action_icon_state = "vampire_rejuvinate"
|
||||
charge_max = 200
|
||||
stat_allowed = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast(list/targets, mob/user = usr)
|
||||
var/mob/living/U = user
|
||||
|
||||
user.SetWeakened(0)
|
||||
user.SetStunned(0)
|
||||
user.SetParalysis(0)
|
||||
user.SetSleeping(0)
|
||||
U.adjustStaminaLoss(-75)
|
||||
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
|
||||
spawn(1)
|
||||
if(usr.mind.vampire.get_ability(/datum/vampire_passive/regen))
|
||||
for(var/i = 1 to 5)
|
||||
U.adjustBruteLoss(-2)
|
||||
U.adjustOxyLoss(-5)
|
||||
U.adjustToxLoss(-2)
|
||||
U.adjustFireLoss(-2)
|
||||
sleep(35)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise
|
||||
name = "Hypnotise (20)"
|
||||
desc= "A piercing stare that incapacitates your victim for a good length of time."
|
||||
action_icon_state = "vampire_hypnotise"
|
||||
required_blood = 20
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/hypnotise/cast(list/targets, mob/user = usr)
|
||||
for(var/mob/living/target in targets)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes flash briefly as [user.p_they()] stare[user.p_s()] into [target]'s eyes</span>")
|
||||
if(do_mob(user, target, 50))
|
||||
if(!affects(target))
|
||||
to_chat(user, "<span class='warning'>Your piercing gaze fails to knock out [target].</span>")
|
||||
to_chat(target, "<span class='notice'>[user]'s feeble gaze is ineffective.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Your piercing gaze knocks out [target].</span>")
|
||||
to_chat(target, "<span class='warning'>You find yourself unable to move and barely able to speak.</span>")
|
||||
target.Weaken(10)
|
||||
target.Stun(10)
|
||||
target.stuttering = 10
|
||||
else
|
||||
revert_cast(usr)
|
||||
to_chat(usr, "<span class='warning'>You broke your gaze.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/disease
|
||||
name = "Diseased Touch (100)"
|
||||
desc = "Touches your victim with infected blood giving them Grave Fever, which will, left untreated, causes toxic building and frequent collapsing."
|
||||
gain_desc = "You have gained the Diseased Touch ability which causes those you touch to become weak unless treated medically."
|
||||
action_icon_state = "vampire_disease"
|
||||
required_blood = 100
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/disease/cast(list/targets, mob/user = usr)
|
||||
for(var/mob/living/carbon/target in targets)
|
||||
to_chat(user, "<span class='warning'>You stealthily infect [target] with your diseased touch.</span>")
|
||||
target.help_shake_act(user)
|
||||
if(!affects(target))
|
||||
to_chat(user, "<span class='warning'>They seem to be unaffected.</span>")
|
||||
continue
|
||||
var/datum/disease/D = new /datum/disease/vampire
|
||||
target.ForceContractDisease(D)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare
|
||||
name = "Glare"
|
||||
desc = "A scary glare that incapacitates people for a short while around you."
|
||||
action_icon_state = "vampire_glare"
|
||||
charge_max = 300
|
||||
stat_allowed = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/mob_aoe/glare/cast(list/targets, mob/user = usr)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes emit a blinding flash!</span>")
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
|
||||
var/obj/item/clothing/glasses/sunglasses/blindfold/B = H.glasses
|
||||
if(B.tint)
|
||||
to_chat(user, "<span class='warning'>You're blindfolded!</span>")
|
||||
return
|
||||
for(var/mob/living/target in targets)
|
||||
if(!affects(target))
|
||||
continue
|
||||
target.Stun(5)
|
||||
target.Weaken(5)
|
||||
target.stuttering = 20
|
||||
to_chat(target, "<span class='warning'>You are blinded by [user]'s glare.</span>")
|
||||
add_attack_logs(user, target, "(Vampire) Glared at")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/shapeshift
|
||||
name = "Shapeshift (50)"
|
||||
desc = "Changes your name and appearance at the cost of 50 blood and has a cooldown of 3 minutes."
|
||||
gain_desc = "You have gained the shapeshifting ability, at the cost of stored blood you can change your form permanently."
|
||||
action_icon_state = "genetic_poly"
|
||||
required_blood = 50
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/shapeshift/cast(list/targets, mob/user = usr)
|
||||
user.visible_message("<span class='warning'>[user] transforms!</span>")
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
scramble(1, H, 100)
|
||||
H.real_name = random_name(H.gender, H.dna.species.name) //Give them a name that makes sense for their species.
|
||||
H.sync_organ_dna(assimilate = 1)
|
||||
H.update_body()
|
||||
H.reset_hair() //No more winding up with hairstyles you're not supposed to have, and blowing your cover.
|
||||
H.reset_markings() //...Or markings.
|
||||
H.dna.ResetUIFrom(H)
|
||||
H.flavor_text = ""
|
||||
user.update_icons()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/screech
|
||||
name = "Chiropteran Screech (30)"
|
||||
desc = "An extremely loud shriek that stuns nearby humans and breaks windows as well."
|
||||
gain_desc = "You have gained the Chiropteran Screech ability which stuns anything with ears in a large radius and shatters glass in the process."
|
||||
action_icon_state = "vampire_screech"
|
||||
required_blood = 30
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/screech/cast(list/targets, mob/user = usr)
|
||||
user.visible_message("<span class='warning'>[user] lets out an ear piercing shriek!</span>", "<span class='warning'>You let out a loud shriek.</span>", "<span class='warning'>You hear a loud painful shriek!</span>")
|
||||
for(var/mob/living/carbon/C in hearers(4))
|
||||
if(C == user)
|
||||
continue
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL)
|
||||
continue
|
||||
if(!affects(C))
|
||||
continue
|
||||
to_chat(C, "<span class='warning'><font size='3'><b>You hear a ear piercing shriek and your senses dull!</font></b></span>")
|
||||
C.Weaken(4)
|
||||
C.AdjustEarDamage(0, 20)
|
||||
C.Stuttering(20)
|
||||
C.Stun(4)
|
||||
C.Jitter(150)
|
||||
for(var/obj/structure/window/W in view(4))
|
||||
W.deconstruct(FALSE)
|
||||
playsound(user.loc, 'sound/effects/creepyshriek.ogg', 100, 1)
|
||||
|
||||
|
||||
/proc/isvampirethrall(mob/living/M as mob)
|
||||
return istype(M) && M.mind && SSticker && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall
|
||||
name = "Enthrall (300)"
|
||||
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
|
||||
gain_desc = "You have gained the Enthrall ability which at a heavy blood cost allows you to enslave a human that is not loyal to any other for a random period of time."
|
||||
action_icon_state = "vampire_enthrall"
|
||||
required_blood = 300
|
||||
deduct_blood_on_cast = FALSE
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
for(var/mob/living/target in targets)
|
||||
user.visible_message("<span class='warning'>[user] bites [target]'s neck!</span>", "<span class='warning'>You bite [target]'s neck and begin the flow of power.</span>")
|
||||
to_chat(target, "<span class='warning'>You feel the tendrils of evil invade your mind.</span>")
|
||||
if(!ishuman(target))
|
||||
to_chat(user, "<span class='warning'>You can only enthrall humans.</span>")
|
||||
break
|
||||
if(do_mob(user, target, 50))
|
||||
if(can_enthrall(user, target))
|
||||
handle_enthrall(user, target)
|
||||
vampire.bloodusable -= required_blood //we take the blood after enthralling, not before
|
||||
else
|
||||
revert_cast(user)
|
||||
to_chat(user, "<span class='warning'>You or your target either moved or you dont have enough usable blood.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
|
||||
var/enthrall_safe = 0
|
||||
for(var/obj/item/implant/mindshield/L in C)
|
||||
if(L && L.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
for(var/obj/item/implant/traitor/T in C)
|
||||
if(T && T.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
if(!C)
|
||||
log_runtime(EXCEPTION("something bad happened on enthralling a mob, attacker is [user] [user.key] \ref[user]"), user)
|
||||
return 0
|
||||
if(!C.mind)
|
||||
to_chat(user, "<span class='warning'>[C.name]'s mind is not there for you to enthrall.</span>")
|
||||
return 0
|
||||
if(enthrall_safe || ( C.mind in SSticker.mode.vampires )||( C.mind.vampire )||( C.mind in SSticker.mode.vampire_enthralled ))
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You feel a familiar sensation in your skull that quickly dissipates.</span>")
|
||||
return 0
|
||||
if(!affects(C))
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>Your faith of [SSticker.Bible_deity_name] has kept your mind clear of all evil.</span>")
|
||||
return 0
|
||||
if(!ishuman(C))
|
||||
to_chat(user, "<span class='warning'>You can only enthrall humans!</span>")
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H as mob)
|
||||
if(!istype(H))
|
||||
return 0
|
||||
var/ref = "\ref[user.mind]"
|
||||
if(!(ref in SSticker.mode.vampire_thralls))
|
||||
SSticker.mode.vampire_thralls[ref] = list(H.mind)
|
||||
else
|
||||
SSticker.mode.vampire_thralls[ref] += H.mind
|
||||
|
||||
SSticker.mode.update_vampire_icons_added(H.mind)
|
||||
SSticker.mode.update_vampire_icons_added(user.mind)
|
||||
var/datum/mindslaves/slaved = user.mind.som
|
||||
H.mind.som = slaved
|
||||
slaved.serv += H
|
||||
slaved.add_serv_hud(user.mind, "vampire")//handles master servent icons
|
||||
slaved.add_serv_hud(H.mind, "vampthrall")
|
||||
|
||||
SSticker.mode.vampire_enthralled.Add(H.mind)
|
||||
SSticker.mode.vampire_enthralled[H.mind] = user.mind
|
||||
H.mind.special_role = SPECIAL_ROLE_VAMPIRE_THRALL
|
||||
|
||||
var/datum/objective/protect/serve_objective = new
|
||||
serve_objective.owner = user.mind
|
||||
serve_objective.target = H.mind
|
||||
serve_objective.explanation_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
|
||||
H.mind.objectives += serve_objective
|
||||
|
||||
to_chat(H, "<span class='biggerdanger'>You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.</span>")
|
||||
to_chat(user, "<span class='warning'>You have successfully Enthralled [H]. <i>If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.</i></span>")
|
||||
H.Stun(2)
|
||||
add_attack_logs(user, H, "Vampire-thralled")
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak
|
||||
name = "Cloak of Darkness"
|
||||
desc = "Toggles whether you are currently cloaking yourself in darkness."
|
||||
gain_desc = "You have gained the Cloak of Darkness ability which when toggled makes you near invisible in the shroud of darkness."
|
||||
action_icon_state = "vampire_cloak"
|
||||
charge_max = 10
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak/New()
|
||||
..()
|
||||
update_name()
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak/proc/update_name()
|
||||
var/mob/living/user = loc
|
||||
if(!ishuman(user) || !user.mind || !user.mind.vampire)
|
||||
return
|
||||
name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/V = user.mind.vampire
|
||||
V.iscloaking = !V.iscloaking
|
||||
update_name()
|
||||
to_chat(user, "<span class='notice'>You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/bats
|
||||
name = "Summon Bats (75)"
|
||||
desc = "You summon a pair of space bats who attack nearby targets until they or their target is dead."
|
||||
gain_desc = "You have gained the Summon Bats ability."
|
||||
action_icon_state = "vampire_bats"
|
||||
charge_max = 1200
|
||||
required_blood = 75
|
||||
var/num_bats = 2
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/bats/choose_targets(mob/user = usr)
|
||||
var/list/turf/locs = new
|
||||
for(var/direction in GLOB.alldirs) //looking for bat spawns
|
||||
if(locs.len == num_bats) //we found 2 locations and thats all we need
|
||||
break
|
||||
var/turf/T = get_step(usr, direction) //getting a loc in that direction
|
||||
if(AStar(user, T, /turf/proc/Distance, 1, simulated_only = 0)) // if a path exists, so no dense objects in the way its valid salid
|
||||
locs += T
|
||||
|
||||
// pad with player location
|
||||
for(var/i = locs.len + 1 to num_bats)
|
||||
locs += user.loc
|
||||
|
||||
perform(locs, user = user)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/bats/cast(list/targets, mob/user = usr)
|
||||
for(var/T in targets)
|
||||
new /mob/living/simple_animal/hostile/scarybat(T, user)
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/jaunt
|
||||
name = "Mist Form (30)"
|
||||
desc = "You take on the form of mist for a short period of time."
|
||||
gain_desc = "You have gained the Mist Form ability which allows you to take on the form of mist for a short period and pass over any obstacle in your path."
|
||||
action_icon_state = "mist"
|
||||
charge_max = 600
|
||||
required_blood = 30
|
||||
centcom_cancast = 0
|
||||
var/jaunt_duration = 50 //in deciseconds
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/self/jaunt/cast(list/targets, mob/user = usr)
|
||||
spawn(0)
|
||||
var/mob/living/U = user
|
||||
var/originalloc = get_turf(user.loc)
|
||||
var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt(originalloc)
|
||||
var/atom/movable/overlay/animation = new /atom/movable/overlay(originalloc)
|
||||
animation.name = "blood"
|
||||
animation.density = 0
|
||||
animation.anchored = 1
|
||||
animation.icon = 'icons/mob/mob.dmi'
|
||||
animation.icon_state = "empty"
|
||||
animation.layer = 5
|
||||
animation.master = holder
|
||||
U.ExtinguishMob()
|
||||
flick("mist", animation)
|
||||
user.forceMove(holder)
|
||||
user.client.eye = holder
|
||||
sleep(jaunt_duration)
|
||||
var/mobloc = get_turf(user.loc)
|
||||
animation.loc = mobloc
|
||||
user.canmove = 0
|
||||
sleep(20)
|
||||
flick("mist_reappear", animation)
|
||||
sleep(5)
|
||||
if(!user.Move(mobloc))
|
||||
for(var/turf/T in orange(7, mobloc))
|
||||
if(T)
|
||||
if(user.Move(T))
|
||||
break
|
||||
user.canmove = 1
|
||||
user.client.eye = user
|
||||
qdel(animation)
|
||||
qdel(holder)
|
||||
|
||||
// Blink for vamps
|
||||
// Less smoke spam.
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep
|
||||
name = "Shadowstep (30)"
|
||||
desc = "Vanish into the shadows."
|
||||
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
|
||||
action_icon_state = "shadowblink"
|
||||
charge_max = 20
|
||||
required_blood = 30
|
||||
centcom_cancast = 0
|
||||
|
||||
// Teleport radii
|
||||
var/inner_tele_radius = 0
|
||||
var/outer_tele_radius = 6
|
||||
// Maximum lighting_lumcount.
|
||||
var/max_lum = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep/choose_targets(mob/user = usr)
|
||||
var/list/turfs = new/list()
|
||||
for(var/turf/T in range(user, outer_tele_radius))
|
||||
if(T in range(user, inner_tele_radius))
|
||||
continue
|
||||
if(istype(T, /turf/space))
|
||||
continue
|
||||
if(T.density)
|
||||
continue
|
||||
if(T.x > world.maxx-outer_tele_radius || T.x < outer_tele_radius)
|
||||
continue //putting them at the edge is dumb
|
||||
if(T.y > world.maxy-outer_tele_radius || T.y < outer_tele_radius)
|
||||
continue
|
||||
|
||||
var/lightingcount = T.get_lumcount(0.5) * 10
|
||||
|
||||
// LIGHTING CHECK
|
||||
if(lightingcount > max_lum)
|
||||
continue
|
||||
turfs += T
|
||||
|
||||
if(!turfs.len)
|
||||
revert_cast(user)
|
||||
to_chat(user, "<span class='warning'>You cannot find darkness to step to.</span>")
|
||||
return
|
||||
|
||||
turfs = list(pick(turfs)) // Pick a single turf for the vampire to jump to.
|
||||
perform(turfs, user = user)
|
||||
|
||||
// `targets` should only ever contain the 1 valid turf we're jumping to, even though its a list, that's just how the cast() proc works.
|
||||
/obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr)
|
||||
spawn(0)
|
||||
if(!LAZYLEN(targets)) // If for some reason the turf got deleted.
|
||||
return
|
||||
var/mob/living/U = user
|
||||
U.ExtinguishMob()
|
||||
var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(user))
|
||||
animation.name = user.name
|
||||
animation.density = 0
|
||||
animation.anchored = 1
|
||||
animation.icon = user.icon
|
||||
animation.alpha = 127
|
||||
animation.layer = 5
|
||||
//animation.master = src
|
||||
user.forceMove(targets[1])
|
||||
spawn(10)
|
||||
qdel(animation)
|
||||
|
||||
/datum/vampire_passive/regen
|
||||
gain_desc = "Your rejuvination abilities have improved and will now heal you over time when used."
|
||||
|
||||
/datum/vampire_passive/vision
|
||||
gain_desc = "Your vampiric vision has improved."
|
||||
|
||||
/datum/vampire_passive/full
|
||||
gain_desc = "You have reached your full potential and are no longer weak to the effects of anything holy and your vision has been improved greatly."
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires
|
||||
name = "Raise Vampires"
|
||||
desc = "Summons deadly vampires from bluespace."
|
||||
school = "transmutation"
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
invocation = "none"
|
||||
invocation_type = "none"
|
||||
max_targets = 0
|
||||
range = 3
|
||||
cooldown_min = 20
|
||||
action_icon_state = "revive_thrall"
|
||||
sound = 'sound/magic/wandodeath.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
|
||||
new /obj/effect/temp_visual/cult/sparks(user.loc)
|
||||
var/turf/T = get_turf(user)
|
||||
to_chat(user, "<span class='warning'>You call out within bluespace, summoning more vampiric spirits to aid you!</span>")
|
||||
for(var/mob/living/carbon/human/H in targets)
|
||||
T.Beam(H, "sendbeam", 'icons/effects/effects.dmi', time=30, maxdistance=7, beam_type=/obj/effect/ebeam)
|
||||
new /obj/effect/temp_visual/cult/sparks(H.loc)
|
||||
H.raise_vampire(user)
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/raise_vampire(mob/M)
|
||||
if(!istype(M))
|
||||
log_debug("human/proc/raise_vampire called with invalid argument.")
|
||||
return
|
||||
if(!mind)
|
||||
visible_message("[src] looks to be too stupid to understand what is going on.")
|
||||
return
|
||||
if(dna && (NO_BLOOD in dna.species.species_traits) || dna.species.exotic_blood || !blood_volume)
|
||||
visible_message("[src] looks unfazed!")
|
||||
return
|
||||
if(mind.vampire || mind.special_role == SPECIAL_ROLE_VAMPIRE || mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
|
||||
visible_message("<span class='notice'>[src] looks refreshed!</span>")
|
||||
adjustBruteLoss(-60)
|
||||
adjustFireLoss(-60)
|
||||
for(var/obj/item/organ/external/E in bodyparts)
|
||||
if(prob(25))
|
||||
E.mend_fracture()
|
||||
|
||||
return
|
||||
if(stat != DEAD)
|
||||
if(IsWeakened())
|
||||
visible_message("<span class='warning'>[src] looks to be in pain!</span>")
|
||||
adjustBrainLoss(60)
|
||||
else
|
||||
visible_message("<span class='warning'>[src] looks to be stunned by the energy!</span>")
|
||||
Weaken(20)
|
||||
return
|
||||
for(var/obj/item/implant/mindshield/L in src)
|
||||
if(L && L.implanted)
|
||||
qdel(L)
|
||||
for(var/obj/item/implant/traitor/T in src)
|
||||
if(T && T.implanted)
|
||||
qdel(T)
|
||||
visible_message("<span class='warning'>[src] gets an eerie red glow in their eyes!</span>")
|
||||
var/datum/objective/protect/protect_objective = new
|
||||
protect_objective.owner = mind
|
||||
protect_objective.target = M.mind
|
||||
protect_objective.explanation_text = "Protect [M.real_name]."
|
||||
mind.objectives += protect_objective
|
||||
add_attack_logs(M, src, "Vampire-sired")
|
||||
mind.make_Vampire()
|
||||
revive()
|
||||
Weaken(20)
|
||||
@@ -0,0 +1,79 @@
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_swell
|
||||
name = "Blood Swell (30)"
|
||||
desc = "You infuse your body with blood, making you highly resistant to stuns and physical damage. However, this makes you unable to fire ranged weapons while it is active."
|
||||
gain_desc = "You have gained the ability to temporarly resist large amounts of stuns and physical damage."
|
||||
charge_max = 40 SECONDS
|
||||
required_blood = 30
|
||||
action_icon_state = "blood_swell"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_swell/cast(list/targets, mob/user)
|
||||
var/mob/living/target = targets[1]
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
H.apply_status_effect(STATUS_EFFECT_BLOOD_SWELL)
|
||||
|
||||
/datum/vampire_passive/blood_swell_upgrade
|
||||
gain_desc = "While blood swell is active all of your melee attacks deal increased damage."
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force
|
||||
name = "Overwhelming Force"
|
||||
desc = "When toggled you will automatically pry open doors that you bump into if you do not have access."
|
||||
gain_desc = "You have gained the ability to force open doors at a small blood cost."
|
||||
charge_max = 2 SECONDS
|
||||
action_icon_state = "OH_YEAAAAH"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force/cast(list/targets, mob/user)
|
||||
if(!HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
|
||||
to_chat(user, "<span class='warning'>You feel MIGHTY!</span>")
|
||||
ADD_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
|
||||
user.status_flags &= ~CANPUSH
|
||||
user.move_resist = MOVE_FORCE_STRONG
|
||||
else
|
||||
REMOVE_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
|
||||
user.move_resist = MOVE_FORCE_DEFAULT
|
||||
user.status_flags |= CANPUSH
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush
|
||||
name = "Blood Rush (30)"
|
||||
desc = "Infuse yourself with blood magic to boost your movement speed."
|
||||
gain_desc = "You have gained the ability to temporarily move at high speeds."
|
||||
charge_max = 30 SECONDS
|
||||
required_blood = 30
|
||||
action_icon_state = "blood_rush"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush/cast(list/targets, mob/user)
|
||||
var/mob/living/target = targets[1]
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/H = target
|
||||
to_chat(H, "<span class='notice'>You feel a rush of energy!</span>")
|
||||
H.apply_status_effect(STATUS_EFFECT_BLOOD_RUSH)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge
|
||||
name = "Charge (30)"
|
||||
desc = "You charge at wherever you click on screen, dealing large amounts of damage, stunning and destroying walls and other objects."
|
||||
gain_desc = "You can now charge at a target on screen, dealing massive damage and destroying structures."
|
||||
required_blood = 30
|
||||
charge_max = 30 SECONDS
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "vampire_charge"
|
||||
allowed_type = /atom
|
||||
range = 7
|
||||
auto_target_single = FALSE
|
||||
click_radius = -1
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge/can_cast(mob/user, charge_check, show_message)
|
||||
var/mob/living/L = user
|
||||
if(L.IsWeakened() || L.resting)
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge/cast(list/targets, mob/user)
|
||||
var/target = targets[1]
|
||||
if(isliving(user))
|
||||
var/mob/living/L = user
|
||||
L.apply_status_effect(STATUS_EFFECT_CHARGING)
|
||||
L.throw_at(target, range, 1, L, FALSE, callback = CALLBACK(L, /mob/living/.proc/remove_status_effect, STATUS_EFFECT_CHARGING))
|
||||
@@ -0,0 +1,243 @@
|
||||
/obj/effect/proc_holder/spell/self/vampire/vamp_claws
|
||||
name = "Vampiric Claws (30)"
|
||||
desc = "You channel blood magics to forge deadly vampiric claws that leech blood and strike rapidly. Cannot be used if you are holding something that cannot be dropped."
|
||||
gain_desc = "You have gained the ability to forge your hands into vampiric claws."
|
||||
charge_max = 30 SECONDS
|
||||
required_blood = 30
|
||||
action_icon_state = "vampire_claws"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/vamp_claws/cast(mob/user)
|
||||
if(user.l_hand || user.r_hand)
|
||||
to_chat(user, "<span class='notice'>You drop what was in your hands as large blades spring from your fingers!</span>")
|
||||
user.drop_l_hand()
|
||||
user.drop_r_hand()
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Large blades of blood spring from your fingers!</span>")
|
||||
var/obj/item/twohanded/required/vamp_claws/claws = new /obj/item/twohanded/required/vamp_claws(user.loc)
|
||||
user.put_in_hands(claws)
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/vamp_claws/can_cast(mob/user, charge_check, show_message)
|
||||
var/mob/living/L = user
|
||||
if(L.canUnEquip(L.l_hand) && L.canUnEquip(L.r_hand))
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws
|
||||
name = "vampiric claws"
|
||||
desc = "A pair of eldritch claws made of living blood, they seem to flow yet they are solid"
|
||||
icon = 'icons/effects/vampire_effects.dmi'
|
||||
icon_state = "vamp_claws"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
flags = ABSTRACT | NODROP | DROPDEL
|
||||
force = 10
|
||||
force_wielded = 10
|
||||
armour_penetration = 20
|
||||
block_chance = 50
|
||||
sharp = TRUE
|
||||
attack_effect_override = ATTACK_EFFECT_CLAW
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "savaged", "clawed")
|
||||
sprite_sheets_inhand = list("Vox" = 'icons/mob/clothing/species/vox/held.dmi', "Drask" = 'icons/mob/clothing/species/drask/held.dmi')
|
||||
var/durability = 20
|
||||
var/blood_drain_amount = 15
|
||||
var/blood_absorbed_amount = 5
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/afterattack(atom/target, mob/user, proximity)
|
||||
if(!user.mind?.vampire)
|
||||
return
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/C = target
|
||||
if(C.ckey && C.stat != DEAD && C.affects_vampire() && !(NO_BLOOD in C.dna.species.species_traits))
|
||||
C.bleed(blood_drain_amount)
|
||||
user.mind.vampire.adjust_blood(C, blood_absorbed_amount)
|
||||
durability -= 1
|
||||
if(durability <= 0)
|
||||
qdel(src)
|
||||
to_chat(user, "<span class='warning'>Your claws shatter!</span>")
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/process()
|
||||
durability -= 1
|
||||
if(durability <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text, final_block_chance, damage, attack_type)
|
||||
if(attack_type == PROJECTILE_ATTACK)
|
||||
final_block_chance = 0
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/melee_attack_chain(mob/user, atom/target, params)
|
||||
..()
|
||||
if(wielded)
|
||||
user.changeNext_move(CLICK_CD_MELEE * 0.5)
|
||||
|
||||
/obj/item/twohanded/required/vamp_claws/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You dispel your claws!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils
|
||||
name = "Blood Tendrils (10)"
|
||||
desc = "You summon blood tendrils from bluespace after a delay to ensnare people in an area, slowing them down."
|
||||
gain_desc = "You have gained the ability to summon blood tendrils to slow people down in an area that you target."
|
||||
required_blood = 10
|
||||
|
||||
vampire_ability = TRUE
|
||||
click_radius = 1
|
||||
charge_max = 30 SECONDS
|
||||
allowed_type = /atom
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "blood_tendrils"
|
||||
sound = 'sound/misc/enter_blood.ogg'
|
||||
var/area_of_affect = 1
|
||||
|
||||
selection_activated_message = "<span class='notice'>You channel blood magics to weaken the bluespace veil. <B>Left-click to cast at a target area!</B></span>"
|
||||
selection_deactivated_message = "<span class='notice'>Your magics subside.</span>"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/cast(list/targets, mob/user)
|
||||
var/turf/T = get_turf(targets[1]) // there should only ever be one entry in targets for this spell
|
||||
|
||||
for(var/turf/simulated/blood_turf in view(area_of_affect, T))
|
||||
if(blood_turf.density)
|
||||
continue
|
||||
new /obj/effect/temp_visual/blood_tendril(blood_turf)
|
||||
|
||||
addtimer(CALLBACK(src, .proc/apply_slowdown, T, area_of_affect, 3, user), 0.5 SECONDS)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils/proc/apply_slowdown(turf/T, distance, slowed_amount, mob/user)
|
||||
for(var/mob/living/L in view(distance, T))
|
||||
if(L.affects_vampire(user))
|
||||
L.AdjustSlowed(slowed_amount)
|
||||
L.visible_message("<span class='warning'>[L] gets ensared in blood tendrils, restricting [L.p_their()] movement!</span>")
|
||||
new /obj/effect/temp_visual/blood_tendril/long(get_turf(L))
|
||||
|
||||
/obj/effect/temp_visual/blood_tendril
|
||||
icon = 'icons/effects/vampire_effects.dmi'
|
||||
icon_state = "blood_tendril"
|
||||
duration = 1 SECONDS
|
||||
|
||||
/obj/effect/temp_visual/blood_tendril/long
|
||||
duration = 2 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool
|
||||
name = "Sanguine Pool (50)"
|
||||
desc = "You shift your form into a pool of blood, making you invulnerable and able to move through anything that's not a wall or space. You leave a trail of blood behind you when you do this."
|
||||
gain_desc = "You have gained the ability to shift into a pool of blood, allowing you to evade pursuers with great mobility."
|
||||
vampire_ability = TRUE
|
||||
required_blood = 50
|
||||
jaunt_duration = 3 SECONDS
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "blood_pool"
|
||||
jaunt_type_path = /obj/effect/dummy/spell_jaunt/blood_pool
|
||||
jaunt_water_effect = FALSE
|
||||
jaunt_out_type = /obj/effect/temp_visual/dir_setting/cult/phase/out
|
||||
jaunt_in_type = /obj/effect/temp_visual/dir_setting/cult/phase
|
||||
jaunt_in_time = 0
|
||||
sound1 = 'sound/misc/enter_blood.ogg'
|
||||
|
||||
/obj/effect/proc_holder/spell/blood_eruption
|
||||
name = "Blood Eruption (100)"
|
||||
desc = "Every pool of blood in 4 tiles erupts with a spike of living blood, damaging anyone stood on it."
|
||||
gain_desc = "You have gained the ability to weaponise pools of blood to damage those stood on them."
|
||||
vampire_ability = TRUE
|
||||
required_blood = 100
|
||||
charge_max = 200 SECONDS
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "blood_spikes"
|
||||
|
||||
/obj/effect/proc_holder/spell/blood_eruption/cast(list/targets, mob/user)
|
||||
for(var/mob/living/L in targets)
|
||||
var/turf/T = get_turf(L)
|
||||
var/obj/effect/decal/cleanable/blood/B = locate(/obj/effect/decal/cleanable/blood) in T
|
||||
var/obj/effect/temp_visual/blood_spike/spike = new /obj/effect/temp_visual/blood_spike(T)
|
||||
spike.color = B.basecolor
|
||||
playsound(L, 'sound/misc/demon_attack1.ogg', 50, TRUE)
|
||||
L.apply_damage(50, BRUTE, BODY_ZONE_CHEST)
|
||||
L.visible_message("<span class='warning'><b>[L] gets impaled by a spike of living blood!</b></span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/blood_eruption/choose_targets(mob/user)
|
||||
var/list/targets = list()
|
||||
for(var/mob/living/L in view(4, user))
|
||||
var/turf/T = get_turf(L)
|
||||
if(locate(/obj/effect/decal/cleanable/blood) in T)
|
||||
if(L.affects_vampire(user) && !isLivingSSD(L))
|
||||
targets.Add(L)
|
||||
|
||||
if(!length(targets))
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(targets)
|
||||
|
||||
/obj/effect/temp_visual/blood_spike
|
||||
icon = 'icons/effects/vampire_effects.dmi'
|
||||
icon_state = "bloodspike_white"
|
||||
duration = 0.3 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill
|
||||
name = "The Blood Bringers Rite"
|
||||
desc = "When toggled, everyone around you begins to bleed profusely."
|
||||
gain_desc = "You have gained the ability to rip the very life force out of people and absorb it, healing you."
|
||||
charge_max = 10 SECONDS
|
||||
action_icon_state = "blood_bringers_rite"
|
||||
required_blood = 10
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill/cast(list/targets, mob/user)
|
||||
var/mob/target = targets[1]
|
||||
if(!target.mind.vampire.get_ability(/datum/vampire_passive/blood_spill))
|
||||
target.mind.vampire.force_add_ability(/datum/vampire_passive/blood_spill)
|
||||
else
|
||||
for(var/datum/vampire_passive/blood_spill/B in target.mind.vampire.powers)
|
||||
target.mind.vampire.remove_ability(B)
|
||||
|
||||
/datum/vampire_passive/blood_spill
|
||||
var/max_beams = 10
|
||||
|
||||
/datum/vampire_passive/blood_spill/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/vampire_passive/blood_spill/Destroy(force, ...)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/datum/vampire_passive/blood_spill/process()
|
||||
var/beam_number = 0
|
||||
var/turf/T = get_turf(owner)
|
||||
for(var/mob/living/carbon/human/H in view(7, T))
|
||||
if(NO_BLOOD in H.dna.species.species_traits)
|
||||
continue
|
||||
|
||||
if(!H.affects_vampire(owner) || H.stat)
|
||||
continue
|
||||
|
||||
var/drain_amount = rand(5, 10)
|
||||
beam_number++
|
||||
H.bleed(drain_amount)
|
||||
H.Beam(owner, icon_state = "drainbeam", time = 2 SECONDS)
|
||||
H.adjustBruteLoss(2)
|
||||
owner.heal_overall_damage(8, 2, TRUE)
|
||||
owner.adjustStaminaLoss(-15)
|
||||
owner.AdjustStunned(-1)
|
||||
owner.AdjustWeakened(-1)
|
||||
if(drain_amount == 10)
|
||||
to_chat(H, "<span class='warning'>You feel your life force draining!</b></span>")
|
||||
|
||||
if(beam_number >= max_beams)
|
||||
break
|
||||
owner.mind.vampire.bloodusable = max(owner.mind.vampire.bloodusable - 10, 0)
|
||||
if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
|
||||
owner.mind.vampire.remove_ability(src)
|
||||
@@ -0,0 +1,188 @@
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak
|
||||
name = "Cloak of Darkness"
|
||||
desc = "Toggles whether you are currently cloaking yourself in darkness. When in darkness and toggled on, you move at increased speeds."
|
||||
gain_desc = "You have gained the Cloak of Darkness ability, which when toggled makes you nearly invisible and highly agile in the shroud of darkness."
|
||||
action_icon_state = "vampire_cloak"
|
||||
charge_max = 2 SECONDS
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak/New()
|
||||
..()
|
||||
update_name()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak/proc/update_name()
|
||||
var/mob/living/user = loc
|
||||
if(!ishuman(user) || !user.mind || !user.mind.vampire)
|
||||
return
|
||||
action.button.name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/V = user.mind.vampire
|
||||
V.iscloaking = !V.iscloaking
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(V.iscloaking)
|
||||
H.physiology.burn_mod *= 1.3
|
||||
user.RegisterSignal(user, COMSIG_LIVING_IGNITED, /mob/living.proc/update_vampire_cloak)
|
||||
else
|
||||
user.UnregisterSignal(user, COMSIG_LIVING_IGNITED)
|
||||
H.physiology.burn_mod /= 1.3
|
||||
|
||||
update_name()
|
||||
to_chat(user, "<span class='notice'>You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.</span>")
|
||||
|
||||
/mob/living/proc/update_vampire_cloak()
|
||||
SIGNAL_HANDLER
|
||||
mind.vampire.handle_vampire_cloak()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare
|
||||
name = "Shadow Snare (20)"
|
||||
desc = "You summon a trap on the ground. When crossed it will blind the target, extinguish any lights they may have, and ensnare them."
|
||||
gain_desc = "You have gained the ability to summon a trap that will blind, ensnare, and turn off the lights of anyone who crosses it."
|
||||
charge_max = 20 SECONDS
|
||||
required_blood = 20
|
||||
vampire_ability = TRUE
|
||||
allowed_type = /turf/simulated
|
||||
click_radius = -1
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "shadow_snare"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare/cast(list/targets, mob/user)
|
||||
var/turf/target = targets[1]
|
||||
new /obj/item/restraints/legcuffs/beartrap/shadow_snare(target)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare
|
||||
name = "shadow snare"
|
||||
desc = "An almost transparent trap that melts into the shadows."
|
||||
alpha = 60
|
||||
armed = TRUE
|
||||
anchored = TRUE
|
||||
breakouttime = 5 SECONDS
|
||||
flags = DROPDEL
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Crossed(AM, oldloc)
|
||||
if(!iscarbon(AM) || !armed)
|
||||
return
|
||||
var/mob/living/carbon/C = AM
|
||||
if(!C.affects_vampire()) // no parameter here so holy always protects
|
||||
return
|
||||
C.extinguish_light()
|
||||
C.EyeBlind(10)
|
||||
STOP_PROCESSING(SSobj, src) // won't wither away once you are trapped
|
||||
..()
|
||||
if(!iscarbon(loc)) // if it fails to latch onto someone for whatever reason, delete itself, we don't want unarmed ones lying around.
|
||||
qdel(src)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/attack_hand(mob/user)
|
||||
Crossed(user)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/attack_tk(mob/user)
|
||||
if(iscarbon(user))
|
||||
to_chat(user, "<span class='userdanger'>The snare sends a psychic backlash!</span>")
|
||||
user.EyeBlind(10)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/process()
|
||||
var/turf/T = get_turf(src)
|
||||
var/lighting_count = T.get_lumcount() * 10
|
||||
if(lighting_count > 2)
|
||||
obj_integrity -= 50
|
||||
|
||||
if(obj_integrity <= 0)
|
||||
visible_message("<span class='notice'>[src] withers away.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Initialize(mapload)
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/restraints/legcuffs/beartrap/shadow_snare/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage
|
||||
name = "Dark Passage (30)"
|
||||
desc = "You teleport to a targeted turf."
|
||||
gain_desc = "You have gained the ability to blink a short distance towards a targeted turf."
|
||||
charge_max = 40 SECONDS
|
||||
required_blood = 30
|
||||
vampire_ability = TRUE
|
||||
allowed_type = /turf/simulated
|
||||
click_radius = 0
|
||||
centcom_cancast = FALSE
|
||||
action_icon_state = "dark_passage"
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage/cast(list/targets, mob/user)
|
||||
var/turf/target = get_turf(targets[1])
|
||||
|
||||
new /obj/effect/temp_visual/vamp_mist_out(get_turf(user))
|
||||
|
||||
user.forceMove(target)
|
||||
|
||||
/obj/effect/temp_visual/vamp_mist_out
|
||||
duration = 2 SECONDS
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "mist"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish
|
||||
name = "Extinguish"
|
||||
desc = "You extinguish any light source in an area around you."
|
||||
gain_desc = "You have gained the ability to extinguish nearby light sources."
|
||||
charge_max = 20 SECONDS
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
action_icon_state = "vampire_extinguish"
|
||||
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish/cast(list/targets, mob/user = usr)
|
||||
for(var/turf/T in targets)
|
||||
T.extinguish_light()
|
||||
for(var/atom/A in T.contents)
|
||||
A.extinguish_light()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness
|
||||
name = "Eternal Darkness"
|
||||
desc = "When toggled, you shroud the area around you in darkness and slowly lower the body temperature of people nearby."
|
||||
gain_desc = "You have gained the ability to shroud the area around you in darkness, only the strongest of lights can pierce your unholy powers."
|
||||
charge_max = 10 SECONDS
|
||||
action_icon_state = "eternal_darkness"
|
||||
required_blood = 5
|
||||
var/shroud_power = -4
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness/cast(list/targets, mob/user)
|
||||
var/mob/target = targets[1]
|
||||
if(!target.mind.vampire.get_ability(/datum/vampire_passive/eternal_darkness))
|
||||
target.mind.vampire.force_add_ability(/datum/vampire_passive/eternal_darkness)
|
||||
target.set_light(6, shroud_power, "#AAD84B")
|
||||
else
|
||||
for(var/datum/vampire_passive/eternal_darkness/E in target.mind.vampire.powers)
|
||||
target.mind.vampire.remove_ability(E)
|
||||
|
||||
/datum/vampire_passive/eternal_darkness
|
||||
gain_desc = "You surround yourself in a unnatural darkness, freezing those around you."
|
||||
|
||||
/datum/vampire_passive/eternal_darkness/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/datum/vampire_passive/eternal_darkness/Destroy(force, ...)
|
||||
owner.remove_light()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/datum/vampire_passive/eternal_darkness/process()
|
||||
for(var/mob/living/L in view(6, owner))
|
||||
if(L.affects_vampire(owner))
|
||||
L.adjust_bodytemperature(-20 * TEMPERATURE_DAMAGE_COEFFICIENT)
|
||||
|
||||
owner.mind.vampire.bloodusable = max(owner.mind.vampire.bloodusable - 5, 0)
|
||||
|
||||
if(!owner.mind.vampire.bloodusable || owner.stat == DEAD)
|
||||
owner.mind.vampire.remove_ability(src)
|
||||
|
||||
/datum/vampire_passive/xray
|
||||
gain_desc = "You can now see through walls, incase you hadn't noticed."
|
||||
@@ -0,0 +1,464 @@
|
||||
//This should hold all the vampire related powers
|
||||
/mob/living/proc/affects_vampire(mob/user)
|
||||
//Other vampires aren't affected
|
||||
if(mind?.vampire)
|
||||
return FALSE
|
||||
//Vampires who have reached their full potential can affect nearly everything
|
||||
if(user?.mind.vampire.get_ability(/datum/vampire_passive/full))
|
||||
return TRUE
|
||||
//Holy characters are resistant to vampire powers
|
||||
if(mind?.isholy)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/self/choose_targets(mob/user = usr)
|
||||
perform(list(user))
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/choose_targets(mob/user = usr)
|
||||
var/list/targets[0]
|
||||
for(var/mob/living/L in view(range, user))
|
||||
if(L == user)
|
||||
continue
|
||||
targets += L
|
||||
|
||||
if(!length(targets))
|
||||
revert_cast(user)
|
||||
return
|
||||
|
||||
perform(targets, user = user)
|
||||
|
||||
/obj/effect/proc_holder/spell/proc/before_cast_vampire(list/targets)
|
||||
// sanity check before we cast
|
||||
if(!usr.mind || !usr.mind.vampire)
|
||||
targets.Cut()
|
||||
return FALSE
|
||||
|
||||
if(!required_blood)
|
||||
return
|
||||
|
||||
// enforce blood
|
||||
var/datum/vampire/vampire = usr.mind.vampire
|
||||
var/blood_cost_modifier = 1 + vampire.nullified / 100
|
||||
var/blood_cost = round(required_blood * blood_cost_modifier)
|
||||
|
||||
if(blood_cost <= vampire.bloodusable)
|
||||
if(!deduct_blood_on_cast) //don't take the blood yet if this is false!
|
||||
return
|
||||
vampire.bloodusable -= blood_cost
|
||||
SSblackbox.record_feedback("tally", "vampire_powers_used", 1, "[name]")
|
||||
to_chat(usr, "<span class='boldnotice'>You have [vampire.bloodusable] left to use.</span>")
|
||||
return TRUE
|
||||
else
|
||||
// stop!!
|
||||
targets.Cut()
|
||||
return FALSE
|
||||
|
||||
/datum/vampire_passive
|
||||
var/gain_desc
|
||||
var/mob/living/owner = null
|
||||
|
||||
/datum/vampire_passive/New()
|
||||
..()
|
||||
if(!gain_desc)
|
||||
gain_desc = "You can now use [src]."
|
||||
|
||||
/datum/vampire_passive/Destroy(force, ...)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/rejuvenate
|
||||
name = "Rejuvenate"
|
||||
desc = "Use reserve blood to enliven your body, removing any incapacitating effects."
|
||||
action_icon_state = "vampire_rejuvinate"
|
||||
charge_max = 200
|
||||
stat_allowed = 1
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/rejuvenate/cast(list/targets, mob/user = usr)
|
||||
var/mob/living/U = user
|
||||
|
||||
U.SetWeakened(0)
|
||||
U.SetStunned(0)
|
||||
U.SetParalysis(0)
|
||||
U.SetSleeping(0)
|
||||
U.SetConfused(0)
|
||||
U.adjustStaminaLoss(-100)
|
||||
to_chat(user, "<span class='notice'>You instill your body with clean blood and remove any incapacitating effects.</span>")
|
||||
var/rejuv_bonus = U.mind.vampire.get_rejuv_bonus()
|
||||
if(rejuv_bonus)
|
||||
INVOKE_ASYNC(src, .proc/heal, U, rejuv_bonus)
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/rejuvenate/proc/heal(mob/living/user, rejuv_bonus)
|
||||
for(var/i in 1 to 5)
|
||||
user.adjustBruteLoss(-2 * rejuv_bonus)
|
||||
user.adjustOxyLoss(-5 * rejuv_bonus)
|
||||
user.adjustToxLoss(-2 * rejuv_bonus)
|
||||
user.adjustFireLoss(-2 * rejuv_bonus)
|
||||
for(var/datum/reagent/R in user.reagents.reagent_list)
|
||||
if(!R.harmless)
|
||||
user.reagents.remove_reagent(R.id, 2 * rejuv_bonus)
|
||||
sleep(35)
|
||||
|
||||
/datum/vampire/proc/get_rejuv_bonus()
|
||||
var/rejuv_multiplier = 0
|
||||
if(!get_ability(/datum/vampire_passive/regen))
|
||||
return rejuv_multiplier
|
||||
|
||||
if(subclass?.improved_rejuv_healing)
|
||||
rejuv_multiplier = clamp((100 - owner.health) / 20, 1, 5) // brute and burn healing between 5 and 50
|
||||
return rejuv_multiplier
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize
|
||||
name = "Choose Specialization"
|
||||
desc = "Choose what sub-class of vampire you want to evolve into."
|
||||
gain_desc = "You can now choose what specialization of vampire you want to evolve into."
|
||||
charge_max = 2 SECONDS
|
||||
action_icon_state = "select_class"
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/cast(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "SpecMenu", "Specialisation Menu", 900, 600, master_ui, state)
|
||||
ui.set_autoupdate(FALSE)
|
||||
ui.open()
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_data(mob/user)
|
||||
var/datum/vampire/vamp = user.mind.vampire
|
||||
var/list/data = list("subclasses" = vamp.subclass)
|
||||
return data
|
||||
|
||||
/obj/effect/proc_holder/spell/self/vampire/specialize/ui_act(action, list/params)
|
||||
if(..())
|
||||
return
|
||||
var/datum/vampire/vamp = usr.mind.vampire
|
||||
|
||||
if(vamp.subclass)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("umbrae")
|
||||
vamp.add_subclass(SUBCLASS_UMBRAE)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
if("hemomancer")
|
||||
vamp.add_subclass(SUBCLASS_HEMOMANCER)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
if("gargantua")
|
||||
vamp.add_subclass(SUBCLASS_GARGANTUA)
|
||||
vamp.upgrade_tiers -= type
|
||||
vamp.remove_ability(src)
|
||||
|
||||
|
||||
/datum/vampire/proc/add_subclass(subclass_to_add, announce = TRUE)
|
||||
var/datum/vampire_subclass/new_subclass = new subclass_to_add
|
||||
subclass = new_subclass
|
||||
check_vampire_upgrade(announce)
|
||||
SSblackbox.record_feedback("nested tally", "vampire_subclasses", 1, list("[new_subclass.name]"))
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare
|
||||
name = "Glare"
|
||||
desc = "Your eyes flash, stunning and silencing anyone infront of you. It has lesser effects for those around you."
|
||||
action_icon_state = "vampire_glare"
|
||||
charge_max = 30 SECONDS
|
||||
stat_allowed = 1
|
||||
range = 1
|
||||
vampire_ability = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
/// No deviation at all. Flashed from the front or front-left/front-right. Alternatively, flashed in direct view.
|
||||
#define DEVIATION_NONE 3
|
||||
/// Partial deviation. Flashed from the side. Alternatively, flashed out the corner of your eyes.
|
||||
#define DEVIATION_PARTIAL 2
|
||||
/// Full deviation. Flashed from directly behind or behind-left/behind-rack. Not flashed at all.
|
||||
#define DEVIATION_FULL 1
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare/cast(list/targets, mob/living/user = usr)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/sunglasses/blindfold))
|
||||
var/obj/item/clothing/glasses/sunglasses/blindfold/B = H.glasses
|
||||
if(B.tint)
|
||||
to_chat(user, "<span class='warning'>You're blindfolded!</span>")
|
||||
return
|
||||
user.mob_light(LIGHT_COLOR_BLOOD_MAGIC, 3, _duration = 2)
|
||||
user.visible_message("<span class='warning'>[user]'s eyes emit a blinding flash!</span>")
|
||||
|
||||
for(var/mob/living/target in targets)
|
||||
if(!target.affects_vampire(user))
|
||||
continue
|
||||
|
||||
var/deviation
|
||||
if(user.weakened || user.resting)
|
||||
deviation = DEVIATION_PARTIAL
|
||||
else
|
||||
deviation = calculate_deviation(target, user)
|
||||
|
||||
if(deviation == DEVIATION_FULL)
|
||||
target.AdjustConfused(3)
|
||||
target.adjustStaminaLoss(40)
|
||||
else if(deviation == DEVIATION_PARTIAL)
|
||||
target.Weaken(1)
|
||||
target.AdjustConfused(3)
|
||||
target.adjustStaminaLoss(40)
|
||||
else
|
||||
target.adjustStaminaLoss(120)
|
||||
target.Weaken(6)
|
||||
target.AdjustSilence(3)
|
||||
target.flash_eyes(1, TRUE, TRUE)
|
||||
to_chat(target, "<span class='warning'>You are blinded by [user]'s glare.</span>")
|
||||
add_attack_logs(user, target, "(Vampire) Glared at")
|
||||
|
||||
/obj/effect/proc_holder/spell/mob_aoe/glare/proc/calculate_deviation(mob/victim, mob/attacker)
|
||||
// Are they on the same tile? We'll return partial deviation. This may be someone flashing while lying down
|
||||
if(victim.loc == attacker.loc)
|
||||
return DEVIATION_PARTIAL
|
||||
|
||||
// If the victim was looking at the attacker, this is the direction they'd have to be facing.
|
||||
var/attacker_to_victim = get_dir(attacker, victim)
|
||||
// The victim's dir is necessarily a cardinal value.
|
||||
var/attacker_dir = attacker.dir
|
||||
|
||||
// - - -
|
||||
// - V - Attacker facing south
|
||||
// # # #
|
||||
// Attacker within 45 degrees of where the victim is facing.
|
||||
if(attacker_dir & attacker_to_victim)
|
||||
return DEVIATION_NONE
|
||||
|
||||
// # # #
|
||||
// - V - Attacker facing south
|
||||
// - - -
|
||||
// Victim at 135 or more degrees of where the victim is facing.
|
||||
if(attacker_dir & GetOppositeDir(attacker_to_victim))
|
||||
return DEVIATION_FULL
|
||||
|
||||
// - - -
|
||||
// # V # Attacker facing south
|
||||
// - - -
|
||||
// Victim lateral to the victim.
|
||||
return DEVIATION_PARTIAL
|
||||
|
||||
#undef DEVIATION_NONE
|
||||
#undef DEVIATION_PARTIAL
|
||||
#undef DEVIATION_FULL
|
||||
|
||||
/datum/vampire_passive/regen
|
||||
gain_desc = "Your rejuvenation abilities have improved and will now heal you over time when used."
|
||||
|
||||
/datum/vampire_passive/vision
|
||||
gain_desc = "Your vampiric vision has improved."
|
||||
|
||||
/datum/vampire_passive/full
|
||||
gain_desc = "You have reached your full potential. You are no longer weak to the effects of anything holy and your vision has improved greatly."
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires
|
||||
name = "Raise Vampires"
|
||||
desc = "Summons deadly vampires from bluespace."
|
||||
school = "transmutation"
|
||||
charge_max = 100
|
||||
clothes_req = 0
|
||||
human_req = 1
|
||||
invocation = "none"
|
||||
invocation_type = "none"
|
||||
max_targets = 0
|
||||
range = 3
|
||||
cooldown_min = 20
|
||||
action_icon_state = "revive_thrall"
|
||||
vampire_ability = TRUE
|
||||
sound = 'sound/magic/wandodeath.ogg'
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
gain_desc = "You have gained the ability to Raise Vampires. This extremely powerful AOE ability affects all humans near you. Vampires/thralls are healed. Corpses are raised as vampires. Others are stunned, then brain damaged, then killed."
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires/cast(list/targets, mob/user = usr)
|
||||
new /obj/effect/temp_visual/cult/sparks(user.loc)
|
||||
var/turf/T = get_turf(user)
|
||||
to_chat(user, "<span class='warning'>You call out within bluespace, summoning more vampiric spirits to aid you!</span>")
|
||||
for(var/mob/living/carbon/human/H in targets)
|
||||
T.Beam(H, "sendbeam", 'icons/effects/effects.dmi', time = 30, maxdistance = 7, beam_type = /obj/effect/ebeam)
|
||||
new /obj/effect/temp_visual/cult/sparks(H.loc)
|
||||
raise_vampire(user, H)
|
||||
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires/proc/raise_vampire(mob/M, mob/living/carbon/human/H)
|
||||
if(!istype(M) || !istype(H))
|
||||
return
|
||||
if(!H.mind)
|
||||
visible_message("[H] looks to be too stupid to understand what is going on.")
|
||||
return
|
||||
if(H.dna && (NO_BLOOD in H.dna.species.species_traits) || H.dna.species.exotic_blood || !H.blood_volume)
|
||||
visible_message("[H] looks unfazed!")
|
||||
return
|
||||
if(H.mind.vampire || H.mind.special_role == SPECIAL_ROLE_VAMPIRE || H.mind.special_role == SPECIAL_ROLE_VAMPIRE_THRALL)
|
||||
visible_message("<span class='notice'>[H] looks refreshed!</span>")
|
||||
H.adjustBruteLoss(-60)
|
||||
H.adjustFireLoss(-60)
|
||||
for(var/obj/item/organ/external/E in H.bodyparts)
|
||||
if(prob(25))
|
||||
E.mend_fracture()
|
||||
E.internal_bleeding = FALSE
|
||||
|
||||
return
|
||||
if(H.stat != DEAD)
|
||||
if(H.IsWeakened())
|
||||
visible_message("<span class='warning'>[H] looks to be in pain!</span>")
|
||||
H.adjustBrainLoss(60)
|
||||
else
|
||||
visible_message("<span class='warning'>[H] looks to be stunned by the energy!</span>")
|
||||
H.Weaken(20)
|
||||
return
|
||||
for(var/obj/item/implant/mindshield/L in H)
|
||||
if(L && L.implanted)
|
||||
qdel(L)
|
||||
for(var/obj/item/implant/traitor/T in H)
|
||||
if(T && T.implanted)
|
||||
qdel(T)
|
||||
visible_message("<span class='warning'>[H] gets an eerie red glow in their eyes!</span>")
|
||||
var/datum/objective/protect/protect_objective = new
|
||||
protect_objective.owner = H.mind
|
||||
protect_objective.target = M.mind
|
||||
protect_objective.explanation_text = "Protect [M.real_name]."
|
||||
H.mind.objectives += protect_objective
|
||||
add_attack_logs(M, H, "Vampire-sired")
|
||||
H.mind.make_vampire()
|
||||
H.revive()
|
||||
H.Weaken(20)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/turf_teleport/shadow_step
|
||||
name = "Shadow Step (30)"
|
||||
desc = "Teleport to a nearby dark region"
|
||||
gain_desc = "You have gained the ability to shadowstep, which makes you disappear into nearby shadows at the cost of blood."
|
||||
action_icon_state = "shadowblink"
|
||||
charge_max = 20
|
||||
required_blood = 30
|
||||
centcom_cancast = FALSE
|
||||
vampire_ability = TRUE
|
||||
include_space = FALSE
|
||||
range = -1
|
||||
include_user = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
// Teleport radii
|
||||
inner_tele_radius = 0
|
||||
outer_tele_radius = 6
|
||||
|
||||
include_light_turfs = FALSE
|
||||
|
||||
sound1 = null
|
||||
sound2 = null
|
||||
|
||||
// pure adminbus at the moment
|
||||
/proc/isvampirethrall(mob/living/M)
|
||||
return istype(M) && M.mind && SSticker.mode && (M.mind in SSticker.mode.vampire_enthralled)
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall
|
||||
name = "Enthrall (150)"
|
||||
desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only."
|
||||
gain_desc = "You have gained the ability to thrall people to your will."
|
||||
action_icon_state = "vampire_enthrall"
|
||||
required_blood = 150
|
||||
deduct_blood_on_cast = FALSE
|
||||
vampire_ability = TRUE
|
||||
humans_only = TRUE
|
||||
panel = "Vampire"
|
||||
school = "vampire"
|
||||
action_background_icon_state = "bg_vampire"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets, mob/user = usr)
|
||||
var/datum/vampire/vampire = user.mind.vampire
|
||||
for(var/mob/living/target in targets)
|
||||
user.visible_message("<span class='warning'>[user] bites [target]'s neck!</span>", "<span class='warning'>You bite [target]'s neck and begin the flow of power.</span>")
|
||||
to_chat(target, "<span class='warning'>You feel the tendrils of evil invade your mind.</span>")
|
||||
if(do_mob(user, target, 50))
|
||||
if(can_enthrall(user, target))
|
||||
handle_enthrall(user, target)
|
||||
var/blood_cost_modifier = 1 + vampire.nullified/100
|
||||
var/blood_cost = round(required_blood * blood_cost_modifier)
|
||||
vampire.bloodusable -= blood_cost //we take the blood after enthralling, not before
|
||||
else
|
||||
revert_cast(user)
|
||||
to_chat(user, "<span class='warning'>You or your target either moved or you dont have enough usable blood.</span>")
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C)
|
||||
var/enthrall_safe = 0
|
||||
for(var/obj/item/implant/mindshield/L in C)
|
||||
if(L && L.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
for(var/obj/item/implant/traitor/T in C)
|
||||
if(T && T.implanted)
|
||||
enthrall_safe = 1
|
||||
break
|
||||
if(!C)
|
||||
log_runtime(EXCEPTION("something bad happened on enthralling a mob, attacker is [user] [user.key] \ref[user]"), user)
|
||||
return FALSE
|
||||
if(!C.mind)
|
||||
to_chat(user, "<span class='warning'>[C.name]'s mind is not there for you to enthrall.</span>")
|
||||
return FALSE
|
||||
if(enthrall_safe || (C.mind in SSticker.mode.vampires) || (C.mind.vampire) || (C.mind in SSticker.mode.vampire_enthralled))
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You feel a familiar sensation in your skull that quickly dissipates.</span>")
|
||||
return FALSE
|
||||
if(!C.affects_vampire(user))
|
||||
if(C.mind.isholy)
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>Your faith in [SSticker.Bible_deity_name] has kept your mind clear of all evil.</span>")
|
||||
else
|
||||
C.visible_message("<span class='warning'>[C] seems to resist the takeover!</span>", "<span class='notice'>You resist the attack on your mind.</span>")
|
||||
return FALSE
|
||||
if(!ishuman(C))
|
||||
to_chat(user, "<span class='warning'>You can only enthrall sentient humanoids!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall/proc/handle_enthrall(mob/living/user, mob/living/carbon/human/H)
|
||||
if(!istype(H))
|
||||
return 0
|
||||
var/ref = "\ref[user.mind]"
|
||||
if(!(ref in SSticker.mode.vampire_thralls))
|
||||
SSticker.mode.vampire_thralls[ref] = list(H.mind)
|
||||
else
|
||||
SSticker.mode.vampire_thralls[ref] += H.mind
|
||||
SSticker.mode.update_vampire_icons_added(H.mind)
|
||||
SSticker.mode.update_vampire_icons_added(user.mind)
|
||||
var/datum/mindslaves/slaved = user.mind.som
|
||||
if(!slaved)
|
||||
slaved = new()
|
||||
slaved.masters = user.mind
|
||||
H.mind.som = slaved
|
||||
slaved.serv += H
|
||||
slaved.add_serv_hud(user.mind, "vampire")//handles master servent icons
|
||||
slaved.add_serv_hud(H.mind, "vampthrall")
|
||||
|
||||
SSticker.mode.vampire_enthralled.Add(H.mind)
|
||||
SSticker.mode.vampire_enthralled[H.mind] = user.mind
|
||||
H.mind.special_role = SPECIAL_ROLE_VAMPIRE_THRALL
|
||||
|
||||
var/datum/objective/protect/serve_objective = new
|
||||
serve_objective.owner = user.mind
|
||||
serve_objective.target = H.mind
|
||||
serve_objective.explanation_text = "You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command."
|
||||
H.mind.objectives += serve_objective
|
||||
|
||||
to_chat(H, "<span class='biggerdanger'>You have been Enthralled by [user.real_name]. Follow [user.p_their()] every command.</span>")
|
||||
to_chat(user, "<span class='warning'>You have successfully Enthralled [H]. <i>If [H.p_they()] refuse[H.p_s()] to do as you say just adminhelp.</i></span>")
|
||||
H.Stun(2)
|
||||
add_attack_logs(user, H, "Vampire-thralled")
|
||||
@@ -0,0 +1,70 @@
|
||||
/datum/vampire_subclass
|
||||
/// The subclass' name. Used for blackbox logging.
|
||||
var/name = "yell at coderbus"
|
||||
/// A list of powers that a vampire unlocks. The value of the list entry is equal to the blood total required for the vampire to unlock it.
|
||||
var/list/standard_powers
|
||||
/// A list of the powers a vampire unlocks when it reaches full power.
|
||||
var/list/fully_powered_abilities
|
||||
/// Whether or not a vampire heals more based on damage taken.
|
||||
var/improved_rejuv_healing = FALSE
|
||||
|
||||
/datum/vampire_subclass/proc/add_subclass_ability(datum/vampire/vamp)
|
||||
for(var/thing in standard_powers)
|
||||
if(vamp.bloodtotal >= standard_powers[thing])
|
||||
vamp.add_ability(thing)
|
||||
|
||||
/datum/vampire_subclass/proc/add_full_power_abilities(datum/vampire/vamp)
|
||||
for(var/thing in fully_powered_abilities)
|
||||
vamp.add_ability(thing)
|
||||
|
||||
/datum/vampire_subclass/umbrae
|
||||
name = "umbrae"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/cloak = 150,
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare = 250,
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage = 400,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish = 600)
|
||||
fully_powered_abilities = list(/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
|
||||
/datum/vampire_passive/xray)
|
||||
|
||||
/datum/vampire_subclass/hemomancer
|
||||
name = "hemomancer"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws = 150,
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils = 250,
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool = 400,
|
||||
/obj/effect/proc_holder/spell/blood_eruption = 600)
|
||||
fully_powered_abilities = list(/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill)
|
||||
|
||||
/datum/vampire_subclass/gargantua
|
||||
name = "gargantua"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/blood_swell = 150,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush = 250,
|
||||
/datum/vampire_passive/blood_swell_upgrade = 400,
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force = 600)
|
||||
fully_powered_abilities = list(/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge)
|
||||
improved_rejuv_healing = TRUE
|
||||
|
||||
/datum/vampire_subclass/ancient
|
||||
name = "ancient"
|
||||
standard_powers = list(/obj/effect/proc_holder/spell/self/vampire/vamp_claws,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_swell,
|
||||
/obj/effect/proc_holder/spell/self/vampire/cloak,
|
||||
/obj/effect/proc_holder/spell/targeted/click/blood_tendrils,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_rush,
|
||||
/obj/effect/proc_holder/spell/targeted/click/shadow_snare,
|
||||
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/blood_pool,
|
||||
/datum/vampire_passive/blood_swell_upgrade,
|
||||
/obj/effect/proc_holder/spell/targeted/click/dark_passage,
|
||||
/obj/effect/proc_holder/spell/blood_eruption,
|
||||
/obj/effect/proc_holder/spell/self/vampire/overwhelming_force,
|
||||
/obj/effect/proc_holder/spell/aoe_turf/vamp_extinguish,
|
||||
/obj/effect/proc_holder/spell/targeted/raise_vampires,
|
||||
/obj/effect/proc_holder/spell/targeted/enthrall,
|
||||
/datum/vampire_passive/full,
|
||||
/obj/effect/proc_holder/spell/self/vampire/blood_spill,
|
||||
/obj/effect/proc_holder/spell/targeted/click/charge,
|
||||
/obj/effect/proc_holder/spell/self/vampire/eternal_darkness,
|
||||
/datum/vampire_passive/xray)
|
||||
improved_rejuv_healing = TRUE
|
||||
@@ -83,6 +83,10 @@
|
||||
if(!ishuman(M)) //If target is not a human
|
||||
return ..()
|
||||
|
||||
if(!M.mind)
|
||||
to_chat(user, "<span class='warning'>This being has no soul!</span>")
|
||||
return ..()
|
||||
|
||||
if(M.has_brain_worms()) //Borer stuff - RR
|
||||
to_chat(user, "<span class='warning'>This being is corrupted by an alien intelligence and cannot be soul trapped.</span>")
|
||||
return ..()
|
||||
|
||||
@@ -343,6 +343,21 @@
|
||||
playsound(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/slience_ghosts
|
||||
name = "Silence Ghosts"
|
||||
desc = "Tired of people talking behind your back, and spooking you? Why not silence them, and make the dead deader."
|
||||
cost = 2
|
||||
log_name = "SLG"
|
||||
is_ragin_restricted = TRUE //Salt needs to flow here, to be honest
|
||||
|
||||
/datum/spellbook_entry/summon/slience_ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
|
||||
new /datum/event/wizard/ghost_mute()
|
||||
active = TRUE
|
||||
to_chat(user, "<span class='notice'>You have silenced all ghosts!</span>")
|
||||
playsound(get_turf(user), 'sound/effects/ghost.ogg', 50, 1)
|
||||
message_admins("[key_name_admin(usr)] silenced all ghosts as a wizard! (Deadchat is now DISABLED)")
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/guns
|
||||
name = "Summon Guns"
|
||||
desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. There is a good chance that they will shoot each other first."
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
glasses = /obj/item/clothing/glasses/hud/security/sunglasses
|
||||
id = /obj/item/card/id/security
|
||||
l_pocket = /obj/item/flash
|
||||
suit_store = /obj/item/gun/energy/gun/advtaser
|
||||
suit_store = /obj/item/gun/energy/disabler
|
||||
pda = /obj/item/pda/warden
|
||||
backpack_contents = list(
|
||||
/obj/item/restraints/handcuffs = 1
|
||||
@@ -180,7 +180,7 @@
|
||||
l_ear = /obj/item/radio/headset/headset_sec/alt
|
||||
id = /obj/item/card/id/security
|
||||
l_pocket = /obj/item/flash
|
||||
suit_store = /obj/item/gun/energy/gun/advtaser
|
||||
suit_store = /obj/item/gun/energy/disabler
|
||||
pda = /obj/item/pda/security
|
||||
backpack_contents = list(
|
||||
/obj/item/restraints/handcuffs = 1
|
||||
|
||||
@@ -194,16 +194,18 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
|
||||
/datum/job/judge
|
||||
title = "Magistrate"
|
||||
flag = JOB_JUDGE
|
||||
department_flag = JOBCAT_KARMA
|
||||
department_flag = JOBCAT_ENGSEC
|
||||
total_positions = 1
|
||||
spawn_positions = 1
|
||||
supervisors = "the Nanotrasen Supreme Court"
|
||||
department_head = list("Captain")
|
||||
selection_color = "#ddddff"
|
||||
req_admin_notify = 1
|
||||
is_legal = 1
|
||||
req_admin_notify = TRUE
|
||||
is_legal = TRUE
|
||||
transfer_allowed = FALSE
|
||||
minimal_player_age = 30
|
||||
exp_requirements = 6000 // 100 hours baby
|
||||
exp_type = EXP_TYPE_SECURITY
|
||||
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
|
||||
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_EVA, ACCESS_HEADS,
|
||||
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
|
||||
@@ -261,7 +263,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
|
||||
uniform = /obj/item/clothing/under/rank/internalaffairs
|
||||
suit = /obj/item/clothing/suit/storage/internalaffairs
|
||||
shoes = /obj/item/clothing/shoes/brown
|
||||
l_ear = /obj/item/radio/headset/headset_iaa
|
||||
l_ear = /obj/item/radio/headset/headset_iaa/alt
|
||||
glasses = /obj/item/clothing/glasses/hud/security/sunglasses/read_only
|
||||
id = /obj/item/card/id/security
|
||||
l_pocket = /obj/item/laser_pointer
|
||||
|
||||
@@ -96,8 +96,7 @@ GLOBAL_LIST_INIT(whitelisted_positions, list(
|
||||
"Blueshield",
|
||||
"Nanotrasen Representative",
|
||||
"Barber",
|
||||
"Brig Physician",
|
||||
"Magistrate"
|
||||
"Brig Physician"
|
||||
))
|
||||
|
||||
|
||||
|
||||
@@ -420,7 +420,7 @@
|
||||
item_state = "claymorered"
|
||||
|
||||
/obj/item/holo/esword
|
||||
name = "Holographic Energy Sword"
|
||||
name = "holographic energy sword"
|
||||
desc = "This looks like a real energy sword!"
|
||||
icon_state = "sword0"
|
||||
hitsound = "swing_hit"
|
||||
|
||||
@@ -1287,6 +1287,17 @@ About the new airlock wires panel:
|
||||
if(duration > electrified_until)
|
||||
electrify(duration)
|
||||
|
||||
/obj/machinery/door/airlock/ex_act(severity)
|
||||
if(resistance_flags & INDESTRUCTIBLE)
|
||||
return
|
||||
switch(severity)
|
||||
if(EXPLODE_DEVASTATE) //Destroy the airlock completely.
|
||||
qdel(src)
|
||||
if(EXPLODE_HEAVY) //Deconstruct the airlock, leaving damaged airlock frame and parts behind
|
||||
deconstruct(FALSE, null)
|
||||
if(EXPLODE_LIGHT) //Deals 150 damage to the airlock, half a standard airlock's integrity
|
||||
take_damage(150)
|
||||
|
||||
/obj/machinery/door/airlock/attack_alien(mob/living/carbon/alien/humanoid/user)
|
||||
add_fingerprint(user)
|
||||
if(isElectrified())
|
||||
|
||||
@@ -206,8 +206,9 @@
|
||||
continue
|
||||
if(C.opened && !C.close())
|
||||
continue
|
||||
C.locked = 1
|
||||
C.icon_state = C.icon_locked
|
||||
C.locked = TRUE
|
||||
C.close()
|
||||
C.update_icon()
|
||||
|
||||
for(var/obj/machinery/treadmill_monitor/T in targets)
|
||||
T.total_joules = 0
|
||||
|
||||
@@ -149,6 +149,23 @@
|
||||
B.door_opened(src)
|
||||
else
|
||||
do_animate("deny")
|
||||
if(HAS_TRAIT(user, TRAIT_FORCE_DOORS))
|
||||
if(user.mind?.vampire && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
|
||||
if(!user.mind.vampire.bloodusable)
|
||||
REMOVE_TRAIT(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT)
|
||||
return
|
||||
if(welded)
|
||||
to_chat(user, "<span class='warning'>The door is welded.</span>")
|
||||
return
|
||||
if(locked)
|
||||
to_chat(user, "<span class='warning'>The door is bolted.</span>")
|
||||
return
|
||||
if(density)
|
||||
visible_message("<span class='danger'>[user] forces the door open!</span>")
|
||||
playsound(loc, "sparks", 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
open(TRUE)
|
||||
if(user.mind?.vampire && HAS_TRAIT_FROM(user, TRAIT_FORCE_DOORS, VAMPIRE_TRAIT))
|
||||
user.mind.vampire.bloodusable = max(user.mind.vampire.bloodusable - 5, 0)
|
||||
|
||||
/obj/machinery/door/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
@@ -378,11 +395,6 @@
|
||||
if(!stat) //Opens only powered doors.
|
||||
open() //Open everything!
|
||||
|
||||
/obj/machinery/door/ex_act(severity)
|
||||
//if it blows up a wall it should blow up a door
|
||||
..(severity ? max(1, severity - 1) : 0)
|
||||
|
||||
|
||||
/obj/machinery/door/GetExplosionBlock()
|
||||
return density ? real_explosion_block : 0
|
||||
|
||||
|
||||
@@ -720,7 +720,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
return A
|
||||
|
||||
/obj/machinery/porta_turret/centcom
|
||||
name = "Centcom Turret"
|
||||
name = "\improper Centcomm turret"
|
||||
enabled = FALSE
|
||||
ailock = TRUE
|
||||
check_synth = FALSE
|
||||
@@ -732,7 +732,7 @@ GLOBAL_LIST_EMPTY(turret_icons)
|
||||
region_max = REGION_CENTCOMM // Non-turretcontrolled turrets at CC can have their access customized to check for CC accesses.
|
||||
|
||||
/obj/machinery/porta_turret/centcom/pulse
|
||||
name = "Pulse Turret"
|
||||
name = "pulse turret"
|
||||
health = 200
|
||||
enabled = TRUE
|
||||
lethal = TRUE
|
||||
|
||||
@@ -168,6 +168,9 @@
|
||||
use_power = IDLE_POWER_USE
|
||||
return
|
||||
|
||||
/obj/machinery/recharge_station/force_eject_occupant(mob/target)
|
||||
go_out()
|
||||
|
||||
/obj/machinery/recharge_station/verb/move_eject()
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
@@ -89,6 +89,15 @@
|
||||
/obj/machinery/suit_storage_unit/ce/secure
|
||||
secure = TRUE
|
||||
|
||||
/obj/machinery/suit_storage_unit/rd
|
||||
name = "research director's suit storage unit"
|
||||
suit_type = /obj/item/clothing/suit/space/hardsuit/rd
|
||||
mask_type = /obj/item/clothing/mask/gas
|
||||
req_access = list(ACCESS_RD)
|
||||
|
||||
/obj/machinery/suit_storage_unit/rd/secure
|
||||
secure = TRUE
|
||||
|
||||
/obj/machinery/suit_storage_unit/security
|
||||
name = "security suit storage unit"
|
||||
suit_type = /obj/item/clothing/suit/space/hardsuit/security
|
||||
@@ -313,6 +322,8 @@
|
||||
if(shock(user, 100))
|
||||
return
|
||||
if(!is_operational())
|
||||
if(user.a_intent != INTENT_HELP)
|
||||
return ..()
|
||||
if(panel_open)
|
||||
to_chat(usr, "<span class='warning'>Close the maintenance panel first.</span>")
|
||||
else
|
||||
|
||||
@@ -440,7 +440,7 @@
|
||||
range_flame = 2
|
||||
|
||||
/obj/item/bombcore/emp
|
||||
name = "EMP bomb core"
|
||||
name = "\improper EMP bomb core"
|
||||
var/light_emp = 36
|
||||
var/heavy_emp = 18
|
||||
var/pulse_number = 1 //Since one EMP wont destroy anything other then consoles and IPCS, here is an option to have multiple pulses when dentonating. DO NOT USE THIS WITH REALLY LARGE AREAS
|
||||
|
||||
@@ -1804,30 +1804,31 @@
|
||||
icon_state = "secdrobe"
|
||||
ads_list = list("Beat perps in style!", "It's red so you can't see the blood!", "You have the right to be fashionable!", "Now you can be the fashion police you always wanted to be!")
|
||||
vend_reply = "Thank you for using the SecDrobe!"
|
||||
products = list(/obj/item/clothing/under/rank/security = 4,
|
||||
products = list(/obj/item/clothing/under/rank/security/corp = 4,
|
||||
/obj/item/clothing/under/rank/dispatch = 4,
|
||||
/obj/item/clothing/under/rank/security/skirt = 4,
|
||||
/obj/item/clothing/under/rank/security = 4,
|
||||
/obj/item/clothing/under/rank/security2 = 4,
|
||||
/obj/item/clothing/under/rank/security/formal = 4,
|
||||
/obj/item/clothing/under/rank/security/skirt = 4,
|
||||
/obj/item/clothing/under/rank/security/corp = 4,
|
||||
/obj/item/clothing/under/rank/dispatch = 4,
|
||||
/obj/item/clothing/head/soft/sec/corp = 4,
|
||||
/obj/item/clothing/head/officer = 4,
|
||||
/obj/item/clothing/head/beret/sec = 4,
|
||||
/obj/item/clothing/head/soft/sec = 4,
|
||||
/obj/item/clothing/head/soft/sec/corp = 4,
|
||||
/obj/item/clothing/suit/armor/secjacket = 4,
|
||||
/obj/item/clothing/suit/jacket/secbomber = 2,
|
||||
/obj/item/clothing/suit/armor/secjacket = 4,
|
||||
/obj/item/clothing/suit/hooded/wintercoat/security = 4,
|
||||
/obj/item/clothing/gloves/color/black = 4,
|
||||
/obj/item/clothing/accessory/armband/sec = 6,
|
||||
/obj/item/clothing/shoes/laceup = 4,
|
||||
/obj/item/clothing/shoes/jackboots = 4,
|
||||
/obj/item/clothing/shoes/jackboots/jacksandals = 4,
|
||||
/obj/item/clothing/shoes/laceup = 4,
|
||||
/obj/item/storage/backpack/duffel/security = 2,
|
||||
/obj/item/storage/backpack/security = 2,
|
||||
/obj/item/storage/backpack/satchel_sec = 2,
|
||||
/obj/item/storage/backpack/duffel/security = 2)
|
||||
premium = list(/obj/item/clothing/mask/gas/sechailer/swat = 2,
|
||||
/obj/item/clothing/mask/balaclava = 1)
|
||||
contraband = list(/obj/item/toy/figure/crew/secofficer = 1,
|
||||
/obj/item/toy/figure/crew/hos = 1)
|
||||
/obj/item/clothing/gloves/color/black = 4,
|
||||
/obj/item/clothing/accessory/armband/sec = 6)
|
||||
premium = list(/obj/item/clothing/mask/balaclava = 1,
|
||||
/obj/item/clothing/mask/gas/sechailer/swat = 2)
|
||||
contraband = list(/obj/item/toy/figure/crew/hos = 1,
|
||||
/obj/item/toy/figure/crew/secofficer = 1)
|
||||
refill_canister = /obj/item/vending_refill/secdrobe
|
||||
|
||||
/obj/machinery/vending/detdrobe
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
/obj/mecha/combat/gygax/loaded/New()
|
||||
..()
|
||||
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/taser
|
||||
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/weapon/energy/disabler
|
||||
ME.attach(src)
|
||||
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang
|
||||
ME.attach(src)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Teleporter, Wormhole generator, Gravitational catapult, Armor booster modules,
|
||||
// Teleporter, Gravitational catapult, Armor booster modules,
|
||||
// Repair droid, Tesla Energy relay, Generators
|
||||
|
||||
////////////////////////////////////////////// TELEPORTER ///////////////////////////////////////////////
|
||||
@@ -29,53 +29,6 @@
|
||||
energy_drain = 1000
|
||||
tele_precision = 1
|
||||
|
||||
|
||||
////////////////////////////////////////////// WORMHOLE GENERATOR //////////////////////////////////////////
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/wormhole_generator
|
||||
name = "mounted wormhole generator"
|
||||
desc = "An exosuit module that allows generating of small quasi-stable wormholes."
|
||||
icon_state = "mecha_wholegen"
|
||||
origin_tech = "bluespace=4;magnets=4;plasmatech=2"
|
||||
equip_cooldown = 50
|
||||
energy_drain = 300
|
||||
range = MECHA_RANGED
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/wormhole_generator/action(atom/target)
|
||||
if(!action_checks(target) || !is_teleport_allowed(loc.z))
|
||||
return
|
||||
var/list/theareas = get_areas_in_range(100, chassis)
|
||||
if(!theareas.len)
|
||||
return
|
||||
var/area/thearea = pick(theareas)
|
||||
var/list/L = list()
|
||||
var/turf/pos = get_turf(src)
|
||||
for(var/turf/T in get_area_turfs(thearea.type))
|
||||
if(!T.density && pos.z == T.z)
|
||||
var/clear = 1
|
||||
for(var/obj/O in T)
|
||||
if(O.density)
|
||||
clear = 0
|
||||
break
|
||||
if(clear)
|
||||
L+=T
|
||||
if(!L.len)
|
||||
return
|
||||
var/turf/target_turf = pick(L)
|
||||
if(!target_turf)
|
||||
return
|
||||
var/obj/effect/portal/P = new /obj/effect/portal(get_turf(target), target_turf)
|
||||
P.icon = 'icons/obj/objects.dmi'
|
||||
P.failchance = 0
|
||||
P.icon_state = "anom"
|
||||
P.name = "wormhole"
|
||||
message_admins("[key_name_admin(chassis.occupant, chassis.occupant.client)]([ADMIN_QUE(chassis.occupant,"?")]) ([ADMIN_FLW(chassis.occupant,"FLW")]) used a Wormhole Generator in ([loc.x],[loc.y],[loc.z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[loc.x];Y=[loc.y];Z=[loc.z]'>JMP</a>)",0,1)
|
||||
log_game("[key_name(chassis.occupant)] used a Wormhole Generator in ([loc.x],[loc.y],[loc.z])")
|
||||
src = null
|
||||
spawn(rand(150,300))
|
||||
qdel(P)
|
||||
return 1
|
||||
|
||||
/////////////////////////////////////// GRAVITATIONAL CATAPULT ///////////////////////////////////////////
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/gravcatapult
|
||||
@@ -243,18 +196,20 @@
|
||||
set_ready_state(1)
|
||||
return
|
||||
var/h_boost = health_boost
|
||||
var/repaired = 0
|
||||
var/repaired = FALSE
|
||||
if(chassis.internal_damage & MECHA_INT_SHORT_CIRCUIT)
|
||||
h_boost *= -2
|
||||
h_boost = 0
|
||||
chassis.take_damage(2, BURN) //short circuiting droids do damage
|
||||
repaired = TRUE
|
||||
else if(chassis.internal_damage && prob(15))
|
||||
for(var/int_dam_flag in repairable_damage)
|
||||
if(chassis.internal_damage & int_dam_flag)
|
||||
chassis.clearInternalDamage(int_dam_flag)
|
||||
repaired = 1
|
||||
repaired = TRUE
|
||||
break
|
||||
if(h_boost<0 || chassis.obj_integrity < chassis.max_integrity)
|
||||
if(chassis.obj_integrity < chassis.max_integrity && h_boost > 0)
|
||||
chassis.obj_integrity += min(h_boost, chassis.max_integrity-chassis.obj_integrity)
|
||||
repaired = 1
|
||||
repaired = TRUE
|
||||
if(repaired)
|
||||
if(!chassis.use_power(energy_drain))
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
@@ -77,12 +77,14 @@
|
||||
fire_sound = 'sound/weapons/laser.ogg'
|
||||
harmful = TRUE
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/disabler
|
||||
name = "\improper CH-PD Disabler"
|
||||
origin_tech = "combat=3"
|
||||
/obj/item/mecha_parts/mecha_equipment/weapon/energy/disabler
|
||||
equip_cooldown = 8
|
||||
name = "\improper CH-DS \"Peacemaker\" disabler"
|
||||
desc = "A weapon for combat exosuits. Shoots basic disablers."
|
||||
icon_state = "mecha_disabler"
|
||||
energy_drain = 30
|
||||
projectile = /obj/item/projectile/beam/disabler
|
||||
projectiles_per_shot = 2
|
||||
projectile_delay = 1
|
||||
fire_sound = 'sound/weapons/taser2.ogg'
|
||||
harmful = FALSE
|
||||
|
||||
/obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/heavy
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user