Merge remote-tracking branch 'ParadiseSS13/master' into skills_rework

This commit is contained in:
Kyep
2020-09-19 06:39:38 -07:00
534 changed files with 9837 additions and 16102 deletions
+108
View File
@@ -0,0 +1,108 @@
# dmdoc
[DOCUMENTATION]: https://codedocs.paradisestation.org/
[BYOND]: https://secure.byond.com/
[DMDOC]: https://github.com/AffectedArc07/ParaSpacemanDMM/tree/master/src/dmdoc
[DMDOC] is a documentation generator for DreamMaker, the scripting language
of the [BYOND] game engine. It produces simple static HTML files based on
documented files, macros, types, procs, and vars.
We use **dmdoc** to generate [DOCUMENTATION] for our code, and that documentation
is automatically generated and built on every new commit to the master branch
This gives new developers a clickable reference [DOCUMENTATION] they can browse to better help
gain understanding of the Paradise codebase structure and api reference.
## Documenting code on Paradise
We use block comments to document procs and classes, and we use `///` line comments
when documenting individual variables.
Documentation is not required at Paradise, but it is highly recommended that all new code be covered with DMdoc code, according to the [Specifications](#Specification)
We also recommend that when you touch older code, you document the functions that you
have touched in the process of updating that code
### Specification
A class *should* always be autodocumented, and all public functions *should* be documented
All class level defined variables *should* be documented
Internal functions *can* be documented, but may not be
A public function is any function that a developer might reasonably call while using
or interacting with your object. Internal functions are helper functions that your
public functions rely on to implement logic
### Documenting a proc
When documenting a proc, we give a short one line description (as this is shown
next to the proc definition in the list of all procs for a type or global
namespace), then a longer paragraph which will be shown when the user clicks on
the proc to jump to it's definition
```
/**
* Short description of the proc
*
* Longer detailed paragraph about the proc
* including any relevant detail
* Arguments:
* * arg1 - Relevance of this argument
* * arg2 - Relevance of this argument
*/
```
### Documenting a class
We first give the name of the class as a header, this can be omitted if the name is
just going to be the typepath of the class, as dmdoc uses that by default
Then we give a short oneline description of the class
Finally we give a longer multi paragraph description of the class and it's details
```
/**
* # Classname (Can be omitted if it's just going to be the typepath)
*
* The short overview
*
* A longer
* paragraph of functionality about the class
* including any assumptions/special cases
*
*/
```
### Documenting a variable/define
Give a short explanation of what the variable, in the context of the class, or define is.
```
/// Type path of item to go in suit slot
var/suit = null
```
## Module level description of code
Modules are the best way to describe the structure/intent of a package of code
where you don't want to be tied to the formal layout of the class structure.
On Paradise we do this by adding markdown files inside the `code` directory
that will also be rendered and added to the modules tree. The structure for
these is deliberately not defined, so you can be as freeform and as wheeling as
you would like.
[Here is a representative example of what you might write](https://codedocs.paradisestation.org/code/modules/keybindings/readme.html)
## Special variables
You can use certain special template variables in DM DOC comments and they will be expanded
```
[DEFINE_NAME] - Expands to a link to the define definition if documented
[/mob] - Expands to a link to the docs for the /mob class
[/mob/proc/Dizzy] - Expands to a link that will take you to the /mob class and anchor you to the dizzy proc docs
[/mob/var/stat] - Expands to a link that will take you to the /mob class and anchor you to the stat var docs
```
You can customise the link name by using `[link name][link shorthand].`
eg. `[see more about dizzy here] [/mob/proc/Dizzy]`
This is very useful to quickly link to other parts of the autodoc code to expand
upon a comment made, or reasoning about code
+32
View File
@@ -0,0 +1,32 @@
name: Generate Documentation
on:
schedule:
- cron: "0 0 * * *" # Every day at the very start of the day
jobs:
generate_docs:
name: 'Generate Documentation'
runs-on: ubuntu-18.04
steps:
- name: 'Update Branch'
uses: actions/checkout@v2
with:
fetch-depth: 1
ref: master
- name: 'Generate Documentation'
run: |
./tools/github-actions/doc-generator
touch dmdoc/.nojekyll
# Nojekyll is important to disable jeykll syntax, which can mess with files that start with underscores
- name: 'Deploy Documentation'
uses: crazy-max/ghaction-github-pages@v2
with:
keep_history: false
build_dir: dmdoc
jekyll: false
fqdn: codedocs.paradisestation.org
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+6
View File
@@ -0,0 +1,6 @@
[langserver]
dreamchecker = true
[code_standards]
disallow_relative_type_definitions = true
disallow_relative_proc_definitions = true
+20 -74
View File
@@ -40663,40 +40663,16 @@
/turf/simulated/wall/r_wall,
/area/engine/break_room)
"byz" = (
/obj/structure/cable{
icon_state = "0-4";
d2 = 4
},
/obj/machinery/modular_computer/console/preset/engineering,
/obj/machinery/status_display{
pixel_x = -32
},
/obj/machinery/computer/security/engineering,
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "caution"
},
/area/atmos)
"byA" = (
/obj/structure/cable{
d1 = 4;
d2 = 8;
icon_state = "4-8";
tag = ""
},
/obj/structure/chair/office/dark{
dir = 8
},
/turf/simulated/floor/plasteel{
dir = 8;
icon_state = "neutralfull"
},
/area/atmos)
"byB" = (
/obj/structure/cable{
d1 = 1;
d2 = 8;
icon_state = "1-8"
},
/obj/structure/cable{
d1 = 1;
d2 = 4;
@@ -41937,12 +41913,7 @@
icon_state = "1-2";
tag = ""
},
/obj/machinery/modular_computer/console/preset/command,
/obj/structure/cable{
icon_state = "0-2";
pixel_y = 1;
d2 = 2
},
/obj/machinery/computer/shuttle/mining,
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "darkpurple"
@@ -51367,18 +51338,6 @@
icon_state = "dark"
},
/area/engine/break_room)
"bQf" = (
/obj/structure/cable{
d1 = 4;
d2 = 8;
icon_state = "4-8";
pixel_x = 0
},
/turf/simulated/floor/plasteel{
icon_state = "neutral";
dir = 4
},
/area/crew_quarters/chief)
"bQg" = (
/obj/structure/cable{
d1 = 1;
@@ -51405,11 +51364,6 @@
},
/obj/structure/table/reinforced,
/obj/item/clipboard,
/obj/structure/cable{
d1 = 1;
d2 = 8;
icon_state = "1-8"
},
/obj/item/toy/figure/ce,
/turf/simulated/floor/plasteel{
dir = 8;
@@ -54089,12 +54043,6 @@
/area/crew_quarters/chief)
"bUq" = (
/obj/machinery/hologram/holopad,
/obj/structure/cable{
d1 = 4;
d2 = 8;
icon_state = "4-8";
pixel_x = 0
},
/obj/effect/decal/warning_stripes/yellow/hollow,
/turf/simulated/floor/plasteel{
dir = 8;
@@ -55398,11 +55346,6 @@
},
/area/crew_quarters/chief)
"bWl" = (
/obj/machinery/modular_computer/console/preset/engineering,
/obj/structure/cable{
icon_state = "0-4";
d2 = 4
},
/obj/machinery/keycard_auth{
pixel_x = -24
},
@@ -55420,6 +55363,7 @@
pixel_y = -8;
req_access_txt = "11"
},
/obj/machinery/computer/security/engineering,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -60477,6 +60421,9 @@
icon_state = "4-8";
tag = ""
},
/obj/machinery/computer/monitor{
name = "Grid Power Monitoring Computer"
},
/turf/simulated/floor/plasteel{
dir = 5;
icon_state = "dark";
@@ -61203,10 +61150,6 @@
/obj/machinery/tcomms/core/station,
/turf/simulated/floor/bluegrid,
/area/tcommsat/chamber)
"cgA" = (
/obj/machinery/ntnet_relay,
/turf/simulated/floor/bluegrid,
/area/tcommsat/chamber)
"cgB" = (
/obj/machinery/camera{
c_tag = "Singularity NorthEast";
@@ -62511,7 +62454,6 @@
dir = 1;
network = list("Engineering","SS13")
},
/obj/machinery/modular_computer/console/preset/engineering,
/obj/machinery/firealarm{
dir = 8;
pixel_x = -26;
@@ -62521,6 +62463,9 @@
icon_state = "0-4";
d2 = 4
},
/obj/machinery/computer/monitor{
name = "Grid Power Monitoring Computer"
},
/turf/simulated/floor/plasteel{
dir = 5;
icon_state = "dark";
@@ -88629,7 +88574,7 @@
/area/maintenance/starboard)
"dey" = (
/obj/structure/table/wood,
/obj/item/modular_computer/tablet/preset/cheap,
/obj/effect/spawner/lootdrop/maintenance,
/turf/simulated/floor/plasteel{
icon_state = "wood"
},
@@ -97237,7 +97182,6 @@
},
/area/crew_quarters/hor)
"dtZ" = (
/obj/structure/cable,
/obj/structure/cable{
d1 = 1;
d2 = 4;
@@ -97247,7 +97191,6 @@
pixel_x = 0;
pixel_y = -30
},
/obj/machinery/modular_computer/console/preset/research,
/turf/simulated/floor/plasteel{
dir = 2;
icon_state = "whitepurplecorner"
@@ -114776,6 +114719,9 @@
"qrT" = (
/turf/simulated/wall/r_wall,
/area/tcommsat/chamber)
"rSI" = (
/turf/simulated/floor/bluegrid,
/area/tcommsat/chamber)
"udT" = (
/obj/structure/chair/comfy/shuttle{
dir = 8
@@ -123162,9 +123108,9 @@ bVO
bPI
bNM
qrT
eaH
rSI
ceL
cgu
eaH
qrT
qrT
bkt
@@ -123934,7 +123880,7 @@ bXJ
bZh
caX
ccW
ccW
cgu
ccW
chW
qrT
@@ -124704,9 +124650,9 @@ bVT
bXL
bNM
qrT
hng
rSI
vzz
cgA
hng
qrT
qrT
bkt
@@ -138061,7 +138007,7 @@ bIr
bKe
bMh
bOa
bQf
bOa
bOa
bUh
bWk
@@ -142420,7 +142366,7 @@ btt
buD
bvO
ban
byA
bzY
bzY
bBK
aOg
@@ -38185,7 +38185,7 @@
d2 = 2;
icon_state = "1-2"
},
/obj/machinery/modular_computer/console/preset/command,
/obj/machinery/computer/card,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -96408,10 +96408,7 @@
d2 = 2;
icon_state = "1-2"
},
/turf/simulated/floor/plasteel/dark,
/area/tcommsat/server)
"gIG" = (
/obj/machinery/ntnet_relay,
/obj/machinery/tcomms/core/station,
/turf/simulated/floor/bluegrid,
/area/tcommsat/server)
"gRw" = (
@@ -96643,10 +96640,6 @@
},
/turf/space,
/area/solar/starboard)
"rUQ" = (
/obj/machinery/tcomms/core/station,
/turf/simulated/floor/bluegrid,
/area/tcommsat/server)
"sjF" = (
/obj/structure/window/reinforced{
dir = 1
@@ -151146,7 +151139,7 @@ bDf
bFi
bIz
bKl
gIG
bOa
bOb
odO
bKl
@@ -152174,7 +152167,7 @@ bDj
bFm
bRo
bKl
rUQ
bOa
dRN
kwJ
bKl
@@ -167,7 +167,7 @@
/turf/simulated/floor/wood,
/area/ruin/powered/snow_cabin)
"aL" = (
/obj/structure/displaycase/captain,
/obj/mecha/working/ripley/mining,
/turf/simulated/floor/wood,
/area/ruin/powered/snow_cabin)
"aM" = (
@@ -392,12 +392,6 @@
/obj/structure/filingcabinet,
/turf/simulated/floor/pod/dark,
/area/ruin/powered/snow_biodome)
"UM" = (
/obj/machinery/computer/monitor/secret{
dir = 1
},
/turf/simulated/floor/pod/dark,
/area/ruin/powered/snow_biodome)
"Wg" = (
/turf/simulated/wall/r_wall,
/area/ruin/powered/snow_biodome)
@@ -484,7 +478,7 @@ HP
tl
PK
gz
UM
HP
Wg
ak
ak
@@ -68,7 +68,6 @@
"an" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDNW";
invisibility = 100;
location = "SDNE"
},
/turf/simulated/floor/plating/asteroid/airless,
@@ -292,15 +291,13 @@
"aU" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDSW";
invisibility = 100;
location = "SDNW"
},
/turf/simulated/floor/plating/asteroid/airless,
/area/syndicate_depot/outer)
"aV" = (
/obj/machinery/light{
dir = 4;
icon_state = "tube1"
dir = 4
},
/turf/simulated/floor/plating/asteroid/airless,
/area/syndicate_depot/outer)
@@ -429,8 +426,7 @@
/area/syndicate_depot/core)
"bo" = (
/obj/machinery/light{
dir = 4;
icon_state = "tube1"
dir = 4
},
/obj/effect/spawner/random_spawners/syndicate/loot,
/turf/simulated/floor/plasteel{
@@ -512,7 +508,6 @@
id = "syndi_depot_rear";
idle_power_usage = 0;
name = "mysterious button";
normaldoorcontrol = 0;
pixel_x = 24;
use_power = 0
},
@@ -663,8 +658,8 @@
/obj/machinery/turretid/syndicate{
name = "external turret controls";
pixel_x = -32;
pixel_y = 0;
req_access = list(150)
req_access = null;
req_access_txt = "150"
},
/turf/simulated/floor/plasteel{
icon_state = "dark"
@@ -745,9 +740,8 @@
/area/syndicate_depot/core)
"ce" = (
/obj/machinery/light/small{
tag = "icon-bulb1 (EAST)";
icon_state = "bulb1";
dir = 4
dir = 4;
tag = "icon-bulb1 (EAST)"
},
/turf/simulated/floor/mineral/silver,
/area/syndicate_depot/core)
@@ -757,7 +751,6 @@
id = "syndi_depot_rear";
idle_power_usage = 0;
name = "mysterious button";
normaldoorcontrol = 0;
use_power = 0
},
/obj/structure/sign/poster/contraband/syndicate_recruitment,
@@ -774,8 +767,8 @@
/area/syndicate_depot/core)
"ci" = (
/obj/structure/cable{
icon_state = "0-2";
d2 = 2
d2 = 2;
icon_state = "0-2"
},
/obj/machinery/power/smes/upgraded{
charge = 5e+006;
@@ -845,7 +838,6 @@
"cr" = (
/obj/structure/sink{
dir = 4;
icon_state = "sink";
pixel_x = 12
},
/turf/simulated/floor/mineral/silver,
@@ -1154,7 +1146,6 @@
"dc" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDSE";
invisibility = 100;
location = "SDSW"
},
/turf/simulated/floor/plating/asteroid/airless,
@@ -1179,7 +1170,6 @@
"df" = (
/obj/machinery/navbeacon/invisible{
codes_txt = "patrol;next_patrol=SDNE";
invisibility = 100;
location = "SDSE"
},
/turf/simulated/floor/plating/asteroid/airless,
+10 -38
View File
@@ -26723,10 +26723,6 @@
dir = 4
},
/area/security/nuke_storage)
"aXS" = (
/obj/machinery/vending/modularpc,
/turf/simulated/floor/plasteel,
/area/storage/primary)
"aXU" = (
/obj/item/flag/mime,
/obj/machinery/power/apc{
@@ -26847,23 +26843,13 @@
},
/area/crew_quarters/bar)
"aYf" = (
/obj/machinery/modular_computer/console/preset/command,
/obj/structure/cable{
icon_state = "0-2";
pixel_y = 1;
d2 = 2
},
/obj/machinery/computer/card,
/turf/simulated/floor/plasteel{
dir = 10;
icon_state = "green"
},
/area/bridge)
"aYg" = (
/obj/structure/cable{
d1 = 1;
d2 = 2;
icon_state = "1-2"
},
/turf/simulated/floor/plasteel{
dir = 1;
icon_state = "greencorner"
@@ -38277,11 +38263,6 @@
/turf/simulated/floor/plasteel,
/area/bridge)
"bup" = (
/obj/structure/cable{
d1 = 1;
d2 = 2;
icon_state = "1-2"
},
/obj/machinery/atmospherics/unary/vent_pump/on,
/turf/simulated/floor/plasteel,
/area/bridge)
@@ -38894,11 +38875,6 @@
icon_state = "4-8";
tag = ""
},
/obj/structure/cable{
d1 = 1;
d2 = 4;
icon_state = "1-4"
},
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/turf/simulated/floor/plasteel,
/area/bridge)
@@ -95344,6 +95320,11 @@
icon_state = "vault"
},
/area/shuttle/escape)
"kIR" = (
/obj/structure/lattice/catwalk,
/obj/machinery/atmospherics/pipe/simple/hidden/yellow,
/turf/space,
/area/space/nearstation)
"kLF" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 9
@@ -95977,11 +95958,6 @@
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,
/turf/simulated/wall,
/area/crew_quarters/dorms)
"rOX" = (
/obj/machinery/atmospherics/pipe/simple/hidden/yellow,
/obj/machinery/ntnet_relay,
/turf/simulated/floor/plasteel/dark,
/area/tcommsat/chamber)
"rSv" = (
/obj/structure/shuttle/engine/propulsion{
dir = 8;
@@ -96028,10 +96004,6 @@
icon_state = "floor4"
},
/area/shuttle/administration)
"sag" = (
/obj/machinery/atmospherics/pipe/simple/hidden/supply,
/turf/simulated/floor/plasteel/dark,
/area/tcommsat/chamber)
"sbp" = (
/turf/simulated/shuttle/wall{
icon_state = "wall3"
@@ -115856,7 +115828,7 @@ aKb
aNx
aVi
aWt
aXS
aXQ
aZr
bbp
bdk
@@ -131629,7 +131601,7 @@ dmW
aaa
aab
aaa
iUc
aaa
iUc
iUc
iUc
@@ -131886,10 +131858,10 @@ ddC
doE
ddM
ddO
kIR
oOZ
dQC
fAw
rOX
mkE
dpe
dpl
@@ -132144,8 +132116,8 @@ dmB
bfu
dnT
dpf
iUc
rTy
sag
wbr
hyv
dpd
+7 -42
View File
@@ -4296,55 +4296,20 @@
dir = 2
},
/area/centcom/control)
"mE" = (
/obj/structure/flora/ausbushes/lavendergrass,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
"mF" = (
/obj/structure/flora/ausbushes/stalkybush,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
"mG" = (
/obj/structure/flora/ausbushes/pointybush,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
"mH" = (
/obj/structure/flora/ausbushes/ywflowers,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
"mI" = (
/obj/structure/flora/ausbushes/brflowers,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
"mJ" = (
/obj/structure/flora/ausbushes/sparsegrass,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
/area/centcom/control)
"mK" = (
/obj/structure/flora/ausbushes/reedbush,
/turf/unsimulated/floor{
icon_state = "grass1";
name = "grass"
},
/area/centcom/specops)
/area/centcom/control)
"mL" = (
/turf/unsimulated/floor{
dir = 1;
@@ -36255,7 +36220,7 @@ lH
lH
mu
su
mF
mZ
mY
su
nD
@@ -36512,7 +36477,7 @@ mc
lH
lH
su
mE
nd
mX
su
nD
@@ -36769,7 +36734,7 @@ mc
lH
lH
su
mH
mY
na
su
nD
@@ -37026,7 +36991,7 @@ lH
lH
lH
su
mG
WW
mZ
su
nD
@@ -37283,7 +37248,7 @@ lH
mk
mw
su
mJ
na
ne
su
nD
+9 -1
View File
@@ -173,6 +173,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new())
add_fingerprint(user)
var/unsafe_wrenching = FALSE
var/safefromgusts = FALSE
var/I = int_air ? int_air.return_pressure() : 0
var/E = env_air ? env_air.return_pressure() : 0
var/internal_pressure = I - E
@@ -190,9 +191,16 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new())
"<span class='italics'>You hear ratchet.</span>")
investigate_log("was <span class='warning'>REMOVED</span> by [key_name(usr)]", "atmos")
for(var/obj/item/clothing/shoes/magboots/usermagboots in user.get_equipped_items())
if(usermagboots.gustprotection && usermagboots.magpulse)
safefromgusts = TRUE
//You unwrenched a pipe full of pressure? let's splat you into the wall silly.
if(unsafe_wrenching)
unsafe_pressure_release(user,internal_pressure)
if(safefromgusts)
to_chat(user, "<span class='italics'>Your magboots cling to the floor as a great burst of wind bellows against you.</span>")
else
unsafe_pressure_release(user,internal_pressure)
deconstruct(TRUE)
else
return ..()
@@ -137,51 +137,56 @@
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/passive_gate/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/binary/passive_gate/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 385, 115, state = state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
ui.open()
/obj/machinery/atmospherics/binary/passive_gate/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
/obj/machinery/atmospherics/binary/passive_gate/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"rate" = round(target_pressure),
"max_rate" = MAX_OUTPUT_PRESSURE,
"gas_unit" = "kPa",
"step" = 10 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
)
return data
/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
if("max_rate")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_rate")
target_pressure = 0
. = TRUE
if("custom_rate")
target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/binary/passive_gate/proc/toggle()
if(powered())
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure))
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
update_icon()
SSnanoui.update_uis(src)
update_icon()
/obj/machinery/atmospherics/binary/passive_gate/attackby(obj/item/W, mob/user, params)
if(!istype(W, /obj/item/wrench))
@@ -192,51 +192,51 @@ Thus, the two variables affect pump operation are set in New():
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/binary/pump/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 385, 115, state = state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
ui.open()
/obj/machinery/atmospherics/binary/pump/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
/obj/machinery/atmospherics/binary/pump/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"rate" = round(target_pressure),
"max_rate" = MAX_OUTPUT_PRESSURE,
"gas_unit" = "kPa",
"step" = 10 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
)
return data
/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
/obj/machinery/atmospherics/binary/pump/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure))
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
update_icon()
SSnanoui.update_uis(src)
if("max_rate")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_rate")
target_pressure = 0
. = TRUE
if("custom_rate")
target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/binary/pump/power_change()
var/old_stat = stat
@@ -188,51 +188,51 @@ Thus, the two variables affect pump operation are set in New():
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/volume_pump/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/binary/volume_pump/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/binary/volume_pump/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 310, 115, state = state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state)
ui.open()
/obj/machinery/atmospherics/binary/volume_pump/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["rate"] = round(transfer_rate)
data["max_rate"] = round(MAX_TRANSFER_RATE)
/obj/machinery/atmospherics/binary/volume_pump/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"rate" = round(transfer_rate),
"max_rate" = round(MAX_TRANSFER_RATE),
"gas_unit" = "L/s",
"step" = 1 // This is for the TGUI <NumberInput> step. It's here since multiple pumps share the same UI, but need different values.
)
return data
/obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list)
/obj/machinery/atmospherics/binary/volume_pump/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["rate"])
var/rate = href_list["rate"]
if(rate == "max")
rate = MAX_TRANSFER_RATE
. = TRUE
else if(rate == "input")
rate = input("New transfer rate (0-[MAX_TRANSFER_RATE] L/s):", name, transfer_rate) as num|null
if(!isnull(rate))
. = TRUE
else if(text2num(rate) != null)
rate = text2num(rate)
. = TRUE
if(.)
transfer_rate = clamp(rate, 0, MAX_TRANSFER_RATE)
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
update_icon()
SSnanoui.update_uis(src)
if("max_rate")
transfer_rate = MAX_TRANSFER_RATE
. = TRUE
if("min_rate")
transfer_rate = 0
. = TRUE
if("custom_rate")
transfer_rate = clamp(text2num(params["rate"]), 0 , MAX_TRANSFER_RATE)
. = TRUE
if(.)
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/binary/volume_pump/power_change()
var/old_stat = stat
@@ -1,94 +0,0 @@
//--------------------------------------------
// Omni device port types
//--------------------------------------------
#define ATM_NONE 0
#define ATM_INPUT 1
#define ATM_OUTPUT 2
#define ATM_O2 3
#define ATM_N2 4
#define ATM_CO2 5
#define ATM_P 6 //Plasma
#define ATM_N2O 7
//--------------------------------------------
// Omni port datum
//
// Used by omni devices to manage connections
// to other atmospheric objects.
//--------------------------------------------
/datum/omni_port
var/obj/machinery/atmospherics/omni/master
var/dir
var/update = 1
var/mode = 0
var/concentration = 0
var/con_lock = 0
var/transfer_moles = 0
var/datum/gas_mixture/air
var/obj/machinery/atmospherics/node
var/datum/pipeline/parent
/datum/omni_port/New(var/obj/machinery/atmospherics/omni/M, var/direction = NORTH)
..()
dir = direction
if(istype(M))
master = M
air = new
air.volume = 200
/datum/omni_port/proc/connect()
if(node)
return
master.atmos_init()
if(node)
node.atmos_init()
node.addMember(master)
master.build_network()
/datum/omni_port/proc/disconnect()
if(node)
node.disconnect(master)
node = null
master.nullifyPipenet(parent)
//--------------------------------------------
// Need to find somewhere else for these
//--------------------------------------------
//returns a text string based on the direction flag input
// if capitalize is true, it will return the string capitalized
// otherwise it will return the direction string in lower case
/proc/dir_name(var/dir, var/capitalize = 0)
var/string = null
switch(dir)
if(NORTH)
string = "North"
if(SOUTH)
string = "South"
if(EAST)
string = "East"
if(WEST)
string = "West"
if(!capitalize && string)
string = lowertext(string)
return string
//returns a direction flag based on the string passed to it
// case insensitive
/proc/dir_flag(var/dir)
dir = lowertext(dir)
switch(dir)
if("north")
return NORTH
if("south")
return SOUTH
if("east")
return EAST
if("west")
return WEST
else
return 0
@@ -1,273 +0,0 @@
//--------------------------------------------
// Gas filter - omni variant
//--------------------------------------------
/obj/machinery/atmospherics/omni/filter
name = "omni gas filter"
icon_state = "map_filter"
var/list/o_filters = new()
var/datum/omni_port/input
var/datum/omni_port/output
/obj/machinery/atmospherics/omni/filter/Destroy()
input = null
output = null
o_filters.Cut()
return ..()
/obj/machinery/atmospherics/omni/filter/sort_ports()
for(var/datum/omni_port/P in ports)
if(P.update)
if(output == P)
output = null
if(input == P)
input = null
if(o_filters.Find(P))
o_filters -= P
P.air.volume = 200
switch(P.mode)
if(ATM_INPUT)
input = P
if(ATM_OUTPUT)
output = P
if(ATM_O2 to ATM_N2O)
o_filters += P
/obj/machinery/atmospherics/omni/filter/error_check()
if(!input || !output || !o_filters)
return 1
if(o_filters.len < 1 || o_filters.len > 2) //requires 1 or 2 o_filters ~otherwise why are you using a filter?
return 1
return 0
/obj/machinery/atmospherics/omni/filter/process_atmos()
..()
if(!on)
return 0
if(!input || !output)
return 0
var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference
var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug*
var/output_pressure = output_air.return_pressure()
if(output_pressure >= target_pressure)
return 1
for(var/datum/omni_port/P in o_filters)
if(P.air.return_pressure() >= target_pressure)
return 1
var/pressure_delta = target_pressure - output_pressure
if(input_air.return_temperature() > 0)
input.transfer_moles = pressure_delta * output_air.volume / (input_air.return_temperature() * R_IDEAL_GAS_EQUATION)
if(input.transfer_moles > 0)
var/datum/gas_mixture/removed = input_air.remove(input.transfer_moles)
if(!removed)
return 1
for(var/datum/omni_port/P in o_filters)
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.return_temperature()
switch(P.mode)
if(ATM_O2)
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(ATM_N2)
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(ATM_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(ATM_P)
filtered_out.toxins = removed.toxins
removed.toxins = 0
filtered_out.agent_b = removed.agent_b
removed.agent_b = 0
if(ATM_N2O)
filtered_out.sleeping_agent = removed.sleeping_agent
removed.sleeping_agent = 0
else
filtered_out = null
P.air.merge(filtered_out)
P.parent.update = 1
output_air.merge(removed)
output.parent.update = 1
input.transfer_moles = 0
input.parent.update = 1
return 1
/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
usr.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330)
ui.open()
/obj/machinery/atmospherics/omni/filter/ui_data(mob/user, datum/topic_state/state)
var/data[0]
data["power"] = on
data["config"] = configuring
var/portData[0]
for(var/datum/omni_port/P in ports)
if(!configuring && P.mode == 0)
continue
var/input = 0
var/output = 0
var/filter = 1
var/f_type = null
switch(P.mode)
if(ATM_INPUT)
input = 1
filter = 0
if(ATM_OUTPUT)
output = 1
filter = 0
if(ATM_O2 to ATM_N2O)
f_type = mode_send_switch(P.mode)
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
"input" = input, \
"output" = output, \
"filter" = filter, \
"f_type" = f_type)
if(portData.len)
data["ports"] = portData
if(output)
data["pressure"] = target_pressure
return data
/obj/machinery/atmospherics/omni/filter/proc/mode_send_switch(var/mode = ATM_NONE)
switch(mode)
if(ATM_O2)
return "Oxygen"
if(ATM_N2)
return "Nitrogen"
if(ATM_CO2)
return "Carbon Dioxide"
if(ATM_P)
return "Plasma" //*cough* Plasma *cough*
if(ATM_N2O)
return "Nitrous Oxide"
else
return null
/obj/machinery/atmospherics/omni/filter/Topic(href, href_list)
if(..())
return 1
switch(href_list["command"])
if("power")
if(!configuring)
on = !on
else
on = 0
if("configure")
configuring = !configuring
if(configuring)
on = 0
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !on)
switch(href_list["command"])
if("set_pressure")
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
target_pressure = between(0, new_pressure, 4500)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"]))
if("switch_filter")
var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Plasma", "Nitrous Oxide")
switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter))
update_icon()
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/filter/proc/mode_return_switch(var/mode)
switch(mode)
if("Oxygen")
return ATM_O2
if("Nitrogen")
return ATM_N2
if("Carbon Dioxide")
return ATM_CO2
if("Plasma")
return ATM_P
if("Nitrous Oxide")
return ATM_N2O
if("in")
return ATM_INPUT
if("out")
return ATM_OUTPUT
if("None")
return ATM_NONE
else
return null
/obj/machinery/atmospherics/omni/filter/proc/switch_filter(var/dir, var/mode)
//check they aren't trying to disable the input or output ~this can only happen if they hack the cached tmpl file
for(var/datum/omni_port/P in ports)
if(P.dir == dir)
if(P.mode == ATM_INPUT || P.mode == ATM_OUTPUT)
return
switch_mode(dir, mode)
/obj/machinery/atmospherics/omni/filter/proc/switch_mode(var/port, var/mode)
if(mode == null || !port)
return
var/datum/omni_port/target_port = null
var/list/other_ports = new()
for(var/datum/omni_port/P in ports)
if(P.dir == port)
target_port = P
else
other_ports += P
var/previous_mode = null
if(target_port)
previous_mode = target_port.mode
target_port.mode = mode
if(target_port.mode != previous_mode)
handle_port_change(target_port)
else
return
else
return
for(var/datum/omni_port/P in other_ports)
if(P.mode == mode)
var/old_mode = P.mode
P.mode = previous_mode
if(P.mode != old_mode)
handle_port_change(P)
update_ports()
/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P)
switch(P.mode)
if(ATM_NONE)
initialize_directions &= ~P.dir
P.disconnect()
else
initialize_directions |= P.dir
P.connect()
P.update = 1
@@ -1,291 +0,0 @@
//--------------------------------------------
// Gas mixer - omni variant
//--------------------------------------------
/obj/machinery/atmospherics/omni/mixer
name = "omni gas mixer"
icon_state = "map_mixer"
var/list/inputs = new()
var/datum/omni_port/output
//setup tags for initial concentration values (must be decimal)
var/tag_north_con
var/tag_south_con
var/tag_east_con
var/tag_west_con
/obj/machinery/atmospherics/omni/mixer/New()
..()
if(mapper_set())
var/con = 0
for(var/datum/omni_port/P in ports)
switch(P.dir)
if(NORTH)
if(tag_north_con && tag_north == 1)
P.concentration = tag_north_con
con += max(0, tag_north_con)
if(SOUTH)
if(tag_south_con && tag_south == 1)
P.concentration = tag_south_con
con += max(0, tag_south_con)
if(EAST)
if(tag_east_con && tag_east == 1)
P.concentration = tag_east_con
con += max(0, tag_east_con)
if(WEST)
if(tag_west_con && tag_west == 1)
P.concentration = tag_west_con
con += max(0, tag_west_con)
//mappers who are bad at maths will be punished (total concentration must be 100%)
if(con != 1)
tag_north_con = null
tag_south_con = null
tag_east_con = null
tag_west_con = null
/obj/machinery/atmospherics/omni/mixer/Destroy()
inputs.Cut()
output = null
return ..()
/obj/machinery/atmospherics/omni/mixer/sort_ports()
for(var/datum/omni_port/P in ports)
if(P.update)
if(output == P)
output = null
if(inputs.Find(P))
inputs -= P
P.air.volume = 200
switch(P.mode)
if(ATM_INPUT)
inputs += P
if(ATM_OUTPUT)
output = P
if(!mapper_set())
for(var/datum/omni_port/P in inputs)
P.concentration = 1 / max(1, inputs.len)
if(output)
output.air.volume *= 0.75 * inputs.len
output.concentration = 1
/obj/machinery/atmospherics/omni/mixer/proc/mapper_set()
return (tag_north_con || tag_south_con || tag_east_con || tag_west_con)
/obj/machinery/atmospherics/omni/mixer/error_check()
if(!output || !inputs)
return 1
if(inputs.len < 2 || inputs.len > 3) //requires 2 or 3 inputs ~otherwise why are you using a mixer?
return 1
return 0
/obj/machinery/atmospherics/omni/mixer/process_atmos()
..()
if(!on)
return 0
var/datum/gas_mixture/output_air = output.air
var/output_pressure = output_air.return_pressure()
if(output_pressure >= target_pressure * 0.999)
//No need to mix if target is already full! - 0.1% margin of error so we minimize processing minor gas volumes
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_pressure
for(var/datum/omni_port/P in inputs)
if(P.air.return_temperature() > 0)
P.transfer_moles = (P.concentration * pressure_delta) * output_air.return_volume() / (P.air.return_temperature() * R_IDEAL_GAS_EQUATION)
var/ratio_check = null
for(var/datum/omni_port/P in inputs)
if(!P.transfer_moles)
return 1
if(P.air.total_moles() < P.transfer_moles)
ratio_check = 1
continue
if(ratio_check)
var/list/ratio_list = new()
for(var/datum/omni_port/P in inputs)
ratio_list.Add(P.air.total_moles() / P.transfer_moles)
var/ratio = min(ratio_list)
for(var/datum/omni_port/P in inputs)
P.transfer_moles *= ratio
for(var/datum/omni_port/P in inputs)
if(P.transfer_moles > 0)
output_air.merge(P.air.remove(P.transfer_moles))
P.parent.update = 1
P.transfer_moles = 0
output.parent.update = 1
return 1
/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
usr.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330)
ui.open()
/obj/machinery/atmospherics/omni/mixer/ui_data(mob/user, datum/topic_state/state)
var/data[0]
data["power"] = on
data["config"] = configuring
var/portData[0]
for(var/datum/omni_port/P in ports)
if(!configuring && P.mode == 0)
continue
var/input = 0
var/output = 0
switch(P.mode)
if(ATM_INPUT)
input = 1
if(ATM_OUTPUT)
output = 1
portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \
"concentration" = P.concentration, \
"input" = input, \
"output" = output, \
"con_lock" = P.con_lock)
if(portData.len)
data["ports"] = portData
if(output)
data["pressure"] = target_pressure
return data
/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list)
if(..())
return 1
switch(href_list["command"])
if("power")
if(!configuring)
on = !on
else
on = 0
if("configure")
configuring = !configuring
if(configuring)
on = 0
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !on)
switch(href_list["command"])
if("set_pressure")
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
target_pressure = between(0, new_pressure, 4500)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), href_list["mode"])
if("switch_con")
change_concentration(dir_flag(href_list["dir"]))
if("switch_conlock")
con_lock(dir_flag(href_list["dir"]))
update_icon()
SSnanoui.update_uis(src)
return
/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE)
if(mode != ATM_INPUT && mode != ATM_OUTPUT)
switch(mode)
if("in")
mode = ATM_INPUT
if("out")
mode = ATM_OUTPUT
else
mode = ATM_NONE
for(var/datum/omni_port/P in ports)
var/old_mode = P.mode
if(P.dir == port)
switch(mode)
if(ATM_INPUT)
if(P.mode == ATM_OUTPUT)
return
P.mode = mode
if(ATM_OUTPUT)
P.mode = mode
if(ATM_NONE)
if(P.mode == ATM_OUTPUT)
return
if(P.mode == ATM_INPUT && inputs.len > 2)
P.mode = mode
else if(P.mode == ATM_OUTPUT && mode == ATM_OUTPUT)
P.mode = ATM_INPUT
if(P.mode != old_mode)
switch(P.mode)
if(ATM_NONE)
initialize_directions &= ~P.dir
P.disconnect()
else
initialize_directions |= P.dir
P.connect()
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH)
tag_north_con = null
tag_south_con = null
tag_east_con = null
tag_west_con = null
var/old_con = 0
var/non_locked = 0
var/remain_con = 1
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
old_con = P.concentration
else if(!P.con_lock)
non_locked++
else
remain_con -= P.concentration
//return if no adjustable ports
if(non_locked < 1)
return
var/new_con = (input(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100) as num) / 100
//cap it between 0 and the max remaining concentration
new_con = between(0, new_con, remain_con)
//new_con = min(remain_con, new_con)
//clamp remaining concentration so we don't go into negatives
remain_con = max(0, remain_con - new_con)
//distribute remaining concentration between unlocked ports evenly
remain_con /= max(1, non_locked)
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
P.concentration = new_con
else if(!P.con_lock)
P.concentration = remain_con
/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH)
for(var/datum/omni_port/P in inputs)
if(P.dir == port)
P.con_lock = !P.con_lock
@@ -1,302 +0,0 @@
//--------------------------------------------
// Base omni device
//--------------------------------------------
/obj/machinery/atmospherics/omni
name = "omni device"
icon = 'icons/atmos/omni_devices.dmi'
icon_state = "base"
use_power = IDLE_POWER_USE
initialize_directions = 0
can_unwrench = 1
var/on = 0
var/configuring = 0
var/target_pressure = ONE_ATMOSPHERE
var/tag_north = ATM_NONE
var/tag_south = ATM_NONE
var/tag_east = ATM_NONE
var/tag_west = ATM_NONE
var/overlays_on[5]
var/overlays_off[5]
var/overlays_error[2]
var/underlays_current[4]
var/list/ports = new()
/obj/machinery/atmospherics/omni/New()
..()
icon_state = "base"
ports = new()
for(var/d in GLOB.cardinal)
var/datum/omni_port/new_port = new(src, d)
switch(d)
if(NORTH)
new_port.mode = tag_north
if(SOUTH)
new_port.mode = tag_south
if(EAST)
new_port.mode = tag_east
if(WEST)
new_port.mode = tag_west
if(new_port.mode > 0)
initialize_directions |= d
ports += new_port
build_icons()
/obj/machinery/atmospherics/omni/Destroy()
for(var/datum/omni_port/P in ports)
if(P.node)
P.node.disconnect(src)
P.node = null
nullifyPipenet(P.parent)
return ..()
/obj/machinery/atmospherics/omni/atmos_init()
..()
for(var/datum/omni_port/P in ports)
if(P.node || P.mode == 0)
continue
for(var/obj/machinery/atmospherics/target in get_step(src, P.dir))
if(target.initialize_directions & get_dir(target,src))
P.node = target
break
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/update_icon()
..()
if(stat & NOPOWER)
overlays = overlays_off
on = 0
else if(error_check())
overlays = overlays_error
on = 0
else
overlays = on ? (overlays_on) : (overlays_off)
underlays = underlays_current
/obj/machinery/atmospherics/omni/proc/error_check()
return
/obj/machinery/atmospherics/omni/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/omni/attackby(var/obj/item/W as obj, var/mob/user as mob, params)
if(!istype(W, /obj/item/wrench))
return ..()
if(can_unwrench)
var/int_pressure = 0
for(var/datum/omni_port/P in ports)
int_pressure += P.air.return_pressure()
var/datum/gas_mixture/env_air = loc.return_air()
if((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
to_chat(user, "<span class='danger'>You cannot unwrench [src], it is too exerted due to internal pressure.</span>")
add_fingerprint(user)
return 1
playsound(loc, W.usesound, 50, 1)
to_chat(user, "<span class='notice'>You begin to unfasten \the [src]...</span>")
if(do_after(user, 40 * W.toolspeed, target = src))
user.visible_message( \
"[user] unfastens \the [src].", \
"<span class='notice'>You have unfastened \the [src].</span>", \
"You hear a ratchet.")
new /obj/item/pipe(loc, make_from=src)
qdel(src)
else
return ..()
/obj/machinery/atmospherics/omni/attack_hand(mob/user)
if(..())
return
add_fingerprint(usr)
ui_interact(user)
/obj/machinery/atmospherics/omni/attack_ghost(mob/user)
ui_interact(user)
/obj/machinery/atmospherics/omni/proc/build_icons()
if(!check_icon_cache())
return
var/core_icon = null
if(istype(src, /obj/machinery/atmospherics/omni/mixer))
core_icon = "mixer"
else if(istype(src, /obj/machinery/atmospherics/omni/filter))
core_icon = "filter"
else
return
//directional icons are layers 1-4, with the core icon on layer 5
if(core_icon)
overlays_off[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_on[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
overlays_error[1] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_error[2] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , "error")
/obj/machinery/atmospherics/omni/proc/update_port_icons()
if(!check_icon_cache())
return
for(var/datum/omni_port/P in ports)
if(P.update)
var/ref_layer = 0
switch(P.dir)
if(NORTH)
ref_layer = 1
if(SOUTH)
ref_layer = 2
if(EAST)
ref_layer = 3
if(WEST)
ref_layer = 4
if(!ref_layer)
continue
var/list/port_icons = select_port_icons(P)
if(port_icons)
if(P.node)
underlays_current[ref_layer] = port_icons["pipe_icon"]
else
underlays_current[ref_layer] = null
overlays_off[ref_layer] = port_icons["off_icon"]
overlays_on[ref_layer] = port_icons["on_icon"]
else
underlays_current[ref_layer] = null
overlays_off[ref_layer] = null
overlays_on[ref_layer] = null
update_icon()
/obj/machinery/atmospherics/omni/proc/select_port_icons(var/datum/omni_port/P)
if(!istype(P))
return
if(P.mode > 0)
var/ic_dir = dir_name(P.dir)
var/ic_on = ic_dir
var/ic_off = ic_dir
switch(P.mode)
if(ATM_INPUT)
ic_on += "_in_glow"
ic_off += "_in"
if(ATM_OUTPUT)
ic_on += "_out_glow"
ic_off += "_out"
if(ATM_O2 to ATM_N2O)
ic_on += "_filter"
ic_off += "_out"
ic_on = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_on)
ic_off = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_off)
var/pipe_state
var/turf/T = get_turf(src)
if(!istype(T))
return
if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 )
//pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down")
else
//pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact")
return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state)
/obj/machinery/atmospherics/omni/update_underlays()
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/omni/proc/update_ports()
sort_ports()
update_port_icons()
for(var/datum/omni_port/P in ports)
P.update = 0
/obj/machinery/atmospherics/omni/proc/sort_ports()
return
// Pipenet procs
/obj/machinery/atmospherics/omni/build_network(remove_deferral = FALSE)
for(var/datum/omni_port/P in ports)
if(!P.parent)
P.parent = new /datum/pipeline()
P.parent.build_pipeline(src)
..()
/obj/machinery/atmospherics/omni/disconnect(obj/machinery/atmospherics/reference)
for(var/datum/omni_port/P in ports)
if(reference == P.node)
if(istype(P.node, /obj/machinery/atmospherics/pipe))
qdel(P.parent)
P.node = null
update_ports()
/obj/machinery/atmospherics/omni/nullifyPipenet(datum/pipeline/P)
..()
if(!P)
return
for(var/datum/omni_port/PO in ports)
if(P == PO.parent)
PO.parent.other_airs -= PO.air
PO.parent = null
/obj/machinery/atmospherics/omni/returnPipenetAir(datum/pipeline/P)
for(var/datum/omni_port/PO in ports)
if(P == PO.parent)
return PO.air
/obj/machinery/atmospherics/omni/pipeline_expansion(datum/pipeline/P)
if(P)
for(var/datum/omni_port/PO in ports)
if(PO.parent == P)
return list(PO.node)
else
var/list/nodes = list()
for(var/datum/omni_port/PO in ports)
nodes += PO.node
return nodes
/obj/machinery/atmospherics/omni/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A)
for(var/datum/omni_port/PO in ports)
if(A == PO.node)
PO.parent = P
/obj/machinery/atmospherics/omni/returnPipenet(obj/machinery/atmospherics/A)
for(var/datum/omni_port/P in ports)
if(A == P.node)
return P.parent
/obj/machinery/atmospherics/omni/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
for(var/datum/omni_port/P in ports)
if(Old == P.parent)
P.parent = New
/obj/machinery/atmospherics/omni/process_atmos()
..()
for(var/datum/omni_port/port in ports)
if(!port.parent)
return 0
return 1
@@ -1,26 +1,39 @@
/// Nothing will be filtered.
#define FILTER_NOTHING -1
/// Plasma, and Oxygen Agent B.
#define FILTER_TOXINS 0
/// Oxygen only.
#define FILTER_OXYGEN 1
/// Nitrogen only.
#define FILTER_NITROGEN 2
/// Carbon dioxide only.
#define FILTER_CO2 3
/// Nitrous oxide only.
#define FILTER_N2O 4
/obj/machinery/atmospherics/trinary/filter
name = "gas filter"
icon = 'icons/atmos/filter.dmi'
icon_state = "map"
can_unwrench = 1
name = "gas filter"
can_unwrench = TRUE
/// The amount of pressure the filter wants to operate at.
var/target_pressure = ONE_ATMOSPHERE
var/filter_type = 0
/*
Filter types:
-1: Nothing
0: Toxins: Toxins, Oxygen Agent B
1: Oxygen: Oxygen ONLY
2: Nitrogen: Nitrogen ONLY
3: Carbon Dioxide: Carbon Dioxide ONLY
4: Sleeping Agent (N2O)
*/
var/frequency = 0
/// The type of gas we want to filter. Valid values that go here are from the `FILTER` defines at the top of the file.
var/filter_type = FILTER_NOTHING
/// The frequency of the filter. Used with `radio_connection`.
var/frequency = NONE
/// A reference to the filter's `datum/radio_frequency`.
var/datum/radio_frequency/radio_connection
/// A list of available filter options. Used with `tgui_data`.
var/list/filter_list = list(
"Nothing" = FILTER_NOTHING,
"Plasma" = FILTER_TOXINS,
"O2" = FILTER_OXYGEN,
"N2" = FILTER_NITROGEN,
"CO2" = FILTER_CO2,
"N2O" = FILTER_N2O
)
/obj/machinery/atmospherics/trinary/filter/CtrlClick(mob/living/user)
if(!istype(user) || user.incapacitated())
@@ -146,26 +159,26 @@ Filter types:
filtered_out.temperature = removed.temperature
switch(filter_type)
if(0) //removing hydrocarbons
if(FILTER_TOXINS)
filtered_out.toxins = removed.toxins
removed.toxins = 0
filtered_out.agent_b = removed.agent_b
removed.agent_b = 0
if(1) //removing O2
if(FILTER_OXYGEN)
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(2) //removing N2
if(FILTER_NITROGEN)
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(3) //removing CO2
if(FILTER_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(4)//removing N2O
if(FILTER_N2O)
filtered_out.sleeping_agent = removed.sleeping_agent
removed.sleeping_agent = 0
else
@@ -188,7 +201,7 @@ Filter types:
..()
/obj/machinery/atmospherics/trinary/filter/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/trinary/filter/attack_hand(mob/user)
if(..())
@@ -199,53 +212,56 @@ Filter types:
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/trinary/filter/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/trinary/filter/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_filter.tmpl", name, 475, 155, state = state)
ui = new(user, src, ui_key, "AtmosFilter", name, 380, 140, master_ui, state)
ui.open()
/obj/machinery/atmospherics/trinary/filter/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
data["filter_type"] = filter_type
/obj/machinery/atmospherics/trinary/filter/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"pressure" = round(target_pressure),
"max_pressure" = round(MAX_OUTPUT_PRESSURE),
"filter_type" = filter_type
)
data["filter_type_list"] = list()
for(var/label in filter_list)
data["filter_type_list"] += list(list("label" = label, "gas_type" = filter_list[label]))
return data
/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
/obj/machinery/atmospherics/trinary/filter/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if(href_list["filter"])
filter_type = text2num(href_list["filter"])
investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos")
. = TRUE
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
update_icon()
SSnanoui.update_uis(src)
if("set_filter")
filter_type = text2num(params["filter"])
investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos")
return TRUE
if("max_pressure")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_pressure")
target_pressure = 0
. = TRUE
if("custom_pressure")
target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/trinary/filter/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen))
@@ -152,7 +152,7 @@
return 1
/obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user)
if(..())
@@ -163,62 +163,62 @@
return
add_fingerprint(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/atmospherics/trinary/mixer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state)
/obj/machinery/atmospherics/trinary/mixer/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
user.set_machine(src)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_mixer.tmpl", name, 370, 165, state = state)
ui = new(user, src, ui_key, "AtmosMixer", name, 330, 165, master_ui, state)
ui.open()
/obj/machinery/atmospherics/trinary/mixer/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["pressure"] = round(target_pressure)
data["max_pressure"] = round(MAX_OUTPUT_PRESSURE)
data["node1_concentration"] = round(node1_concentration*100)
data["node2_concentration"] = round(node2_concentration*100)
/obj/machinery/atmospherics/trinary/mixer/tgui_data(mob/user)
var/list/data = list(
"on" = on,
"pressure" = round(target_pressure, 0.01),
"max_pressure" = MAX_OUTPUT_PRESSURE,
"node1_concentration" = round(node1_concentration * 100),
"node2_concentration" = round(node2_concentration * 100)
)
return data
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
/obj/machinery/atmospherics/trinary/mixer/tgui_act(action, list/params)
if(..())
return 1
return
if(href_list["power"])
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["pressure"])
var/pressure = href_list["pressure"]
if(pressure == "max")
pressure = MAX_OUTPUT_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if(href_list["node1"])
var/value = text2num(href_list["node1"])
node1_concentration = max(0, min(1, node1_concentration + value))
node2_concentration = max(0, min(1, node2_concentration - value))
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
. = TRUE
if(href_list["node2"])
var/value = text2num(href_list["node2"])
node2_concentration = max(0, min(1, node2_concentration + value))
node1_concentration = max(0, min(1, node1_concentration - value))
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
. = TRUE
switch(action)
if("power")
toggle()
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
return TRUE
update_icon()
SSnanoui.update_uis(src)
if("set_node")
if(params["node_name"] == "Node 1")
node1_concentration = clamp(round(text2num(params["concentration"]), 0.01), 0, 1)
node2_concentration = round(1 - node1_concentration, 0.01)
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
return TRUE
else
node2_concentration = clamp(round(text2num(params["concentration"]), 0.01), 0, 1)
node1_concentration = round(1 - node2_concentration, 0.01)
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
return TRUE
if("max_pressure")
target_pressure = MAX_OUTPUT_PRESSURE
. = TRUE
if("min_pressure")
target_pressure = 0
. = TRUE
if("custom_pressure")
target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE)
. = TRUE
if(.)
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
/obj/machinery/atmospherics/trinary/mixer/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen))
-17
View File
@@ -33,7 +33,6 @@
//var/list/underlays_intact[]
//var/list/pipe_underlays_exposed[]
//var/list/pipe_underlays_intact[]
var/list/omni_icons[]
/datum/pipe_icon_manager/New()
check_icons()
@@ -53,8 +52,6 @@
return manifold_icons[state + color]
if("device")
return device_icons[state]
if("omni")
return omni_icons[state]
if("underlay")
return underlays[state + dir + color]
//if("underlay_intact")
@@ -75,8 +72,6 @@
gen_manifold_icons()
if(!device_icons)
gen_device_icons()
if(!omni_icons)
gen_omni_icons()
//if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact)
if(!underlays)
gen_underlay_icons()
@@ -150,18 +145,6 @@
continue
device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_omni_icons()
if(!omni_icons)
omni_icons = new()
var/icon/omni = new('icons/atmos/omni_devices.dmi')
for(var/state in omni.IconStates())
if(!state || findtext(state, "map"))
continue
omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_underlay_icons()
if(!underlays)
+3 -3
View File
@@ -32,13 +32,13 @@
if(!R)
return 1
atom/movable/proc/CanAtmosPass()
/atom/movable/proc/CanAtmosPass()
return 1
atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
return (!density || !height)
turf/CanPass(atom/movable/mover, turf/target, height=1.5)
/turf/CanPass(atom/movable/mover, turf/target, height=1.5)
if(!target) return 0
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
+2 -2
View File
@@ -473,7 +473,7 @@
SSair.active_super_conductivity -= src
return 0
turf/simulated/proc/consider_superconductivity(starting)
/turf/simulated/proc/consider_superconductivity(starting)
if(!thermal_conductivity)
return 0
@@ -489,7 +489,7 @@ turf/simulated/proc/consider_superconductivity(starting)
SSair.active_super_conductivity |= src
return 1
turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space
/turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space
if(temperature > T0C) //Considering 0 degC as te break even point for radiation in and out
var/delta_temperature = (temperature_archived - TCMB) //hardcoded space temperature
if((heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER))
+1 -1
View File
@@ -36,7 +36,7 @@ Be sure to include required js functions in your page, or it'll raise an excepti
And yes I know this is a proc in a defines file, but its highly relevant so it can be here
*/
proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null)
/proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null)
if(receiver && target_element && control_id) // && winexists(receiver, control_id))
var/list/argums = list(target_element, new_content)
if(callback)
+16
View File
@@ -0,0 +1,16 @@
#define MARTIAL_COMBO_FAIL 0 // If the combo failed
#define MARTIAL_COMBO_CONTINUE 1 // If the combo should continue
#define MARTIAL_COMBO_DONE 2 // If the combo is successful and done
#define MARTIAL_COMBO_DONE_NO_CLEAR 3 // If the combo is successful and done but the others should have a chance to finish
#define MARTIAL_COMBO_DONE_BASIC_HIT 4 // If the combo should do a basic hit after it's done
#define MARTIAL_COMBO_DONE_CLEAR_COMBOS 5 // If the combo should do a basic hit after it's done
#define MARTIAL_ARTS_CANNOT_USE -1
#define MARTIAL_COMBO_STEP_HARM "Harm"
#define MARTIAL_COMBO_STEP_DISARM "Disarm"
#define MARTIAL_COMBO_STEP_GRAB "Grab"
#define MARTIAL_COMBO_STEP_HELP "Help"
// A check used for all act types. Such as disarm_act
#define MARTIAL_ARTS_ACT_CHECK if((. = ..()) != FALSE) return .
+1
View File
@@ -208,6 +208,7 @@
#define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian))
#define isnymph(A) (istype((A), /mob/living/simple_animal/diona))
#define ishostile(A) (istype(A, /mob/living/simple_animal/hostile))
#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider))
#define issilicon(A) (istype((A), /mob/living/silicon))
#define isAI(A) (istype((A), /mob/living/silicon/ai))
-2
View File
@@ -21,8 +21,6 @@
#define PIPE_TVALVE 18
#define PIPE_MANIFOLD4W 19
#define PIPE_CAP 20
#define PIPE_OMNI_MIXER 21
#define PIPE_OMNI_FILTER 22
#define PIPE_UNIVERSAL 23
#define PIPE_SUPPLY_STRAIGHT 24
#define PIPE_SUPPLY_BENT 25
+2 -2
View File
@@ -48,7 +48,7 @@
#define INIT_ORDER_GARBAGE 21
#define INIT_ORDER_DBCORE 20
#define INIT_ORDER_BLACKBOX 19
#define INIT_ORDER_SERVER_MAINT 18
#define INIT_ORDER_CLEANUP 18
#define INIT_ORDER_INPUT 17
#define INIT_ORDER_SOUNDS 16
#define INIT_ORDER_INSTRUMENTS 15
@@ -90,7 +90,7 @@
#define FIRE_PRIORITY_NANOMOB 10
#define FIRE_PRIORITY_NIGHTSHIFT 10
#define FIRE_PRIORITY_IDLE_NPC 10
#define FIRE_PRIORITY_SERVER_MAINT 10
#define FIRE_PRIORITY_CLEANUP 10
#define FIRE_PRIORITY_TICKETS 10
#define FIRE_PRIORITY_RESEARCH 10
#define FIRE_PRIORITY_GARBAGE 15
+14 -14
View File
@@ -1,4 +1,4 @@
proc/GetOppositeDir(var/dir)
/proc/GetOppositeDir(var/dir)
switch(dir)
if(NORTH) return SOUTH
if(SOUTH) return NORTH
@@ -10,7 +10,7 @@ proc/GetOppositeDir(var/dir)
if(SOUTHEAST) return NORTHWEST
return 0
proc/random_underwear(gender, species = "Human")
/proc/random_underwear(gender, species = "Human")
var/list/pick_list = list()
switch(gender)
if(MALE) pick_list = GLOB.underwear_m
@@ -18,7 +18,7 @@ proc/random_underwear(gender, species = "Human")
else pick_list = GLOB.underwear_list
return pick_species_allowed_underwear(pick_list, species)
proc/random_undershirt(gender, species = "Human")
/proc/random_undershirt(gender, species = "Human")
var/list/pick_list = list()
switch(gender)
if(MALE) pick_list = GLOB.undershirt_m
@@ -26,7 +26,7 @@ proc/random_undershirt(gender, species = "Human")
else pick_list = GLOB.undershirt_list
return pick_species_allowed_underwear(pick_list, species)
proc/random_socks(gender, species = "Human")
/proc/random_socks(gender, species = "Human")
var/list/pick_list = list()
switch(gender)
if(MALE) pick_list = GLOB.socks_m
@@ -34,7 +34,7 @@ proc/random_socks(gender, species = "Human")
else pick_list = GLOB.socks_list
return pick_species_allowed_underwear(pick_list, species)
proc/pick_species_allowed_underwear(list/all_picks, species)
/proc/pick_species_allowed_underwear(list/all_picks, species)
var/list/valid_picks = list()
for(var/test in all_picks)
var/datum/sprite_accessory/S = all_picks[test]
@@ -46,7 +46,7 @@ proc/pick_species_allowed_underwear(list/all_picks, species)
return pick(valid_picks)
proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
/proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
var/h_style = "Bald"
var/list/valid_hairstyles = list()
for(var/hairstyle in GLOB.hair_styles_public_list)
@@ -75,7 +75,7 @@ proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohea
return h_style
proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
/proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead)
var/f_style = "Shaved"
var/list/valid_facial_hairstyles = list()
for(var/facialhairstyle in GLOB.facial_hair_styles_list)
@@ -104,7 +104,7 @@ proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/
return f_style
proc/random_head_accessory(species = "Human")
/proc/random_head_accessory(species = "Human")
var/ha_style = "None"
var/list/valid_head_accessories = list()
for(var/head_accessory in GLOB.head_accessory_styles_list)
@@ -119,7 +119,7 @@ proc/random_head_accessory(species = "Human")
return ha_style
proc/random_marking_style(var/location = "body", species = "Human", var/datum/robolimb/robohead, var/body_accessory, var/alt_head)
/proc/random_marking_style(var/location = "body", species = "Human", var/datum/robolimb/robohead, var/body_accessory, var/alt_head)
var/m_style = "None"
var/list/valid_markings = list()
for(var/marking in GLOB.marking_styles_list)
@@ -158,7 +158,7 @@ proc/random_marking_style(var/location = "body", species = "Human", var/datum/ro
return m_style
proc/random_body_accessory(species = "Vulpkanin")
/proc/random_body_accessory(species = "Vulpkanin")
var/body_accessory = null
var/list/valid_body_accessories = list()
for(var/B in GLOB.body_accessory_by_name)
@@ -174,7 +174,7 @@ proc/random_body_accessory(species = "Vulpkanin")
return body_accessory
proc/random_name(gender, species = "Human")
/proc/random_name(gender, species = "Human")
var/datum/species/current_species
if(species)
@@ -188,7 +188,7 @@ proc/random_name(gender, species = "Human")
else
return current_species.get_random_name(gender)
proc/random_skin_tone(species = "Human")
/proc/random_skin_tone(species = "Human")
if(species == "Human" || species == "Drask")
switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino"))
if("caucasian") . = -10
@@ -202,7 +202,7 @@ proc/random_skin_tone(species = "Human")
. = rand(1, 6)
return .
proc/skintone2racedescription(tone, species = "Human")
/proc/skintone2racedescription(tone, species = "Human")
if(species == "Human")
switch(tone)
if(30 to INFINITY) return "albino"
@@ -225,7 +225,7 @@ proc/skintone2racedescription(tone, species = "Human")
else
return "unknown"
proc/age2agedescription(age)
/proc/age2agedescription(age)
switch(age)
if(0 to 1) return "infant"
if(1 to 3) return "toddler"
+1 -1
View File
@@ -196,7 +196,7 @@
//checks text for html tags
//if tag is not in whitelist (var/list/paper_tag_whitelist in global.dm)
//relpaces < with &lt;
proc/checkhtml(var/t)
/proc/checkhtml(var/t)
t = sanitize_simple(t, list("&#"="."))
var/p = findtext(t,"<",1)
while(p) //going through all the tags
+2 -2
View File
@@ -60,7 +60,7 @@
return time2text(station_time(time, TRUE), format)
/* Returns 1 if it is the selected month and day */
proc/isDay(var/month, var/day)
/proc/isDay(var/month, var/day)
if(isnum(month) && isnum(day))
var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month
var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day
@@ -95,7 +95,7 @@ proc/isDay(var/month, var/day)
/proc/seconds_to_time(var/seconds as num)
var/numSeconds = seconds % 60
var/numMinutes = (seconds - numSeconds) / 60
return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds."
return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds"
//Take a value in seconds and makes it display like a clock
/proc/seconds_to_clock(var/seconds as num)
+11 -36
View File
@@ -20,31 +20,6 @@
return 0
//Inverts the colour of an HTML string
/proc/invertHTML(HTMLstring)
if(!( istext(HTMLstring) ))
CRASH("Given non-text argument!")
else
if(length(HTMLstring) != 7)
CRASH("Given non-HTML argument!")
var/textr = copytext(HTMLstring, 2, 4)
var/textg = copytext(HTMLstring, 4, 6)
var/textb = copytext(HTMLstring, 6, 8)
var/r = hex2num(textr)
var/g = hex2num(textg)
var/b = hex2num(textb)
textr = num2hex(255 - r)
textg = num2hex(255 - g)
textb = num2hex(255 - b)
if(length(textr) < 2)
textr = text("0[]", textr)
if(length(textg) < 2)
textr = text("0[]", textg)
if(length(textb) < 2)
textr = text("0[]", textb)
return text("#[][][]", textr, textg, textb)
//Returns the middle-most value
/proc/dd_range(var/low, var/high, var/num)
return max(low,min(high,num))
@@ -529,7 +504,7 @@ Returns 1 if the chain up to the area contains the given typepath
return max(min(middle, high), low)
//returns random gauss number
proc/GaussRand(var/sigma)
/proc/GaussRand(var/sigma)
var/x,y,rsq
do
x=2*rand()-1
@@ -539,7 +514,7 @@ proc/GaussRand(var/sigma)
return sigma*y*sqrt(-2*log(rsq)/rsq)
//returns random gauss number, rounded to 'roundto'
proc/GaussRandRound(var/sigma,var/roundto)
/proc/GaussRandRound(var/sigma,var/roundto)
return round(GaussRand(sigma),roundto)
//Will return the contents of an atom recursivly to a depth of 'searchDepth'
@@ -583,7 +558,7 @@ proc/GaussRandRound(var/sigma,var/roundto)
return 1
proc/is_blocked_turf(turf/T, exclude_mobs)
/proc/is_blocked_turf(turf/T, exclude_mobs)
if(T.density)
return 1
for(var/i in T)
@@ -984,16 +959,16 @@ proc/is_blocked_turf(turf/T, exclude_mobs)
proc/get_cardinal_dir(atom/A, atom/B)
/proc/get_cardinal_dir(atom/A, atom/B)
var/dx = abs(B.x - A.x)
var/dy = abs(B.y - A.y)
return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12)
//chances are 1:value. anyprob(1) will always return true
proc/anyprob(value)
/proc/anyprob(value)
return (rand(1,value)==value)
proc/view_or_range(distance = world.view , center = usr , type)
/proc/view_or_range(distance = world.view , center = usr , type)
switch(type)
if("view")
. = view(distance,center)
@@ -1001,7 +976,7 @@ proc/view_or_range(distance = world.view , center = usr , type)
. = range(distance,center)
return
proc/oview_or_orange(distance = world.view , center = usr , type)
/proc/oview_or_orange(distance = world.view , center = usr , type)
switch(type)
if("view")
. = oview(distance,center)
@@ -1009,7 +984,7 @@ proc/oview_or_orange(distance = world.view , center = usr , type)
. = orange(distance,center)
return
proc/get_mob_with_client_list()
/proc/get_mob_with_client_list()
var/list/mobs = list()
for(var/mob/M in GLOB.mob_list)
if(M.client)
@@ -1233,10 +1208,10 @@ GLOBAL_LIST_INIT(wall_items, typecacheof(list(/obj/machinery/power/apc, /obj/mac
return 0
proc/get_angle(atom/a, atom/b)
/proc/get_angle(atom/a, atom/b)
return atan2(b.y - a.y, b.x - a.x)
proc/atan2(x, y)
/proc/atan2(x, y)
if(!x && !y) return 0
return y >= 0 ? arccos(x / sqrt(x * x + y * y)) : -arccos(x / sqrt(x * x + y * y))
@@ -1329,7 +1304,7 @@ Standard way to write links -Sayu
return FACING_INIT_FACING_TARGET_TARGET_FACING_PERPENDICULAR
atom/proc/GetTypeInAllContents(typepath)
/atom/proc/GetTypeInAllContents(typepath)
var/list/processing_list = list(src)
var/list/processed = list()
+3 -2
View File
@@ -10,12 +10,12 @@ GLOBAL_DATUM_INIT(command_announcer, /obj/item/radio/intercom/command, create_co
// Load order issues means this can't be new'd until other code runs
// This is probably not the way I should be doing this, but I don't know how to do it right!
proc/create_global_announcer()
/proc/create_global_announcer()
spawn(0)
GLOB.global_announcer = new(null)
return
proc/create_command_announcer()
/proc/create_command_announcer()
spawn(0)
GLOB.command_announcer = new(null)
return
@@ -92,6 +92,7 @@ GLOBAL_VAR(map_name) // Self explanatory
GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) // Station datacore, manifest, etc
GLOBAL_VAR_INIT(panic_bunker_enabled, FALSE) // Is the panic bunker enabled
GLOBAL_VAR_INIT(pending_server_update, FALSE)
//Database connections
//A connection is established on world creation. Ideally, the connection dies when the server restarts (After feedback logging.).
+7
View File
@@ -231,6 +231,13 @@
to_chat(user, "<span class='notice'>The door bolt lights have been enabled.</span>")
update_icon()
// FIRE ALARMS
/obj/machinery/firealarm/AICtrlClick()
if(enabled)
reset()
else
alarm()
// AI-CONTROLLED SLIP GENERATOR IN AI CORE
+3
View File
@@ -170,6 +170,9 @@
/obj/machinery/ai_slipper/BorgAltClick() //Dispenses liquid if on
Activate()
/obj/machinery/firealarm/BorgCtrlClick()
AICtrlClick()
/*
As with AI, these are not used in click code,
because the code for robots is specific, not generic.
+44
View File
@@ -0,0 +1,44 @@
/**
* # Cleanup Subsystem
*
* For now, all it does is periodically clean the supplied global lists of any null values they may contain.
*
* Why is this important?
*
* Sometimes, these lists can gain nulls due to errors.
* For example, when a dead player trasitions from the `dead_mob_list` to the `alive_mob_list`, a null value may get stuck in the dead mob list.
* This can cause issues when other code tries to do things with the values in the list, but are instead met with null values.
* These problems are incredibly hard to track down and fix, so this subsystem is a solution to that.
*/
SUBSYSTEM_DEF(cleanup)
name = "Null cleanup"
wait = 30 SECONDS
flags = SS_POST_FIRE_TIMING
priority = FIRE_PRIORITY_CLEANUP
init_order = INIT_ORDER_CLEANUP
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
offline_implications = "Certain global lists will no longer be cleared of nulls, which may result in runtimes. No immediate action is needed."
/// A list of global lists we want the subsystem to clean.
var/list/lists_to_clean
/datum/controller/subsystem/cleanup/Initialize(start_timeofday)
// If you want this subsystem to clean out nulls from a specific list, add it here.
lists_to_clean = list(
GLOB.clients = "clients",
GLOB.player_list = "player_list",
GLOB.mob_list = "mob_list",
GLOB.alive_mob_list = "alive_mob_list",
GLOB.dead_mob_list = "dead_mob_list",
GLOB.human_list = "human_list",
GLOB.carbon_list = "carbon_list"
)
return ..()
/datum/controller/subsystem/cleanup/fire(resumed)
for(var/L in lists_to_clean)
var/list/_list = L
var/prev_length = length(_list)
listclearnulls(_list)
if(length(_list) < prev_length)
stack_trace("Found a null value in GLOB.[lists_to_clean[_list]]!")
+40 -38
View File
@@ -620,20 +620,32 @@ SUBSYSTEM_DEF(jobs)
var/mob/M = tgtcard.getPlayer()
for(var/datum/job/job in occupations)
if(tgtcard.assignment && tgtcard.assignment == job.title)
jobs_to_formats[job.title] = "disabled" // the job they already have is pre-selected
jobs_to_formats[job.title] = "green" // the job they already have is pre-selected
else if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated")
jobs_to_formats[job.title] = "grey"
else if(!job.would_accept_job_transfer_from_player(M))
jobs_to_formats[job.title] = "linkDiscourage" // jobs which are karma-locked and not unlocked for this player are discouraged
jobs_to_formats[job.title] = "grey" // jobs which are karma-locked and not unlocked for this player are discouraged
else if((job.title in GLOB.command_positions) && istype(M) && M.client && job.available_in_playtime(M.client))
jobs_to_formats[job.title] = "linkDiscourage" // command jobs which are playtime-locked and not unlocked for this player are discouraged
jobs_to_formats[job.title] = "grey" // command jobs which are playtime-locked and not unlocked for this player are discouraged
else if(job.total_positions && !job.current_positions && job.title != "Civilian")
jobs_to_formats[job.title] = "linkEncourage" // jobs with nobody doing them at all are encouraged
jobs_to_formats[job.title] = "teal" // jobs with nobody doing them at all are encouraged
else if(job.total_positions >= 0 && job.current_positions >= job.total_positions)
jobs_to_formats[job.title] = "linkDiscourage" // jobs that are full (no free positions) are discouraged
jobs_to_formats[job.title] = "grey" // jobs that are full (no free positions) are discouraged
if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated")
jobs_to_formats["Custom"] = "grey"
return jobs_to_formats
/datum/controller/subsystem/jobs/proc/log_job_transfer(transferee, oldvalue, newvalue, whodidit)
id_change_records["[id_change_counter]"] = list("transferee" = transferee, "oldvalue" = oldvalue, "newvalue" = newvalue, "whodidit" = whodidit, "timestamp" = station_time_timestamp())
/datum/controller/subsystem/jobs/proc/log_job_transfer(transferee, oldvalue, newvalue, whodidit, reason)
id_change_records["[id_change_counter]"] = list(
"transferee" = transferee,
"oldvalue" = oldvalue,
"newvalue" = newvalue,
"whodidit" = whodidit,
"timestamp" = station_time_timestamp(),
"reason" = reason
)
id_change_counter++
/datum/controller/subsystem/jobs/proc/slot_job_transfer(oldtitle, newtitle)
@@ -663,45 +675,35 @@ SUBSYSTEM_DEF(jobs)
return
var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
if(PM && PM.can_receive())
PM.notify("<b>Automated Notification: </b>\"[antext]\" (Unable to Reply)")
PM.notify("<b>Automated Notification: </b>\"[antext]\" (Unable to Reply)", 0) // the 0 means don't make the PDA flash
/datum/controller/subsystem/jobs/proc/notify_by_name(target_name, antext)
// Used to notify a specific crew member based on their real_name
if(!target_name || !antext)
return
var/obj/item/pda/target_pda
for(var/obj/item/pda/check_pda in GLOB.PDAs)
if(check_pda.owner == target_name)
target_pda = check_pda
break
if(!target_pda)
return
var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
if(PM && PM.can_receive())
PM.notify("<b>Automated Notification: </b>\"[antext]\" (Unable to Reply)", 0) // the 0 means don't make the PDA flash
/datum/controller/subsystem/jobs/proc/fetch_transfer_record_html(var/centcom)
var/record_html = "<TABLE border=\"1\">"
var/table_headers = list("Crewman", "Old Rank", "New Rank", "Authorized By", "Time")
var/hidden_fields = list("deletedby")
if(centcom)
table_headers += "<span class='bad'>Deleted By</span>"
record_html += "<TR>"
for(var/thisheader in table_headers)
record_html += "<TD><B>[thisheader]</B></TD>"
record_html += "</TR>"
var/visible_record_count = 0
/datum/controller/subsystem/jobs/proc/format_job_change_records(centcom)
var/list/formatted = list()
for(var/thisid in id_change_records)
var/thisrecord = id_change_records[thisid]
if(thisrecord["deletedby"] && !centcom)
continue
record_html += "<TR>"
var/list/newlist = list()
for(var/lkey in thisrecord)
if(lkey in hidden_fields)
if(centcom)
record_html += "<TD><span class='bad'>[thisrecord[lkey]]<span></TD>"
else
continue
else
record_html += "<TD>[thisrecord[lkey]]</TD>"
record_html += "</TR>"
visible_record_count++
newlist[lkey] = thisrecord[lkey]
formatted.Add(list(newlist))
return formatted
record_html += "</TABLE>"
if(!visible_record_count)
return "No records on file yet."
return record_html
/datum/controller/subsystem/jobs/proc/delete_log_records(sourceuser, delete_all)
. = 0
+1 -1
View File
@@ -34,7 +34,7 @@ SUBSYSTEM_DEF(parallax)
for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc);
if(A != C.movingmob)
if(C.movingmob != null)
if(C.movingmob != null && C.movingmob.client_mobs_in_contents)
C.movingmob.client_mobs_in_contents -= C.mob
UNSETEMPTY(C.movingmob.client_mobs_in_contents)
LAZYINITLIST(A.client_mobs_in_contents)
+8 -3
View File
@@ -93,6 +93,11 @@ SUBSYSTEM_DEF(shuttle)
return S
WARNING("couldn't find dock with id: [id]")
/datum/controller/subsystem/shuttle/proc/secondsToRefuel()
var/elapsed = world.time - SSticker.round_start_time
var/remaining = round((config.shuttle_refuel_delay - elapsed) / 10)
return remaining > 0 ? remaining : 0
/datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason)
if(!emergency)
WARNING("requestEvac(): There is no emergency shuttle, but the shuttle was called. Using the backup shuttle instead.")
@@ -107,7 +112,7 @@ SUBSYSTEM_DEF(shuttle)
return
emergency = backup_shuttle
if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay)
if(secondsToRefuel())
to_chat(user, "The emergency shuttle is refueling. Please wait another [abs(round(((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)/600))] minutes before trying again.")
return
@@ -131,7 +136,7 @@ SUBSYSTEM_DEF(shuttle)
call_reason = trim(html_encode(call_reason))
if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH)
to_chat(user, "You must provide a reason.")
to_chat(user, "Reason is too short. [CALL_SHUTTLE_REASON_LENGTH] character minimum.")
return
var/area/signal_origin = get_area(user)
@@ -192,7 +197,7 @@ SUBSYSTEM_DEF(shuttle)
var/obj/machinery/computer/communications/C = thing
if(C.stat & BROKEN)
continue
else if(istype(thing, /datum/computer_file/program/comm) || istype(thing, /obj/item/circuitboard/communications))
else if(istype(thing, /obj/item/circuitboard/communications))
continue
var/turf/T = get_turf(thing)
+13
View File
@@ -450,6 +450,7 @@
/datum/action/spell_action
check_flags = 0
background_icon_state = "bg_spell"
var/recharge_text_color = "#FFFFFF"
/datum/action/spell_action/New(Target)
..()
@@ -487,6 +488,18 @@
return spell.can_cast(owner)
return 0
/datum/action/spell_action/UpdateButtonIcon()
if(button && !(. = ..()))
var/obj/effect/proc_holder/spell/S = target
if(!istype(S))
return
var/progress = S.get_availability_percentage()
var/col_val_high = 72 * progress + 128
var/col_val_low = 200 * progress
button.maptext = "<div style=\"font-size:6pt;color:[recharge_text_color];font:'Small Fonts';text-align:center;\" valign=\"bottom\">[round_down(progress * 100)]%</div>"
button.color = rgb(col_val_high, col_val_low, col_val_low, col_val_high)
else
button.maptext = null
/*
/datum/action/spell_action/alien
+5 -1
View File
@@ -1,3 +1,5 @@
#define AIR_ALARM_DATA_CACHE_DURATION 10 SECONDS
GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new())
/datum/repository/air_alarm/proc/air_alarm_data(var/list/monitored_alarms, var/refresh = 0, var/obj/machinery/alarm/passed_alarm)
@@ -8,7 +10,7 @@ GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new())
cache_entry = new/datum/cache_entry
cache_data = cache_entry
if(!refresh)
if(!refresh && cache_entry.timestamp + AIR_ALARM_DATA_CACHE_DURATION > world.time)
return cache_entry.data
if(SSticker && SSticker.current_state < GAME_STATE_PLAYING && istype(passed_alarm)) // Generating the list for the first time as the game hasn't started - no need to run through the machines list everything every time
@@ -29,3 +31,5 @@ GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new())
/datum/repository/air_alarm/proc/update_cache(var/obj/machinery/alarm/alarm)
return air_alarm_data(refresh = 1, passed_alarm = alarm)
#undef AIR_ALARM_DATA_CACHE_DURATION
+13 -1
View File
@@ -1,5 +1,8 @@
GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
/datum/repository/crew
var/static/list/bold_jobs
/datum/repository/crew/New()
cache_data = list()
..()
@@ -18,6 +21,13 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
if(world.time < cache_entry.timestamp)
return cache_entry.data
// Initialize the jobs here because in New(), GLOB.command_positions may not be inited yet
if(!bold_jobs)
bold_jobs = list()
bold_jobs += GLOB.command_positions
bold_jobs += get_all_centcom_jobs()
bold_jobs += list("Nanotrasen Representative", "Blueshield", "Magistrate")
for(var/thing in GLOB.human_list)
var/mob/living/carbon/human/H = thing
var/obj/item/clothing/under/C = H.w_uniform
@@ -32,11 +42,13 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["is_command"] = (crewmemberData["assignment"] in bold_jobs)
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
crewmemberData["dead"] = H.stat > UNCONSCIOUS
crewmemberData["dead"] = H.stat == DEAD
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
crewmemberData["stat"] = H.stat
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
+17 -10
View File
@@ -47,23 +47,30 @@
return
if(!isturf(target))
return
if(!user.unEquip(I))
return
var/turf/source_turf = get_turf(I)
var/turf/target_turf = target
var/list/clickparams = params2list(params)
var/x_offset = text2num(clickparams["icon-x"]) - 16
var/y_offset = text2num(clickparams["icon-y"]) - 16
var/x_offset
var/y_offset
if(target_turf != get_turf(I)) //Trying to stick it on a wall, don't move it to the actual wall or you can move the item through it. Instead set the pixels as appropriate
var/target_direction = get_dir(source_turf, target_turf)//The direction we clicked
// Snowflake diagonal handling
if(target_direction in GLOB.diagonals)
to_chat(user, "<span class='warning'>You cant reach [target_turf].</span>")
return
if(target_direction & EAST)
x_offset += 32
x_offset = 16
y_offset = rand(-12, 12)
else if(target_direction & WEST)
x_offset -= 32
if(target_direction & NORTH)
y_offset += 32
x_offset = -16
y_offset = rand(-12, 12)
else if(target_direction & NORTH)
x_offset = rand(-12, 12)
y_offset = 16
else if(target_direction & SOUTH)
y_offset -= 32
x_offset = rand(-12, 12)
y_offset = -16
if(!user.unEquip(I))
return
to_chat(user, "<span class='notice'>You stick [I] to [target_turf].</span>")
I.pixel_x = x_offset
I.pixel_y = y_offset
+8
View File
@@ -191,6 +191,10 @@
..()
desc = "That's Definitely Not [M.real_name]."
/datum/dog_fashion/head/cone
name = "REAL_NAME"
desc = "Omnicone's Chosen Champion"
/datum/dog_fashion/back/hardsuit
name = "Space Explorer REAL_NAME"
desc = "That's one small step for a corgi. One giant yap for corgikind."
@@ -200,3 +204,7 @@
D.mutations.Add(BREATHLESS)
D.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)
D.minbodytemp = 0
/datum/dog_fashion/head/fried_vox_empty
name = "Colonel REAL_NAME"
desc = "Keep away from live vox."
+5 -7
View File
@@ -152,13 +152,11 @@
return doTeleport()
return 0
/datum/teleport/instant //teleports when datum is created
start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
if(..())
if(teleport())
return 1
return 0
/datum/teleport/instant/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null)
if(..())
if(teleport())
return 1
return 0
/datum/teleport/instant/science
+5 -4
View File
@@ -35,6 +35,7 @@
var/list/restricted_roles = list()
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
var/datum/martial_art/martial_art
var/role_alt_title
@@ -914,7 +915,7 @@
log_admin("[key_name(usr)] has equipped [key_name(current)] as a wizard")
message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a wizard")
if("name")
SSticker.mode.name_wizard(current)
INVOKE_ASYNC(SSticker.mode, /datum/game_mode/wizard.proc/name_wizard, current)
log_admin("[key_name(usr)] has allowed wizard [key_name(current)] to name themselves")
message_admins("[key_name_admin(usr)] has allowed wizard [key_name_admin(current)] to name themselves")
if("autoobjectives")
@@ -1102,8 +1103,8 @@
special_role = null
to_chat(current,"<span class='userdanger'>Your infernal link has been severed! You are no longer a devil!</span>")
RemoveSpell(/obj/effect/proc_holder/spell/targeted/infernal_jaunt)
RemoveSpell(/obj/effect/proc_holder/spell/fireball/hellish)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/summon_contract)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/click/fireball/hellish)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/click/summon_contract)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/pitchfork)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/pitchfork/greater)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/conjure_item/pitchfork/ascended)
@@ -1501,7 +1502,7 @@
SSticker.mode.equip_wizard(current)
for(var/obj/item/spellbook/S in current.contents)
S.op = 0
SSticker.mode.name_wizard(current)
INVOKE_ASYNC(SSticker.mode, /datum/game_mode/wizard.proc/name_wizard, current)
SSticker.mode.forge_wizard_objectives(src)
SSticker.mode.greet_wizard(src)
SSticker.mode.update_wiz_icons_added(src)
+1 -1
View File
@@ -242,7 +242,7 @@
/obj/item/organ/internal/cyberimp/eyes/shield,
/obj/item/organ/internal/cyberimp/eyes/hud/security,
/obj/item/organ/internal/cyberimp/eyes/xray,
/obj/item/organ/internal/cyberimp/brain/anti_stun,
/obj/item/organ/internal/cyberimp/brain/anti_stun/hardened,
/obj/item/organ/internal/cyberimp/chest/nutriment/plus,
/obj/item/organ/internal/cyberimp/arm/combat/centcom
)
-10
View File
@@ -351,16 +351,6 @@ GLOBAL_LIST_EMPTY(rpd_pipe_list) //Some pipes we don't want to be dispensable
pipe_id = PIPE_CIRCULATOR
pipe_icon = "circ"
/datum/pipes/atmospheric/omni_filter
pipe_name = "omni filter"
pipe_id = PIPE_OMNI_FILTER
pipe_icon = "omni_filter"
/datum/pipes/atmospheric/omni_mixer
pipe_name = "omni mixer"
pipe_id = PIPE_OMNI_MIXER
pipe_icon = "omni_mixer"
/datum/pipes/atmospheric/insulated
pipe_name = "insulated pipe"
pipe_id = PIPE_INSULATED_STRAIGHT
+2 -2
View File
@@ -16,7 +16,7 @@
name = "Biodome Winter"
id = "biodome-winter"
description = "For those getaways where you want to get back to nature, but you don't want to leave the fortified military compound where you spend your days. \
Includes a unique(*) laser pistol display case, and the recently introduced I.C.E(tm)."
Includes the recently introduced I.C.E(tm)."
suffix = "lavaland_biodome_winter.dmm"
/datum/map_template/ruin/lavaland/biodome/clown
@@ -42,7 +42,7 @@
cost = 10
allow_duplicates = FALSE
datum/map_template/ruin/lavaland/ash_walker
/datum/map_template/ruin/lavaland/ash_walker
name = "Ash Walker Nest"
id = "ash-walker"
description = "A race of unbreathing lizards live here, that run faster than a human can, worship a broken dead city, and are capable of reproducing by something involving tentacles? \
+15 -12
View File
@@ -6,44 +6,47 @@
qdel(src)
owner = new_owner
/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = FALSE, datum/topic_state/state = GLOB.ghost_state, datum/nanoui/master_ui = null)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/datum/spawners_menu/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui_state/state = GLOB.tgui_observer_state, datum/tgui/master_ui = null)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "spawners_menu.tmpl", "Spawners Menu", 700, 600, master_ui, state = state)
ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state = state)
ui.open()
/datum/spawners_menu/ui_data(mob/user)
/datum/spawners_menu/tgui_data(mob/user)
var/list/data = list()
data["spawners"] = list()
for(var/spawner in GLOB.mob_spawners)
var/list/this = list()
this["name"] = spawner
this["desc"] = ""
this["important_info"] = ""
this["fluff"] = ""
this["uids"] = list()
for(var/spawner_obj in GLOB.mob_spawners[spawner])
for(var/spawner_obj in GLOB.mob_spawners[spawner])//each spawner can contain multiple actual spawners, we use only one desc/info
this["uids"] += "\ref[spawner_obj]"
if(!this["desc"])
if(!this["desc"]) //haven't set descriptions yet
if(istype(spawner_obj, /obj/effect/mob_spawn))
var/obj/effect/mob_spawn/MS = spawner_obj
this["desc"] = MS.flavour_text
this["desc"] = MS.description
this["important_info"] = MS.important_info
this["fluff"] = MS.flavour_text
else
var/obj/O = spawner_obj
this["desc"] = O.desc
this["amount_left"] = LAZYLEN(GLOB.mob_spawners[spawner])
data["spawners"] += list(this)
return data
/datum/spawners_menu/Topic(href, href_list)
/datum/spawners_menu/tgui_act(action, params)
if(..())
return 1
var/spawners = replacetext(href_list["uid"], ",", ";")
return
var/spawners = replacetext(params["ID"], ",", ";")
var/list/possible_spawners = params2list(spawners)
var/obj/effect/mob_spawn/MS = locate(pick(possible_spawners))
if(!MS || !istype(MS))
log_runtime(EXCEPTION("A ghost tried to interact with an invalid spawner, or the spawner didn't exist."))
return
switch(href_list["action"])
switch(action)
if("jump")
owner.forceMove(get_turf(MS))
. = TRUE
+172 -70
View File
@@ -24,6 +24,20 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
user.face_atom(A)
return FALSE
/datum/click_intercept/proc_holder
var/obj/effect/proc_holder/spell
/datum/click_intercept/proc_holder/New(client/C, obj/effect/proc_holder/spell_to_cast)
. = ..()
spell = spell_to_cast
/datum/click_intercept/proc_holder/InterceptClickOn(user, params, atom/object)
spell.InterceptClickOn(user, params, object)
/datum/click_intercept/proc_holder/quit()
spell.remove_ranged_ability(spell.ranged_ability_user)
return ..()
/obj/effect/proc_holder/proc/add_ranged_ability(mob/living/user, var/msg)
if(!user || !user.client)
return
@@ -32,7 +46,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
user.ranged_ability.remove_ranged_ability(user)
user.ranged_ability = src
ranged_ability_user = user
user.client.click_intercept = user.ranged_ability
user.client.click_intercept = new /datum/click_intercept/proc_holder(user.client, user.ranged_ability)
add_mousepointer(user.client)
active = TRUE
if(msg)
@@ -48,15 +62,17 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
C.mouse_pointer_icon = initial(C.mouse_pointer_icon)
/obj/effect/proc_holder/proc/remove_ranged_ability(mob/living/user, var/msg)
if(!user || !user.client || (user.ranged_ability && user.ranged_ability != src)) //To avoid removing the wrong ability
if(!user || (user.ranged_ability && user.ranged_ability != src)) //To avoid removing the wrong ability
return
user.ranged_ability = null
ranged_ability_user = null
user.client.click_intercept = null
remove_mousepointer(user.client)
active = FALSE
if(msg)
to_chat(user, msg)
if(user.client)
qdel(user.client.click_intercept)
user.client.click_intercept = null
remove_mousepointer(user.client)
if(msg)
to_chat(user, msg)
update_icon()
/obj/effect/proc_holder/spell
@@ -114,10 +130,14 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
var/sound = null //The sound the spell makes when it is cast
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0, mob/living/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
to_chat(user, "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>")
return 0
/* Checks if the user can cast the spell
* @param charge_check If the proc should do the cooldown check
* @param start_recharge If the proc should set the cooldown
* @param user The caster of the spell
*/
/obj/effect/proc_holder/spell/proc/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
if(!can_cast(user, charge_check, TRUE))
return FALSE
if(ishuman(user))
var/mob/living/carbon/human/caster = user
@@ -126,49 +146,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
caster.reset_perspective(0)
return 0
if(is_admin_level(user.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
return 0
if(!skipcharge)
switch(charge_type)
if("recharge")
if(charge_counter < charge_max)
to_chat(user, still_recharging_msg)
return 0
if("charges")
if(!charge_counter)
to_chat(user, "<span class='notice'>[name] has no charges left.</span>")
return 0
if(!ghost)
if(user.stat && !stat_allowed)
to_chat(user, "<span class='notice'>You can't cast this spell while incapacitated.</span>")
return 0
if(ishuman(user) && (invocation_type == "whisper" || invocation_type == "shout") && user.is_muzzled())
to_chat(user, "Mmmf mrrfff!")
return 0
var/obj/effect/proc_holder/spell/noclothes/clothes_spell = locate() in (user.mob_spell_list | (user.mind ? user.mind.spell_list : list()))
if((ishuman(user) && clothes_req) && !istype(clothes_spell))//clothes check
var/mob/living/carbon/human/H = user
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)
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
if(!robe.magical || !hat.magical || !shoes.magical)
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
else if(!ishuman(user))
if(clothes_req || human_req)
to_chat(user, "<span class='notice'>This spell can only be cast by humans!</span>")
return 0
if(nonabstract_req && (isbrain(user) || ispAI(user)))
to_chat(user, "<span class='notice'>This spell can only be cast by physical beings!</span>")
return 0
if(!skipcharge)
if(start_recharge)
switch(charge_type)
if("recharge")
charge_counter = 0 //doesn't start recharging until the targets selecting ends
@@ -230,12 +208,12 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
/obj/effect/proc_holder/spell/process()
charge_counter += 2
if(action)
action.UpdateButtonIcon()
if(charge_counter < charge_max)
return
STOP_PROCESSING(SSfastprocess, src)
charge_counter = charge_max
if(action)
action.UpdateButtonIcon()
/obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr, make_attack_logs = TRUE) //if recharge is started is important for the trigger spells
before_cast(targets)
@@ -339,6 +317,19 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars
return
/obj/effect/proc_holder/spell/proc/get_availability_percentage()
switch(charge_type)
if("recharge")
if(charge_counter == 0)
return 0
return charge_counter / charge_max
if("charges")
if(charge_counter)
return 1
return 0
if("holdervar")
return 1
/obj/effect/proc_holder/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob
var/max_targets = 1 //leave 0 for unlimited targets in range, 1 for one selectable target in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range
var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast
@@ -429,6 +420,100 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
return
/obj/effect/proc_holder/spell/targeted/click
var/click_radius = 1 // How big the radius around the clicked atom is to find a suitable target. -1 is only the selected atom is considered
var/selection_activated_message = "<span class='notice'>Click on a target to cast the spell.</span>"
var/selection_deactivated_message = "<span class='notice'>You choose to not cast this spell.</span>"
var/allowed_type = /mob/living // Which type the targets have to be
var/auto_target_single = TRUE // If the spell should auto select a target if only one is found
/obj/effect/proc_holder/spell/targeted/click/Click()
var/mob/living/user = usr
if(!istype(user))
return
if(active)
remove_ranged_ability(user, selection_deactivated_message)
else
if(cast_check(TRUE, FALSE, user))
if(auto_target_single && attempt_auto_target(user))
return
add_ranged_ability(user, selection_activated_message)
else
to_chat(user, "<span class='warning'>[src] is not ready to be used yet.</span>")
/obj/effect/proc_holder/spell/targeted/click/proc/attempt_auto_target(mob/user)
var/atom/target
for(var/atom/A in view_or_range(range, user, selection_type))
if(valid_target(A, user))
if(target)
return FALSE // Two targets found. ABORT
target = A
if(target && cast_check(TRUE, TRUE, user)) // Singular target found. Cast it instantly
to_chat(user, "<span class='warning'>Only one target found. Casting [src] on [target]!</span>")
perform(list(target), user = user)
return TRUE
return FALSE
/obj/effect/proc_holder/spell/targeted/click/InterceptClickOn(mob/living/user, params, atom/A)
if(..() || !cast_check(TRUE, TRUE, user))
remove_ranged_ability(user)
revert_cast(user)
return TRUE
var/list/targets = list()
if(valid_target(A, user))
targets.Add(A)
if((!max_targets || max_targets > targets.len) && click_radius >= 0)
var/list/found_others = list()
for(var/atom/target in range(click_radius, A))
if(valid_target(target, user))
found_others |= target
if(!max_targets)
targets.Add(found_others)
else
if(max_targets <= found_others.len + targets.len)
targets.Add(found_others)
else
switch(random_target_priority) //Add in the rest
if(TARGET_RANDOM)
while(targets.len < max_targets && found_others.len) // Add the others
targets.Add(pick_n_take(found_others))
if(TARGET_CLOSEST)
var/list/distances = list()
for(var/target in found_others)
distances[target] = get_dist(user, target)
sortTim(distances, /proc/cmp_numeric_asc, TRUE) // Sort on distance
for(var/target in distances)
targets.Add(target)
if(targets.len >= max_targets)
break
if(!targets.len)
to_chat(user, "<span class='warning'>No suitable target found.</span>")
revert_cast(user)
return FALSE
perform(targets, user = user)
remove_ranged_ability(user)
return TRUE
/* Checks if a target is valid
* Should not include to_chats or other types of messages since this is used often on tons of targets.
* @param target The target to check
* @param user The user of the spell
*/
/obj/effect/proc_holder/spell/targeted/click/proc/valid_target(target, user)
return istype(target, allowed_type) && (include_user || target != user) && \
(target in view_or_range(range, user, selection_type))
/obj/effect/proc_holder/spell/targeted/click/choose_targets(mob/living/user, atom/A) // Not used
return
/obj/effect/proc_holder/spell/aoe_turf/choose_targets(mob/user = usr)
var/list/targets = list()
@@ -462,30 +547,39 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
qdel(dummy)
return 1
/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr)
/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list))
if(show_message)
to_chat(user, "<span class='warning'>You shouldn't have this spell! Something's wrong.</span>")
return 0
if(is_admin_level(user.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
return 0
switch(charge_type)
if("recharge")
if(charge_counter < charge_max)
return 0
if("charges")
if(!charge_counter)
return 0
if(user.stat && !stat_allowed)
return 0
if(charge_check)
switch(charge_type)
if("recharge")
if(charge_counter < charge_max)
if(show_message)
to_chat(user, still_recharging_msg)
return 0
if("charges")
if(!charge_counter)
if(show_message)
to_chat(user, "<span class='notice'>[name] has no charges left.</span>")
return 0
if(!ghost)
if(user.stat && !stat_allowed)
if(show_message)
to_chat(user, "<span class='notice'>You can't cast this spell while incapacitated.</span>")
return 0
if(ishuman(user) && (invocation_type == "whisper" || invocation_type == "shout") && user.is_muzzled())
if(show_message)
to_chat(user, "Mmmf mrrfff!")
return 0
if(ishuman(user))
var/mob/living/carbon/human/H = user
if((invocation_type == "whisper" || invocation_type == "shout") && H.is_muzzled())
return 0
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
@@ -493,12 +587,20 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell))
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
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
else
if(clothes_req || human_req)
if(show_message)
to_chat(user, "<span class='notice'>This spell can only be cast by humans!</span>")
return 0
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
+1 -1
View File
@@ -11,7 +11,7 @@
/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1, mob/living/user = usr)
var/thearea = before_cast(targets)
if(!thearea || !cast_check(1))
if(!thearea || !cast_check(TRUE, FALSE, user))
revert_cast()
return
invocation(thearea)
+13 -32
View File
@@ -1,25 +1,31 @@
/obj/effect/proc_holder/spell/targeted/chaplain_bless
/obj/effect/proc_holder/spell/targeted/click/chaplain_bless
name = "Bless"
desc = "Blesses a single person."
school = "transmutation"
charge_max = 60
clothes_req = 0
clothes_req = FALSE
invocation = "none"
invocation_type = "none"
max_targets = 1
include_user = 0
humans_only = 1
include_user = FALSE
allowed_type = /mob/living/carbon/human
selection_activated_message = "<span class='notice'>You prepare a blessing. Click on a target to start blessing.</span>"
selection_deactivated_message = "<span class='notice'>The crew will be blessed another time.</span>"
range = 1
click_radius = -1 // Only precision clicking
cooldown_min = 20
action_icon_state = "shield"
/obj/effect/proc_holder/spell/targeted/click/chaplain_bless/valid_target(mob/living/carbon/human/target, user)
if(!..())
return FALSE
/obj/effect/proc_holder/spell/targeted/chaplain_bless/cast(list/targets, mob/living/user = usr, distanceoverride)
return target.mind && target.ckey && !target.stat
/obj/effect/proc_holder/spell/targeted/click/chaplain_bless/cast(list/targets, mob/living/user = usr)
if(!istype(user))
to_chat(user, "Somehow, you are not a living mob. This should never happen. Report this bug.")
revert_cast()
@@ -35,32 +41,7 @@
revert_cast()
return
var/mob/living/carbon/human/target = targets[range]
if(!istype(target))
to_chat(user, "No target.")
revert_cast()
return
if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
to_chat(user, "[target] is too far away!")
revert_cast()
return
if(!target.mind)
to_chat(user, "[target] appears to be catatonic. Your blessing would have no effect.")
revert_cast()
return
if(!target.ckey)
to_chat(user, "[target] appears to be too out of it to benefit from this.")
revert_cast()
return
if(target.stat == DEAD)
to_chat(user, "[target] is already dead. There is no point.")
revert_cast()
return
var/mob/living/carbon/human/target = targets[1]
spawn(0) // allows cast to complete even if recipient ignores the prompt
if(alert(target, "[user] wants to bless you, in the name of [user.p_their()] religion. Accept?", "Accept Blessing?", "Yes", "No") == "Yes") // prevents forced conversions
+13 -7
View File
@@ -21,13 +21,18 @@
action_background_icon_state = "bg_demon"
/obj/effect/proc_holder/spell/targeted/summon_contract
/obj/effect/proc_holder/spell/targeted/click/summon_contract
name = "Summon infernal contract"
desc = "Skip making a contract by hand, just do it by magic."
invocation_type = "whisper"
invocation = "Just sign on the dotted line."
include_user = 0
selection_activated_message = "<span class='notice'>You prepare a detailed contract. Click on a target to summon the contract in his hands.</span>"
selection_deactivated_message = "<span class='notice'>You archive the contract for later use.</span>"
include_user = FALSE
range = 5
auto_target_single = FALSE // Prevent an accidental contract from summoning
click_radius = -1 // Precision clicking required
allowed_type = /mob/living/carbon
clothes_req = FALSE
school = "conjuration"
charge_max = 150
@@ -35,8 +40,9 @@
action_icon_state = "spell_default"
action_background_icon_state = "bg_demon"
/obj/effect/proc_holder/spell/targeted/summon_contract/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/C in targets)
/obj/effect/proc_holder/spell/targeted/click/summon_contract/cast(list/targets, mob/user = usr)
for(var/target in targets)
var/mob/living/carbon/C = target
if(C.mind && user.mind)
if(C.stat == DEAD)
if(user.drop_item())
@@ -63,7 +69,7 @@
to_chat(user,"<span class='notice'>[C] seems to not be sentient. You are unable to summon a contract for them.</span>")
/obj/effect/proc_holder/spell/fireball/hellish
/obj/effect/proc_holder/spell/targeted/click/fireball/hellish
name = "Hellfire"
desc = "This spell launches hellfire at the target."
school = "evocation"
@@ -74,8 +80,8 @@
fireball_type = /obj/item/projectile/magic/fireball/infernal
action_background_icon_state = "bg_demon"
/obj/effect/proc_holder/spell/fireball/hellish/cast(list/targets, mob/living/user = usr)
msg_admin_attack("[key_name_admin(usr)] has fired a fireball.", ATKLOG_FEW)
/obj/effect/proc_holder/spell/targeted/click/fireball/hellish/cast(list/targets, mob/living/user = usr)
add_attack_logs(user, targets, "has fired a Hellfire ball", ATKLOG_FEW)
.=..()
+9 -17
View File
@@ -1,39 +1,31 @@
/obj/effect/proc_holder/spell/targeted/horsemask
/obj/effect/proc_holder/spell/targeted/click/horsemask
name = "Curse of the Horseman"
desc = "This spell triggers a curse on a target, causing them to wield an unremovable horse head mask. They will speak like a horse! Any masks they are wearing will be disintegrated. This spell does not require robes."
school = "transmutation"
charge_type = "recharge"
charge_max = 150
charge_counter = 0
clothes_req = 0
stat_allowed = 0
clothes_req = FALSE
stat_allowed = FALSE
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
range = 7
cooldown_min = 30 //30 deciseconds reduction per rank
selection_type = "range"
selection_activated_message = "<span class='notice'>You start to quietly neigh an incantation. Click on or near a target to cast the spell.</span>"
selection_deactivated_message = "<span class='notice'>You stop neighing to yourself.</span>"
allowed_type = /mob/living/carbon/human
action_icon_state = "barn"
sound = 'sound/magic/HorseHead_curse.ogg'
/obj/effect/proc_holder/spell/targeted/horsemask/cast(list/targets, mob/user = usr)
/obj/effect/proc_holder/spell/targeted/click/horsemask/cast(list/targets, mob/user = usr)
if(!targets.len)
to_chat(user, "<span class='notice'>No target found in range.</span>")
return
var/mob/living/carbon/target = targets[1]
if(!target)
return
if(!ishuman(target))
to_chat(user, "<span class='notice'>It'd be stupid to curse [target] with a horse's head!</span>")
return
if(!(target in oview(range)))//If they are not in overview after selection.
to_chat(user, "<span class='notice'>They are too far away!</span>")
return
var/mob/living/carbon/human/target = targets[1]
var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead
magichead.flags |= NODROP | DROPDEL //curses!
+3 -3
View File
@@ -25,10 +25,10 @@
/obj/effect/proc_holder/spell/targeted/lightning/Click()
if(!ready && start_time == 0)
if(cast_check())
if(cast_check(TRUE, FALSE, usr))
StartChargeup()
else
if(ready && cast_check(skipcharge=1))
if(ready && cast_check(TRUE, TRUE, usr))
choose_targets()
return 1
@@ -44,7 +44,7 @@
if(ready)
Discharge()
obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr)
/obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr)
ready = 0
start_time = 0
if(halo)
+3 -3
View File
@@ -20,10 +20,10 @@
/obj/effect/proc_holder/spell/targeted/magnet/Click()
if(!ready && start_time == 0)
if(cast_check())
if(cast_check(TRUE, FALSE, usr))
StartChargeup()
else
if(ready && cast_check(skipcharge=1))
if(ready && cast_check(TRUE, TRUE, usr))
choose_targets()
return 1
@@ -39,7 +39,7 @@
if(ready)
Discharge()
obj/effect/proc_holder/spell/targeted/magnet/proc/Reset(mob/user = usr)
/obj/effect/proc_holder/spell/targeted/magnet/proc/Reset(mob/user = usr)
ready = 0
energy = 0
start_time = 0
+10 -14
View File
@@ -1,4 +1,4 @@
/obj/effect/proc_holder/spell/targeted/mind_transfer
/obj/effect/proc_holder/spell/targeted/click/mind_transfer
name = "Mind Transfer"
desc = "This spell allows the user to switch bodies with a target."
@@ -8,33 +8,29 @@
invocation = "GIN'YU CAPAN"
invocation_type = "whisper"
range = 1
click_radius = 0 // Still gotta be pretty accurate
selection_activated_message = "<span class='notice'>You prepare to transfer your mind. Click on a target to cast the spell.</span>"
selection_deactivated_message = "<span class='notice'>You decide that your current form is good enough.</span>"
cooldown_min = 200 //100 deciseconds reduction per rank
var/list/protected_roles = list("Wizard","Changeling","Cultist") //which roles are immune to the spell
var/paralysis_amount_caster = 20 //how much the caster is paralysed for after the spell
var/paralysis_amount_victim = 20 //how much the victim is paralysed for after the spell
action_icon_state = "mindswap"
/obj/effect/proc_holder/spell/targeted/click/mind_transfer/valid_target(mob/living/target, user)
if(!..())
return FALSE
return target.stat != DEAD && target.key && target.mind
/*
Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
Make sure spells that are removed from spell_list are actually removed and deleted when mind transfering.
Also, you never added distance checking after target is selected. I've went ahead and did that.
*/
/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/user = usr, distanceoverride)
/obj/effect/proc_holder/spell/targeted/click/mind_transfer/cast(list/targets, mob/user = usr)
var/mob/living/target = targets[range]
if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
to_chat(user, "They are too far away!")
return
if(target.stat == DEAD)
to_chat(user, "You don't particularly want to be dead.")
return
if(!target.key || !target.mind)
to_chat(user, "[target.p_they(TRUE)] appear[target.p_s()] to be catatonic. Not even magic can affect [target.p_their()] vacant mind.")
return
if(user.suiciding)
to_chat(user, "<span class='warning'>You're killing yourself! You can't concentrate enough to do this!</span>")
return
+13 -39
View File
@@ -308,76 +308,50 @@
duration = 300
sound = 'sound/magic/blind.ogg'
/obj/effect/proc_holder/spell/fireball
/obj/effect/proc_holder/spell/targeted/click/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
school = "evocation"
charge_max = 60
clothes_req = 0
clothes_req = FALSE
invocation = "ONI SOMA"
invocation_type = "shout"
auto_target_single = FALSE // Having this true won't ever find a single target and is just lost processing power
range = 20
cooldown_min = 20 //10 deciseconds reduction per rank
click_radius = -1
selection_activated_message = "<span class='notice'>Your prepare to cast your fireball spell! <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>You extinguish your fireball...for now.</span>"
allowed_type = /atom // FIRE AT EVERYTHING
var/fireball_type = /obj/item/projectile/magic/fireball
action_icon_state = "fireball0"
sound = 'sound/magic/fireball.ogg'
active = FALSE
/obj/effect/proc_holder/spell/fireball/Click()
var/mob/living/user = usr
if(!istype(user))
return
var/msg
if(!can_cast(user))
msg = "<span class='warning'>You can no longer cast Fireball.</span>"
remove_ranged_ability(user, msg)
return
if(active)
msg = "<span class='notice'>You extinguish your fireball...for now.</span>"
remove_ranged_ability(user, msg)
else
msg = "<span class='notice'>Your prepare to cast your fireball spell! <B>Left-click to cast at a target!</B></span>"
add_ranged_ability(user, msg)
/obj/effect/proc_holder/spell/fireball/update_icon()
/obj/effect/proc_holder/spell/targeted/click/fireball/update_icon()
if(!action)
return
action.button_icon_state = "fireball[active]"
action.UpdateButtonIcon()
/obj/effect/proc_holder/spell/fireball/InterceptClickOn(mob/living/user, params, atom/target)
if(..())
return FALSE
if(!cast_check(0, user))
remove_ranged_ability(user)
return FALSE
var/list/targets = list(target)
perform(targets, user = user)
return TRUE
/obj/effect/proc_holder/spell/fireball/cast(list/targets, mob/living/user = usr)
/obj/effect/proc_holder/spell/targeted/click/fireball/cast(list/targets, mob/living/user = usr)
var/target = targets[1] //There is only ever one target for fireball
var/turf/T = user.loc
var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction
if(!isturf(U) || !isturf(T))
return 0
return FALSE
var/obj/item/projectile/magic/fireball/FB = new fireball_type(user.loc)
FB.current = get_turf(user)
FB.preparePixelProjectile(target, get_turf(target), user)
FB.fire()
user.newtonian_move(get_dir(U, T))
remove_ranged_ability(user)
return 1
return TRUE
/obj/effect/proc_holder/spell/aoe_turf/repulse
name = "Repulse"
+8 -6
View File
@@ -344,6 +344,14 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
cost = 15
containername = "tactical armor crate"
/datum/supply_packs/security/armory/webbing
name = "Webbing Crate"
contains = list(/obj/item/storage/belt/security/webbing,
/obj/item/storage/belt/security/webbing,
/obj/item/storage/belt/security/webbing)
cost = 15
containername = "tactical webbing crate"
/datum/supply_packs/security/armory/swat
name = "SWAT gear crate"
contains = list(/obj/item/clothing/head/helmet/swat,
@@ -980,12 +988,6 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY
containername = "shield generators crate"
access = ACCESS_TELEPORTER
/datum/supply_packs/science/modularpc
name = "Deluxe Silicate Selections restocking unit"
cost = 15
contains = list(/obj/item/vending_refill/modularpc)
containername = "computer supply crate"
/datum/supply_packs/science/transfer_valves
name = "Tank Transfer Valves Crate"
contains = list(/obj/item/transfer_valve,
+5 -5
View File
@@ -412,9 +412,9 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/jobspecific/energizedfireaxe
name = "Energized Fire Axe"
desc = "A fire axe with a massive electrical charge built into it. It can release this charge on its first victim and will be rather plain after that."
desc = "A fire axe with a massive energy charge built into it. Upon striking someone while charged it will throw them backwards while stunning them briefly, but will take some time to charge up again. It is also much sharper than a regular axe and can pierce light armor."
reference = "EFA"
item = /obj/item/twohanded/energizedfireaxe
item = /obj/item/twohanded/fireaxe/energized
cost = 10
job = list("Life Support Specialist")
@@ -1563,11 +1563,11 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 10
/datum/uplink_item/cyber_implants/antistun
name = "CNS Rebooter Implant"
desc = "This implant will help you get back up on your feet faster after being stunned. \
name = "Hardened CNS Rebooter Implant"
desc = "This implant will help you get back up on your feet faster after being stunned. It is invulnerable to EMPs. \
Comes with an automated implanting tool."
reference = "CIAS"
item = /obj/item/organ/internal/cyberimp/brain/anti_stun
item = /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened
cost = 12
/datum/uplink_item/cyber_implants/reviver
+2 -2
View File
@@ -17,7 +17,7 @@
. += "The green light is [A.shocked ? "on" : "off"]."
. += "The UV display shows [A.uv_super ? "15 nm" : "185 nm"]."
datum/wires/suitstorage/interactable(mob/user)
/datum/wires/suitstorage/interactable(mob/user)
var/obj/machinery/suit_storage_unit/A = holder
if(iscarbon(user) && A.Adjacent(user) && A.shocked)
return A.shock(user, 100)
@@ -42,7 +42,7 @@ datum/wires/suitstorage/interactable(mob/user)
A.uv_super = !mend
..()
datum/wires/suitstorage/on_pulse(wire)
/datum/wires/suitstorage/on_pulse(wire)
var/obj/machinery/suit_storage_unit/A = holder
if(is_cut(wire))
return
+1 -1
View File
@@ -62,7 +62,7 @@
* In the `colors` list, the name of the color is the key, and the wire is the value.
* For example: `colors["red"] = WIRE_ELECTRIFY`. This will look like `list("red" = WIRE_ELECTRIFY)` internally.
*/
datum/wires/proc/randomize()
/datum/wires/proc/randomize()
var/static/list/possible_colors = list("red", "blue", "green", "silver", "orange", "brown", "gold", "white", "cyan", "magenta", "purple", "pink")
var/list/my_possible_colors = possible_colors.Copy()
+26 -26
View File
@@ -29,7 +29,7 @@
#define BLOB 14
// TODO: Investigate more recent type additions and see if I can handle them. - Nadrew
DBConnection
/DBConnection
var/_db_con // This variable contains a reference to the actual database connection.
var/dbi // This variable is a string containing the DBI MySQL requires.
var/user // This variable contains the username data.
@@ -39,14 +39,14 @@ DBConnection
var/server = ""
var/port = 3306
DBConnection/New(dbi_handler,username,password_handler,cursor_handler)
/DBConnection/New(dbi_handler,username,password_handler,cursor_handler)
src.dbi = dbi_handler
src.user = username
src.password = password_handler
src.default_cursor = cursor_handler
_db_con = _dm_db_new_con()
DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler)
/DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler)
if(!config.sql_enabled)
return 0
if(!src) return 0
@@ -54,24 +54,24 @@ DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_han
if(!cursor_handler) cursor_handler = Default_Cursor
return _dm_db_connect(_db_con,dbi_handler,user_handler,password_handler,cursor_handler,null)
DBConnection/proc/Disconnect() return _dm_db_close(_db_con)
/DBConnection/proc/Disconnect() return _dm_db_close(_db_con)
DBConnection/proc/IsConnected()
/DBConnection/proc/IsConnected()
if(!config.sql_enabled) return 0
var/success = _dm_db_is_connected(_db_con)
return success
DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str)
/DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str)
DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con)
DBConnection/proc/SelectDB(database_name,dbi)
/DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con)
/DBConnection/proc/SelectDB(database_name,dbi)
if(IsConnected()) Disconnect()
//return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password)
return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[sqladdress]:[sqlport]"]",user,password)
DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler)
/DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler)
DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler)
/DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler)
if(IsAdminAdvancedProcCall())
to_chat(usr, "<span class='boldannounce'>DB query blocked: Advanced ProcCall detected.</span>")
message_admins("[key_name(usr)] attempted to create a DB query via advanced proc-call")
@@ -83,12 +83,12 @@ DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler)
_db_query = _dm_db_new_query()
return ..()
DBQuery/CanProcCall()
/DBQuery/CanProcCall()
// dont even try it
return FALSE
DBQuery
/DBQuery
var/sql // The sql query being executed.
var/default_cursor
var/list/columns //list of DB Columns populated by Columns()
@@ -98,26 +98,26 @@ DBQuery
var/DBConnection/db_connection
var/_db_query
DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler
/DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler
DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor)
/DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor)
Close()
return _dm_db_execute(_db_query,sql_query,db_connection._db_con,cursor_handler,null)
DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions)
/DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions)
DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query)
/DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query)
DBQuery/proc/RowCount() return _dm_db_row_count(_db_query)
/DBQuery/proc/RowCount() return _dm_db_row_count(_db_query)
DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query)
/DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query)
DBQuery/proc/Columns()
/DBQuery/proc/Columns()
if(!columns)
columns = _dm_db_columns(_db_query,/DBColumn)
return columns
DBQuery/proc/GetRowData()
/DBQuery/proc/GetRowData()
var/list/columns = Columns()
var/list/results
if(columns.len)
@@ -128,23 +128,23 @@ DBQuery/proc/GetRowData()
results[C] = src.item[(cur_col.position+1)]
return results
DBQuery/proc/Close()
/DBQuery/proc/Close()
item.len = 0
columns = null
conversions = null
return _dm_db_close(_db_query)
DBQuery/proc/Quote(str)
/DBQuery/proc/Quote(str)
return db_connection.Quote(str)
DBQuery/proc/SetConversion(column,conversion)
/DBQuery/proc/SetConversion(column,conversion)
if(istext(column)) column = columns.Find(column)
if(!conversions) conversions = new/list(column)
else if(conversions.len < column) conversions.len = column
conversions[column] = conversion
DBColumn
/DBColumn
var/name
var/table
var/position //1-based index into item data
@@ -153,7 +153,7 @@ DBColumn
var/length
var/max_length
DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler)
/DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler)
src.name = name_handler
src.table = table_handler
src.position = position_handler
@@ -164,7 +164,7 @@ DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handl
return ..()
DBColumn/proc/SqlTypeName(type_handler=src.sql_type)
/DBColumn/proc/SqlTypeName(type_handler=src.sql_type)
switch(type_handler)
if(TINYINT) return "TINYINT"
if(SMALLINT) return "SMALLINT"
+1 -1
View File
@@ -570,7 +570,7 @@
/area/proc/prison_break()
for(var/obj/machinery/power/apc/temp_apc in src)
temp_apc.overload_lighting(70)
INVOKE_ASYNC(temp_apc, /obj/machinery/power/apc.proc/overload_lighting, 70)
for(var/obj/machinery/door/airlock/temp_airlock in src)
temp_airlock.prison_open()
for(var/obj/machinery/door/window/temp_windoor in src)
+2 -2
View File
@@ -231,7 +231,7 @@
/atom/proc/on_reagent_change()
return
/atom/proc/Bumped(AM as mob|obj)
/atom/proc/Bumped(atom/movable/AM)
return
/// Convenience proc to see if a container is open for chemistry handling
@@ -257,7 +257,7 @@
/atom/proc/CheckExit()
return TRUE
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
/atom/proc/HasProximity(atom/movable/AM)
return
/atom/proc/emp_act(severity)
+30 -29
View File
@@ -123,13 +123,13 @@
instability = GENE_INSTABILITY_MODERATE
mutation = CRYO
spelltype = /obj/effect/proc_holder/spell/targeted/cryokinesis
spelltype = /obj/effect/proc_holder/spell/targeted/click/cryokinesis
/datum/dna/gene/basic/grant_spell/cryo/New()
..()
block = GLOB.cryoblock
/obj/effect/proc_holder/spell/targeted/cryokinesis
/obj/effect/proc_holder/spell/targeted/click/cryokinesis
name = "Cryokinesis"
desc = "Drops the bodytemperature of another person."
panel = "Abilities"
@@ -137,45 +137,44 @@
charge_type = "recharge"
charge_max = 1200
clothes_req = 0
stat_allowed = 0
clothes_req = FALSE
stat_allowed = FALSE
click_radius = 0
auto_target_single = FALSE // Give the clueless geneticists a way out and to have them not target themselves
selection_activated_message = "<span class='notice'>Your mind grow cold. Click on a target to cast the spell.</span>"
selection_deactivated_message = "<span class='notice'>Your mind returns to normal.</span>"
allowed_type = /mob/living/carbon
invocation_type = "none"
range = 7
selection_type = "range"
include_user = 1
include_user = TRUE
var/list/compatible_mobs = list(/mob/living/carbon/human)
action_icon_state = "genetic_cryo"
/obj/effect/proc_holder/spell/targeted/cryokinesis/cast(list/targets, mob/user = usr)
if(!targets.len)
to_chat(user, "<span class='notice'>No target found in range.</span>")
return
/obj/effect/proc_holder/spell/targeted/click/cryokinesis/cast(list/targets, mob/user = usr)
var/mob/living/carbon/C = targets[1]
if(!iscarbon(C))
to_chat(user, "<span class='warning'>This will only work on normal organic beings.</span>")
return
if(COLDRES in C.mutations)
C.visible_message("<span class='warning'>A cloud of fine ice crystals engulfs [C.name], but disappears almost instantly!</span>")
return
var/handle_suit = 0
var/handle_suit = FALSE
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(istype(H.head, /obj/item/clothing/head/helmet/space))
if(istype(H.wear_suit, /obj/item/clothing/suit/space))
handle_suit = 1
handle_suit = TRUE
if(H.internal)
H.visible_message("<span class='warning'>[user] sprays a cloud of fine ice crystals, engulfing [H]!</span>",
"<span class='notice'>[user] sprays a cloud of fine ice crystals over your [H.head]'s visor.</span>")
add_attack_logs(user, C, "Cryokinesis")
else
H.visible_message("<span class='warning'>[user] sprays a cloud of fine ice crystals engulfing, [H]!</span>",
"<span class='warning'>[user] sprays a cloud of fine ice crystals cover your [H.head]'s visor and make it into your air vents!.</span>")
add_attack_logs(user, C, "Cryokinesis")
H.bodytemperature = max(0, H.bodytemperature - 100)
add_attack_logs(user, C, "Cryokinesis")
if(!handle_suit)
C.bodytemperature = max(0, C.bodytemperature - 200)
C.ExtinguishMob()
@@ -454,7 +453,7 @@
name = "Polymorphism"
desc = "Enables the subject to reconfigure their appearance to mimic that of others."
spelltype =/obj/effect/proc_holder/spell/targeted/polymorph
spelltype =/obj/effect/proc_holder/spell/targeted/click/polymorph
//cooldown = 1800
activation_messages = list("You don't feel entirely like yourself somehow.")
deactivation_messages = list("You feel secure in your identity.")
@@ -465,34 +464,36 @@
..()
block = GLOB.polymorphblock
/obj/effect/proc_holder/spell/targeted/polymorph
/obj/effect/proc_holder/spell/targeted/click/polymorph
name = "Polymorph"
desc = "Mimic the appearance of others!"
panel = "Abilities"
charge_max = 1800
clothes_req = 0
human_req = 1
stat_allowed = 0
clothes_req = FALSE
stat_allowed = FALSE
click_radius = -1 // Precision required
auto_target_single = FALSE // Safety to not turn into monkey (420)
selection_activated_message = "<span class='notice'>You body becomes unstable. Click on a target to cast transform into them.</span>"
selection_deactivated_message = "<span class='notice'>Your body calms down again.</span>"
allowed_type = /mob/living/carbon/human
invocation_type = "none"
range = 1
selection_type = "range"
action_icon_state = "genetic_poly"
/obj/effect/proc_holder/spell/targeted/polymorph/cast(list/targets, mob/user = usr)
var/mob/living/M = targets[1]
if(!ishuman(M))
to_chat(usr, "<span class='warning'>You can only change your appearance to that of another human.</span>")
return
/obj/effect/proc_holder/spell/targeted/click/polymorph/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/target = targets[1]
user.visible_message("<span class='warning'>[user]'s body shifts and contorts.</span>")
spawn(10)
if(M && user)
if(target && user)
playsound(user.loc, 'sound/goonstation/effects/gib.ogg', 50, 1)
var/mob/living/carbon/human/H = user
var/mob/living/carbon/human/target = M
H.UpdateAppearance(target.dna.UI)
H.real_name = target.real_name
H.name = target.name
+15 -23
View File
@@ -214,25 +214,21 @@
/obj/effect/proc_holder/spell/targeted/remotetalk/choose_targets(mob/user = usr)
var/list/targets = new /list()
var/list/validtargets = new /list()
var/turf/T = get_turf(user)
for(var/mob/living/M in range(14, T))
if(M && M.mind)
if(M == user)
continue
validtargets += M
var/list/validtargets = user.get_telepathic_targets()
if(!validtargets.len)
if(!length(validtargets))
to_chat(user, "<span class='warning'>There are no valid targets!</span>")
start_recharge()
return
targets += input("Choose the target to talk to.", "Targeting") as null|mob in validtargets
var/target_name = input("Choose the target to talk to.", "Targeting") as null|anything in validtargets
if(!targets.len || !targets[1]) //doesn't waste the spell
var/mob/living/target
if(!target_name || !(target = validtargets[target_name]))
revert_cast(user)
return
targets += target
perform(targets, user = user)
/obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets, mob/user = usr)
@@ -249,7 +245,7 @@
target.show_message("<span class='abductor'>You hear [user.real_name]'s voice: [say]</span>")
else
target.show_message("<span class='abductor'>You hear a voice that seems to echo around the room: [say]</span>")
user.show_message("<span class='abductor'>You project your mind into [target.name]: [say]</span>")
user.show_message("<span class='abductor'>You project your mind into [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"]: [say]</span>")
for(var/mob/dead/observer/G in GLOB.player_list)
G.show_message("<i>Telepathic message from <b>[user]</b> ([ghost_follow_link(user, ghost=G)]) to <b>[target]</b> ([ghost_follow_link(target, ghost=G)]): [say]</i>")
@@ -266,26 +262,22 @@
var/list/available_targets = list()
/obj/effect/proc_holder/spell/targeted/mindscan/choose_targets(mob/user = usr)
var/list/targets = new /list()
var/list/validtargets = new /list()
var/turf/T = get_turf(user)
for(var/mob/living/M in range(14, T))
if(M && M.mind)
if(M == user)
continue
validtargets += M
var/list/targets = list()
var/list/validtargets = user.get_telepathic_targets()
if(!validtargets.len)
if(!length(validtargets))
to_chat(user, "<span class='warning'>There are no valid targets!</span>")
start_recharge()
return
targets += input("Choose the target to listen to.", "Targeting") as null|mob in validtargets
var/target_name = input("Choose the target to listen to.", "Targeting") as null|anything in validtargets
if(!targets.len || !targets[1]) //doesn't waste the spell
var/mob/living/target
if(!target_name || !(target = validtargets[target_name]))
revert_cast(user)
return
targets += target
perform(targets, user = user)
/obj/effect/proc_holder/spell/targeted/mindscan/cast(list/targets, mob/user = usr)
@@ -295,7 +287,7 @@
var/message = "You feel your mind expand briefly... (Click to send a message.)"
if(REMOTE_TALK in target.mutations)
message = "You feel [user.real_name] request a response from you... (Click here to project mind.)"
user.show_message("<span class='abductor'>You offer your mind to [target.name].</span>")
user.show_message("<span class='abductor'>You offer your mind to [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"].</span>")
target.show_message("<span class='abductor'><A href='?src=[UID()];target=[target.UID()];user=[user.UID()]'>[message]</a></span>")
available_targets += target
addtimer(CALLBACK(src, .proc/removeAvailability, target), 100)
+2 -2
View File
@@ -18,7 +18,7 @@
intercepttext += "<BR>Note in the event of a quarantine breach or uncontrolled spread of the biohazard, the directive 7-10 may be upgraded to a directive 7-12.<BR>"
intercepttext += "Message ends."
if(2)
var/nukecode = "[rand(10000, 99999)]"
var/nukecode = rand(10000, 99999)
for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines)
if(bomb && bomb.r_code)
if(is_station_level(bomb.z))
@@ -40,7 +40,7 @@
aiPlayer.set_zeroth_law(law)
to_chat(aiPlayer, "Laws Updated: [law]")
print_command_report(intercepttext, interceptname)
print_command_report(intercepttext, interceptname, FALSE)
GLOB.event_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg', from = "[command_name()] Update")
/datum/station_state
@@ -112,7 +112,7 @@
feedback_add_details("changeling_powers","TS")
return TRUE
datum/action/changeling/sting/extract_dna
/datum/action/changeling/sting/extract_dna
name = "Extract DNA Sting"
desc = "We stealthily sting a target and extract their DNA. Costs 25 chemicals."
helptext = "Will give you the DNA of your target, allowing you to transform into them."
@@ -132,7 +132,7 @@ datum/action/changeling/sting/extract_dna
feedback_add_details("changeling_powers","ED")
return 1
datum/action/changeling/sting/mute
/datum/action/changeling/sting/mute
name = "Mute Sting"
desc = "We silently sting a human, completely silencing them for a short time. Costs 20 chemicals."
helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot."
@@ -147,7 +147,7 @@ datum/action/changeling/sting/mute
feedback_add_details("changeling_powers","MS")
return 1
datum/action/changeling/sting/blind
/datum/action/changeling/sting/blind
name = "Blind Sting"
desc = "We temporarily blind our victim. Costs 25 chemicals."
helptext = "This sting completely blinds a target for a short time, and leaves them with blurred vision for a long time."
@@ -165,7 +165,7 @@ datum/action/changeling/sting/blind
feedback_add_details("changeling_powers","BS")
return 1
datum/action/changeling/sting/LSD
/datum/action/changeling/sting/LSD
name = "Hallucination Sting"
desc = "We cause mass terror to our victim. Costs 10 chemicals."
helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds."
@@ -182,7 +182,7 @@ datum/action/changeling/sting/LSD
feedback_add_details("changeling_powers","HS")
return 1
datum/action/changeling/sting/cryo //Enable when mob cooling is fixed so that frostoil actually makes you cold, instead of mostly just hungry.
/datum/action/changeling/sting/cryo //Enable when mob cooling is fixed so that frostoil actually makes you cold, instead of mostly just hungry.
name = "Cryogenic Sting"
desc = "We silently sting our victim with a cocktail of chemicals that freezes them from the inside. Costs 15 chemicals."
helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing."
+2 -6
View File
@@ -270,14 +270,10 @@ GLOBAL_LIST_INIT(blacklisted_pylon_turfs, typecacheof(list(
/obj/effect/gateway/singularity_pull()
return
/obj/effect/gateway/Bumped(mob/M as mob|obj)
spawn(0)
return
/obj/effect/gateway/Bumped(atom/movable/AM)
return
/obj/effect/gateway/Crossed(AM as mob|obj, oldloc)
spawn(0)
return
/obj/effect/gateway/Crossed(atom/movable/AM, oldloc)
return
@@ -17,7 +17,8 @@
/obj/effect/mob_spawn/human/demonic_friend/Initialize(mapload, datum/mind/owner_mind, obj/effect/proc_holder/spell/targeted/summon_friend/summoning_spell)
. = ..()
owner = owner_mind
flavour_text = "<span class='big bold'>You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil.</span><b> Be aware that if you do not live up to [owner.name]'s expectations, [owner.p_they()] can send you back to hell with a single thought. [owner.name]'s death will also return you to hell.</b>"
description = "Be someone's loyal friend/slave. If they die, you die as well." //best I could think of in the moment, not sure how this role plays in practise, have never seen it.
flavour_text = "You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil. Be aware that if you do not live up to [owner.name]'s expectations, [owner.p_they()] can send you back to hell with a single thought. [owner.name]'s death will also return you to hell."
var/area/A = get_area(src)
if(!mapload && A)
notify_ghosts("\A friendship shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = TRUE)
+5 -5
View File
@@ -92,7 +92,7 @@ GLOBAL_LIST_INIT(lawlorify, list (
var/form = BASIC_DEVIL
var/exists = 0
var/static/list/dont_remove_spells = list(
/obj/effect/proc_holder/spell/targeted/summon_contract,
/obj/effect/proc_holder/spell/targeted/click/summon_contract,
/obj/effect/proc_holder/spell/targeted/conjure_item/violin,
/obj/effect/proc_holder/spell/targeted/summon_dancefloor)
var/ascendable = FALSE
@@ -326,12 +326,12 @@ GLOBAL_LIST_INIT(lawlorify, list (
owner.RemoveSpell(S)
/datum/devilinfo/proc/give_summon_contract()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_contract(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/summon_contract(null))
/datum/devilinfo/proc/give_base_spells(give_summon_contract = 0)
remove_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/pitchfork(null))
if(give_summon_contract)
give_summon_contract()
@@ -343,13 +343,13 @@ GLOBAL_LIST_INIT(lawlorify, list (
/datum/devilinfo/proc/give_lizard_spells()
remove_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/pitchfork(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
/datum/devilinfo/proc/give_true_spells()
remove_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/pitchfork/greater(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch(null))
+2 -2
View File
@@ -337,7 +337,7 @@
//////////////////////////
//Reports player logouts//
//////////////////////////
proc/display_roundstart_logout_report()
/proc/display_roundstart_logout_report()
var/msg = "<span class='notice'>Roundstart logout report</span>\n\n"
for(var/mob/living/L in GLOB.mob_list)
@@ -507,7 +507,7 @@ proc/display_roundstart_logout_report()
message_text += G.get_report()
message_text += "<hr>"
print_command_report(message_text, "[command_name()] Orders")
print_command_report(message_text, "[command_name()] Orders", FALSE)
/datum/game_mode/proc/declare_station_goal_completion()
for(var/V in station_goals)
+1 -1
View File
@@ -250,7 +250,7 @@ GLOBAL_LIST_EMPTY(cortical_stacks) //Stacks for 'leave nobody behind' objective.
..()
datum/game_mode/proc/auto_declare_completion_heist()
/datum/game_mode/proc/auto_declare_completion_heist()
if(raiders.len)
var/check_return = 0
if(GAMEMODE_IS_HEIST)
@@ -679,7 +679,7 @@
for(var/thing in GLOB.apcs)
var/obj/machinery/power/apc/apc
if(prob(30 * apc.overload))
apc.overload_lighting()
INVOKE_ASYNC(apc, /obj/machinery/power/apc.proc/overload_lighting)
else
apc.overload++
to_chat(owner, "<span class='notice'>Overcurrent applied to the powernet.</span>")
@@ -19,15 +19,13 @@
mob_name = "a swarmer"
death = FALSE
roundstart = FALSE
flavour_text = {"
<b>You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate.</b>
<b>Clicking on any object will try to consume it, either deconstructing it into its components, destroying it, or integrating any materials it has into you if successful.</b>
<b>Ctrl-Clicking on a mob will attempt to remove it from the area and place it in a safe environment for storage.</b>
<b>Objectives:</b>
important_info = "Follow your objectives, do not make the station inhospitable or try and kill crew."
flavour_text = "You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate."
description = {" Your goal is to create more of yourself by consuming the station. Clicking on any object will try to consume it, either deconstructing it into its components, destroying it, or integrating any materials it has into you if successful. Ctrl-Clicking on a mob will attempt to remove it from the area and place it in a safe environment for storage.
Objectives:
1. Consume resources and replicate until there are no more resources left.
2. Ensure that this location is fit for invasion at a later date; do not perform actions that would render it dangerous or inhospitable.
3. Biological resources will be harvested at a later date; do not harm them.
"}
3. Biological resources will be harvested at a later date; do not harm them."}
/obj/effect/mob_spawn/swarmer/Initialize(mapload)
. = ..()
@@ -7,7 +7,7 @@
var/swarmer_report = "<font size=3><b>[command_name()] High-Priority Update</b></span>"
swarmer_report += "<br><br>Our long-range sensors have detected an odd signal emanating from your station's gateway. We recommend immediate investigation of your gateway, as something may have come \
through."
print_command_report(swarmer_report, "Classified [command_name()] Update")
print_command_report(swarmer_report, "Classified [command_name()] Update", FALSE)
GLOB.event_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg')
/datum/event/spawn_swarmer/start()
@@ -363,7 +363,7 @@
if("Protector")
pickedtype = /mob/living/simple_animal/hostile/guardian/protector
var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user)
var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user, user)
G.summoner = user
G.summoned = TRUE
G.key = key
@@ -3,12 +3,12 @@
layer = LYING_MOB_LAYER
/mob/living/simple_animal/hostile/guardian/beam
melee_damage_lower = 7
melee_damage_upper = 7
melee_damage_lower = 12
melee_damage_upper = 12
attacktext = "shocks"
melee_damage_type = BURN
attack_sound = 'sound/machines/defib_zap.ogg'
damage_transfer = 0.7
damage_transfer = 0.6
range = 7
playstyle_string = "As a <b>Lightning</b> type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them."
magic_fluff_string = "..And draw the Tesla, a shocking, lethal source of power."
@@ -18,6 +18,17 @@
var/list/enemychains = list()
var/successfulshocks = 0
/mob/living/simple_animal/hostile/guardian/beam/New(loc, mob/living/user)
. = ..()
if(!user)
return
summoner = user
if(!(NO_SHOCK in summoner.mutations))
summoner.mutations.Add(NO_SHOCK)
/mob/living/simple_animal/hostile/guardian/beam/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
return FALSE //You are lightning, you should not be hurt by such things.
/mob/living/simple_animal/hostile/guardian/beam/AttackingTarget()
. = ..()
if(. && isliving(target) && target != src && target != summoner)
@@ -106,3 +117,8 @@
)
L.adjustFireLoss(1.2) //adds up very rapidly
. = 1
/mob/living/simple_animal/hostile/guardian/beam/death(gibbed)
if(summoner && (NO_SHOCK in summoner.mutations))
summoner.mutations.Remove(NO_SHOCK)
return ..()
@@ -25,6 +25,7 @@
overlays.Cut()
melee_damage_lower = initial(melee_damage_lower)
melee_damage_upper = initial(melee_damage_upper)
obj_damage = initial(obj_damage)
speed = initial(speed)
damage_transfer = 0.4
to_chat(src, "<span class='danger'>You switch to combat mode.</span>")
@@ -35,6 +36,7 @@
overlays.Add(shield_overlay)
melee_damage_lower = 2
melee_damage_upper = 2
obj_damage = 6 //40/7.5 rounded up, we don't want a protector guardian 2 shotting blob tiles while taking 5% damage, thats just silly.
speed = 1
damage_transfer = 0.05 //damage? what's damage?
to_chat(src, "<span class='danger'>You switch to protection mode.</span>")
@@ -153,7 +153,7 @@
else
name = "[initial(name)] ([cast_amount]E)"
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
/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
if(charge_counter < charge_max)
+2 -2
View File
@@ -3,7 +3,7 @@
/datum/game_mode
var/list/datum/mind/syndicates = list()
proc/issyndicate(mob/living/M as mob)
/proc/issyndicate(mob/living/M as mob)
return istype(M) && M.mind && SSticker && SSticker.mode && (M.mind in SSticker.mode.syndicates)
/datum/game_mode/nuclear
@@ -103,7 +103,7 @@ proc/issyndicate(mob/living/M as mob)
var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb")
var/nuke_code = "[rand(10000, 99999)]"
var/nuke_code = rand(10000, 99999)
var/leader_selected = 0
var/agent_number = 1
var/spawnpos = 1
+139 -164
View File
@@ -14,29 +14,29 @@ GLOBAL_VAR(bomb_set)
icon_state = "nuclearbomb0"
density = 1
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/deployable = 0
var/extended = 0
var/lighthack = 0
var/extended = FALSE
var/lighthack = FALSE
var/timeleft = 120
var/timing = 0
var/timing = FALSE
var/exploded = FALSE
var/r_code = "ADMIN"
var/code = ""
var/yes_code = 0
var/safety = 1
var/code
var/yes_code = FALSE
var/safety = TRUE
var/obj/item/disk/nuclear/auth = null
var/removal_stage = NUKE_INTACT
var/lastentered
var/is_syndicate = 0
var/is_syndicate = FALSE
use_power = NO_POWER_USE
var/previous_level = ""
var/datum/wires/nuclearbomb/wires = null
/obj/machinery/nuclearbomb/syndicate
is_syndicate = 1
is_syndicate = TRUE
/obj/machinery/nuclearbomb/New()
..()
r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn.
r_code = rand(10000, 99999.0) // Creates a random code upon object spawn.
wires = new/datum/wires/nuclearbomb(src)
previous_level = get_security_level()
GLOB.poi_list |= src
@@ -49,25 +49,24 @@ GLOBAL_VAR(bomb_set)
/obj/machinery/nuclearbomb/process()
if(timing)
GLOB.bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed.
GLOB.bomb_set = TRUE // So long as there is one nuke timing, it means one nuke is armed.
timeleft = max(timeleft - 2, 0) // 2 seconds per process()
if(timeleft <= 0)
INVOKE_ASYNC(src, .proc/explode)
SSnanoui.update_uis(src)
return
/obj/machinery/nuclearbomb/attackby(obj/item/O as obj, mob/user as mob, params)
if(istype(O, /obj/item/disk/nuclear))
if(extended)
if(!user.drop_item())
to_chat(user, "<span class='notice'>\The [O] is stuck to your hand!</span>")
to_chat(user, "<span class='notice'>[O] is stuck to your hand!</span>")
return
O.forceMove(src)
auth = O
add_fingerprint(user)
return attack_hand(user)
else
to_chat(user, "<span class='notice'>You need to deploy \the [src] first. Right click on the sprite, select 'Make Deployable' then click on \the [src] with an empty hand.</span>")
to_chat(user, "<span class='notice'>You need to deploy [src] first.</span>")
return
return ..()
@@ -171,181 +170,157 @@ GLOBAL_VAR(bomb_set)
removal_stage = NUKE_SEALANT_OPEN
/obj/machinery/nuclearbomb/attack_ghost(mob/user as mob)
if(extended)
attack_hand(user)
attack_hand(user)
/obj/machinery/nuclearbomb/attack_hand(mob/user as mob)
if(extended)
if(panel_open)
wires.Interact(user)
else
ui_interact(user)
else if(deployable)
if(removal_stage != NUKE_MOBILE)
anchored = 1
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring!</span>")
else
visible_message("<span class='warning'>\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
if(!lighthack)
flick("nuclearbombc", src)
icon_state = "nuclearbomb1"
extended = 1
return
/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "nuclear_bomb.tmpl", "Nuke Control Panel", 450, 550, state = GLOB.physical_state)
ui.open()
ui.set_auto_update(1)
/obj/machinery/nuclearbomb/ui_data(mob/user, datum/topic_state/state)
var/data[0]
data["is_syndicate"] = is_syndicate
data["hacking"] = 0
data["auth"] = is_auth(user)
if(is_auth(user))
if(yes_code)
data["authstatus"] = timing ? "Functional/Set" : "Functional"
else
data["authstatus"] = "Auth. S2"
if(panel_open)
wires.Interact(user)
else
if(timing)
data["authstatus"] = "Set"
else
data["authstatus"] = "Auth. S1"
tgui_interact(user)
/obj/machinery/nuclearbomb/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "NuclearBomb", name, 450, 300, master_ui, state)
ui.open()
/obj/machinery/nuclearbomb/tgui_data(mob/user)
var/list/data = list()
data["extended"] = extended
data["authdisk"] = is_auth(user)
data["diskname"] = auth ? auth.name : FALSE
data["authcode"] = yes_code
data["authfull"] = data["authdisk"] && data["authcode"]
data["safe"] = safety ? "Safe" : "Engaged"
data["time"] = timeleft
data["timer"] = timing
data["safety"] = safety
data["anchored"] = anchored
data["yescode"] = yes_code
data["message"] = "AUTH"
if(is_auth(user))
data["message"] = code
if(yes_code)
data["message"] = "*****"
return data
/obj/machinery/nuclearbomb/verb/make_deployable()
set category = "Object"
set name = "Make Deployable"
set src in oview(1)
if(usr.stat || !usr.canmove || usr.restrained())
return
if(deployable)
to_chat(usr, "<span class='warning'>You close several panels to make [src] undeployable.</span>")
deployable = 0
data["codemsg"] = "CLEAR CODE"
else if(code)
data["codemsg"] = "RE-ENTER CODE"
else
data["codemsg"] = "ENTER CODE"
else
to_chat(usr, "<span class='warning'>You adjust some panels to make [src] deployable.</span>")
deployable = 1
return
data["codemsg"] = "-----"
return data
/obj/machinery/nuclearbomb/proc/is_auth(var/mob/user)
if(auth)
return 1
return TRUE
else if(user.can_admin_interact())
return 1
return TRUE
else
return 0
return FALSE
/obj/machinery/nuclearbomb/Topic(href, href_list)
/obj/machinery/nuclearbomb/tgui_act(action, params)
if(..())
return 1
if(href_list["auth"])
if(auth)
auth.loc = loc
yes_code = 0
auth = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/disk/nuclear))
usr.drop_item()
I.loc = src
auth = I
if(is_auth(usr))
if(href_list["type"])
if(href_list["type"] == "E")
return
. = TRUE
if(exploded)
return
switch(action)
if("deploy")
if(removal_stage != NUKE_MOBILE)
anchored = TRUE
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring!</span>")
else
visible_message("<span class='warning'>[src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
if(!lighthack)
flick("nuclearbombc", src)
icon_state = "nuclearbomb1"
extended = TRUE
return
if("auth")
if(auth)
if(!usr.get_active_hand() && Adjacent(usr))
usr.put_in_hands(auth)
else
auth.forceMove(get_turf(src))
yes_code = FALSE
auth = null
else
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/disk/nuclear))
usr.drop_item()
I.forceMove(src)
auth = I
return
if(!is_auth(usr)) // All requests below here require NAD inserted.
return FALSE
switch(action)
if("code")
if(yes_code) // Clear code
code = null
yes_code = FALSE
return
// If no code set, enter new one
var/tempcode = input(usr, "Code", "Input Code", null) as num|null
if(tempcode)
code = min(max(round(tempcode), 0), 999999)
if(code == r_code)
yes_code = 1
yes_code = TRUE
code = null
else
code = "ERROR"
return
if(!yes_code) // All requests below here require both NAD inserted AND code correct
return
switch(action)
if("toggle_anchor")
if(removal_stage == NUKE_MOBILE)
anchored = FALSE
visible_message("<span class='warning'>[src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
else if(isinspace())
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
return FALSE
else
if(href_list["type"] == "R")
yes_code = 0
code = null
else
lastentered = text("[]", href_list["type"])
if(text2num(lastentered) == null)
var/turf/LOC = get_turf(usr)
message_admins("[key_name_admin(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: <a href='?_src_=vars;Vars=[UID()]'>[lastentered]</a>! ([LOC ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[LOC.x];Y=[LOC.y];Z=[LOC.z]'>JMP</a>" : "null"])", 0)
log_admin("EXPLOIT: [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]!")
else
code += lastentered
if(length(code) > 5)
code = "ERROR"
if(yes_code)
if(href_list["time"])
var/time = text2num(href_list["time"])
timeleft += time
timeleft = min(max(round(src.timeleft), 120), 600)
if(href_list["timer"])
if(timing == -1.0)
SSnanoui.update_uis(src)
return
if(safety)
to_chat(usr, "<span class='warning'>The safety is still on.</span>")
SSnanoui.update_uis(src)
return
timing = !(timing)
if(timing)
if(!lighthack)
icon_state = "nuclearbomb2"
if(!safety)
message_admins("[key_name_admin(usr)] engaged a nuclear bomb (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)")
if(!is_syndicate)
set_security_level("delta")
GLOB.bomb_set = 1 //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N
else
GLOB.bomb_set = 0
anchored = !(anchored)
if(anchored)
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring.</span>")
else
visible_message("<span class='warning'>The anchoring bolts slide back into the depths of [src].</span>")
return
if("set_time")
var/time = input(usr, "Detonation time (seconds, min 120, max 600)", "Input Time", 120) as num|null
if(time)
timeleft = min(max(round(time), 120), 600)
if("toggle_safety")
safety = !(safety)
if(safety)
if(!is_syndicate)
set_security_level(previous_level)
timing = FALSE
GLOB.bomb_set = FALSE
if("toggle_armed")
if(safety)
to_chat(usr, "<span class='notice'>The safety is still on.</span>")
return
timing = !(timing)
if(timing)
if(!lighthack)
icon_state = "nuclearbomb2"
if(!safety)
message_admins("[key_name_admin(usr)] engaged a nuclear bomb [ADMIN_JMP(src)]")
if(!is_syndicate)
set_security_level(previous_level)
GLOB.bomb_set = 0
if(!lighthack)
icon_state = "nuclearbomb1"
if(href_list["safety"])
safety = !(safety)
if(safety)
if(!is_syndicate)
set_security_level(previous_level)
timing = 0
GLOB.bomb_set = 0
if(href_list["anchor"])
if(removal_stage == NUKE_MOBILE)
anchored = 0
visible_message("<span class='warning'>\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.</span>")
SSnanoui.update_uis(src)
return
if(!isinspace())
anchored = !(anchored)
if(anchored)
visible_message("<span class='warning'>With a steely snap, bolts slide out of [src] and anchor it to the flooring.</span>")
else
visible_message("<span class='warning'>The anchoring bolts slide back into the depths of [src].</span>")
set_security_level("delta")
GLOB.bomb_set = TRUE // There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke
else
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
GLOB.bomb_set = TRUE
else
if(!is_syndicate)
set_security_level(previous_level)
GLOB.bomb_set = FALSE
if(!lighthack)
icon_state = "nuclearbomb1"
SSnanoui.update_uis(src)
/obj/machinery/nuclearbomb/blob_act(obj/structure/blob/B)
if(timing == -1.0)
if(exploded)
return
if(timing) //boom
INVOKE_ASYNC(src, .proc/explode)
@@ -360,11 +335,11 @@ GLOBAL_VAR(bomb_set)
#define NUKERANGE 80
/obj/machinery/nuclearbomb/proc/explode()
if(safety)
timing = 0
timing = FALSE
return
timing = -1.0
yes_code = 0
safety = 1
exploded = TRUE
yes_code = FALSE
safety = TRUE
if(!lighthack)
icon_state = "nuclearbomb3"
playsound(src,'sound/machines/alarm.ogg',100,0,5)
@@ -18,80 +18,56 @@
return 0
/obj/effect/proc_holder/spell/targeted/glare //Stuns and mutes a human target, depending on the distance relative to the shadowling
/obj/effect/proc_holder/spell/targeted/click/glare //Stuns and mutes a human target, depending on the distance relative to the shadowling
name = "Glare"
desc = "Stuns and mutes a target for a decent duration. Duration depends on the proximity to the target."
panel = "Shadowling Abilities"
charge_max = 300
clothes_req = 0
clothes_req = FALSE
range = 10 //has no effect beyond this range, so setting this makes invalid/useless targets not show up in popup
action_icon_state = "glare"
humans_only = 1 //useless since we override chose_targets, but might be used for other code later??? Might remove, idk
/obj/effect/proc_holder/spell/targeted/glare/choose_targets(mob/user)
var/list/possible_targets = list()
for(var/mob/living/carbon/human/target in view_or_range(range, user, "view"))
if(target.stat)
continue
if(is_shadow_or_thrall(target))
continue
possible_targets += target
var/mob/living/carbon/human/M
var/list/targets = list()
if(possible_targets.len == 1)//no choice involved
targets = possible_targets
else
M = input("Choose the target for the spell.", "Targeting") as mob in possible_targets
if(M in view_or_range(range, user, "view"))
targets += M
selection_activated_message = "<span class='notice'>Your prepare to your eyes for a stunning glare! <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>Your eyes relax... for now.</span>"
allowed_type = /mob/living/carbon/human
/obj/effect/proc_holder/spell/targeted/click/glare/cast_check(charge_check = TRUE, start_recharge = TRUE, mob/living/user = usr)
if(!shadowling_check(user))
return FALSE
return ..()
if(!targets.len) //doesn't waste the spell
revert_cast(user)
/obj/effect/proc_holder/spell/targeted/click/glare/valid_target(mob/living/carbon/human/target, user)
if(!..())
return FALSE
return !target.stat && !is_shadow_or_thrall(target)
/obj/effect/proc_holder/spell/targeted/click/glare/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/H = targets[1]
user.visible_message("<span class='warning'><b>[user]'s eyes flash a blinding red!</b></span>")
var/distance = get_dist(H, user)
if (distance <= 1) //Melee glare
H.visible_message("<span class='danger'>[H] freezes in place, [H.p_their()] eyes glazing over...</span>", \
"<span class='userdanger'>Your gaze is forcibly drawn into [user]'s eyes, and you are mesmerized by [user.p_their()] heavenly beauty...</span>")
H.Stun(10)
H.AdjustSilence(10)
else //Distant glare
var/loss = 10 - distance
var/duration = 10 - loss
if(loss <= 0)
to_chat(user, "<span class='danger'>Your glare had no effect over a such long distance!</span>")
return
H.slowed = duration
H.AdjustSilence(10)
to_chat(H, "<span class='userdanger'>A red light flashes across your vision, and your mind tries to resist them.. you are exhausted.. you are not able to speak..</span>")
addtimer(CALLBACK(src, .proc/do_stun, H, user, loss), duration SECONDS)
/obj/effect/proc_holder/spell/targeted/click/glare/proc/do_stun(mob/living/carbon/human/target, user, stun_time)
if(!istype(target) || target.stat)
return
perform(targets, user = user)
return
/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets, mob/user = usr)
for(var/mob/living/carbon/human/target in targets)
if(!ishuman(target))
to_chat(user, "<span class='warning'>You may only glare at humans!</span>")
charge_counter = charge_max
return
if(!shadowling_check(user))
charge_counter = charge_max
return
if(target.stat)
to_chat(user, "<span class='warning'>[target] must be conscious!</span>")
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
to_chat(user, "<span class='danger'>You don't see why you would want to paralyze an ally.</span>")
charge_counter = charge_max
return
var/mob/living/carbon/human/M = target
user.visible_message("<span class='warning'><b>[user]'s eyes flash a blinding red!</b></span>")
var/distance = get_dist(target, user)
if (distance <= 1) //Melee glare
target.visible_message("<span class='danger'>[target] freezes in place, [target.p_their()] eyes glazing over...</span>")
to_chat(target, "<span class='userdanger'>Your gaze is forcibly drawn into [user]'s eyes, and you are mesmerized by [user.p_their()] heavenly beauty...</span>")
target.Stun(10)
M.AdjustSilence(10)
else //Distant glare
var/loss = 10 - distance
var/duration = 10 - loss
if(loss <= 0)
to_chat(user, "<span class='danger'>Your glare had no effect over a such long distance!</span>")
return
target.slowed = duration
M.AdjustSilence(10)
to_chat(target, "<span class='userdanger'>A red light flashes across your vision, and your mind tries to resist them.. you are exhausted.. you are not able to speak..</span>")
sleep(duration*10)
target.Stun(loss)
target.visible_message("<span class='danger'>[target] freezes in place, [target.p_their()] eyes glazing over...</span>")
to_chat(target, "<span class='userdanger'>Red lights suddenly dance in your vision, and you are mesmerized by the heavenly lights...</span>")
target.Stun(stun_time)
target.visible_message("<span class='danger'>[target] freezes in place, [target.p_their()] eyes glazing over...</span>",\
"<span class='userdanger'>Red lights suddenly dance in your vision, and you are mesmerized by the heavenly lights...</span>")
/obj/effect/proc_holder/spell/aoe_turf/veil
name = "Veil"
@@ -109,9 +85,10 @@
return
to_chat(user, "<span class='shadowling'>You silently disable all nearby lights.</span>")
for(var/obj/structure/glowshroom/G in orange(2, user)) //Why the fuck was this in the loop below?
G.visible_message("<span class='warning'>\The [G] withers away!</span>")
G.visible_message("<span class='warning'>[G] withers away!</span>")
qdel(G)
for(var/turf/T in targets)
T.extinguish_light()
for(var/atom/A in T.contents)
A.extinguish_light()
@@ -227,96 +204,80 @@
M.reagents.add_reagent("frostoil", 15) //Half of a cryosting
/obj/effect/proc_holder/spell/targeted/enthrall //Turns a target into the shadowling's slave. This overrides all previous loyalties
/obj/effect/proc_holder/spell/targeted/click/enthrall //Turns a target into the shadowling's slave. This overrides all previous loyalties
name = "Enthrall"
desc = "Allows you to enslave a conscious, non-braindead, non-catatonic human to your will. This takes some time to cast."
panel = "Shadowling Abilities"
charge_max = 0
clothes_req = 0
clothes_req = FALSE
range = 1 //Adjacent to user
var/enthralling = 0
var/enthralling = FALSE
action_icon_state = "enthrall"
humans_only = 1
/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets, mob/user = usr)
click_radius = -1 // Precision baby
selection_activated_message = "<span class='notice'>Your prepare your mind to entrall a mortal. <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>Your mind relaxes.</span>"
allowed_type = /mob/living/carbon/human
/obj/effect/proc_holder/spell/targeted/click/enthrall/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
if(enthralling || !shadowling_check(user))
return FALSE
return ..()
/obj/effect/proc_holder/spell/targeted/click/enthrall/valid_target(mob/living/carbon/human/target, user)
if(!..())
return FALSE
return target.key && target.mind && !target.stat && !is_shadow_or_thrall(target) && target.client
/obj/effect/proc_holder/spell/targeted/click/enthrall/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/ling = user
listclearnulls(SSticker.mode.shadowling_thralls)
if(!(ling.mind in SSticker.mode.shadows))
return
if(!isshadowling(ling))
if(SSticker.mode.shadowling_thralls.len >= 5)
charge_counter = charge_max
return
for(var/mob/living/carbon/human/target in targets)
if(!in_range(user, target))
to_chat(user, "<span class='warning'>You need to be closer to enthrall [target].</span>")
charge_counter = charge_max
return
if(!target.key || !target.mind)
to_chat(user, "<span class='warning'>The target has no mind.</span>")
charge_counter = charge_max
return
if(target.stat)
to_chat(user, "<span class='warning'>The target must be conscious.</span>")
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
to_chat(user, "<span class='warning'>You can not enthrall allies.</span>")
charge_counter = charge_max
return
if(!ishuman(target))
to_chat(user, "<span class='warning'>You can only enthrall humans.</span>")
charge_counter = charge_max
return
if(enthralling)
to_chat(user, "<span class='warning'>You are already enthralling!</span>")
charge_counter = charge_max
return
if(!target.client)
to_chat(user, "<span class='warning'>[target]'s mind is vacant of activity.</span>")
enthralling = 1
to_chat(user, "<span class='danger'>This target is valid. You begin the enthralling.</span>")
to_chat(target, "<span class='userdanger'>[user] stares at you. You feel your head begin to pulse.</span>")
var/mob/living/carbon/human/target = targets[1]
enthralling = TRUE
to_chat(user, "<span class='danger'>This target is valid. You begin the enthralling.</span>")
to_chat(target, "<span class='userdanger'>[user] stares at you. You feel your head begin to pulse.</span>")
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
to_chat(user, "<span class='notice'>You place your hands to [target]'s head...</span>")
user.visible_message("<span class='warning'>[user] places [user.p_their()] hands onto the sides of [target]'s head!</span>")
if(2)
to_chat(user, "<span class='notice'>You begin preparing [target]'s mind as a blank slate...</span>")
user.visible_message("<span class='warning'>[user]'s palms flare a bright red against [target]'s temples!</span>")
to_chat(target, "<span class='danger'>A terrible red light floods your mind. You collapse as conscious thought is wiped away.</span>")
target.Weaken(12)
sleep(20)
if(ismindshielded(target))
to_chat(user, "<span class='notice'>They have a mindshield implant. You begin to deactivate it - this will take some time.</span>")
user.visible_message("<span class='warning'>[user] pauses, then dips [user.p_their()] head in concentration!</span>")
to_chat(target, "<span class='boldannounce'>Your mindshield implant becomes hot as it comes under attack!</span>")
sleep(100) //10 seconds - not spawn() so the enthralling takes longer
to_chat(user, "<span class='notice'>The nanobots composing the mindshield implant have been rendered inert. Now to continue.</span>")
user.visible_message("<span class='warning'>[user] relaxes again.</span>")
for(var/obj/item/implant/mindshield/L in target)
if(L && L.implanted)
qdel(L)
to_chat(target, "<span class='boldannounce'>Your mental protection implant unexpectedly falters, dims, dies.</span>")
if(3)
to_chat(user, "<span class='notice'>You begin planting the tumor that will control the new thrall...</span>")
user.visible_message("<span class='warning'>A strange energy passes from [user]'s hands into [target]'s head!</span>")
to_chat(target, "<span class='boldannounce'>You feel your memories twisting, morphing. A sense of horror dominates your mind.</span>")
if(!do_mob(user, target, 70)) //around 21 seconds total for enthralling, 31 for someone with a mindshield implant
to_chat(user, "<span class='warning'>The enthralling has been interrupted - your target's mind returns to its previous state.</span>")
to_chat(target, "<span class='userdanger'>You wrest yourself away from [user]'s hands and compose yourself</span>")
enthralling = 0
return
for(var/progress = 0, progress <= 3, progress++)
switch(progress)
if(1)
to_chat(user, "<span class='notice'>You place your hands to [target]'s head...</span>")
user.visible_message("<span class='warning'>[user] places [user.p_their()] hands onto the sides of [target]'s head!</span>")
if(2)
to_chat(user, "<span class='notice'>You begin preparing [target]'s mind as a blank slate...</span>")
user.visible_message("<span class='warning'>[user]'s palms flare a bright red against [target]'s temples!</span>")
to_chat(target, "<span class='danger'>A terrible red light floods your mind. You collapse as conscious thought is wiped away.</span>")
target.Weaken(12)
sleep(20)
if(ismindshielded(target))
to_chat(user, "<span class='notice'>They have a mindshield implant. You begin to deactivate it - this will take some time.</span>")
user.visible_message("<span class='warning'>[user] pauses, then dips [user.p_their()] head in concentration!</span>")
to_chat(target, "<span class='boldannounce'>Your mindshield implant becomes hot as it comes under attack!</span>")
sleep(100) //10 seconds - not spawn() so the enthralling takes longer
to_chat(user, "<span class='notice'>The nanobots composing the mindshield implant have been rendered inert. Now to continue.</span>")
user.visible_message("<span class='warning'>[user] relaxes again.</span>")
for(var/obj/item/implant/mindshield/L in target)
if(L && L.implanted)
qdel(L)
to_chat(target, "<span class='boldannounce'>Your mental protection implant unexpectedly falters, dims, dies.</span>")
if(3)
to_chat(user, "<span class='notice'>You begin planting the tumor that will control the new thrall...</span>")
user.visible_message("<span class='warning'>A strange energy passes from [user]'s hands into [target]'s head!</span>")
to_chat(target, "<span class='boldannounce'>You feel your memories twisting, morphing. A sense of horror dominates your mind.</span>")
if(!do_mob(user, target, 70)) //around 21 seconds total for enthralling, 31 for someone with a mindshield implant
to_chat(user, "<span class='warning'>The enthralling has been interrupted - your target's mind returns to its previous state.</span>")
to_chat(target, "<span class='userdanger'>You wrest yourself away from [user]'s hands and compose yourself</span>")
enthralling = FALSE
return
enthralling = 0
to_chat(user, "<span class='shadowling'>You have enthralled <b>[target]</b>!</span>")
target.visible_message("<span class='big'>[target] looks to have experienced a revelation!</span>", \
"<span class='warning'>False faces all d<b>ark not real not real not--</b></span>")
target.setOxyLoss(0) //In case the shadowling was choking them out
SSticker.mode.add_thrall(target.mind)
target.mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL
enthralling = FALSE
to_chat(user, "<span class='shadowling'>You have enthralled <b>[target]</b>!</span>")
target.visible_message("<span class='big'>[target] looks to have experienced a revelation!</span>", \
"<span class='warning'>False faces all d<b>ark not real not real not--</b></span>")
target.setOxyLoss(0) //In case the shadowling was choking them out
SSticker.mode.add_thrall(target.mind)
target.mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL
/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor //Resets a shadowling's species to normal, removes genetic defects, and re-equips their armor
name = "Rapid Re-Hatch"
@@ -404,7 +365,7 @@
reviveThrallAcquired = 1
to_chat(target, "<span class='shadowling'><i>The power of your thralls has granted you the <b>Black Recuperation</b> ability. \
This will, after a short time, bring a dead thrall completely back to life with no bodily defects.</i></span>")
target.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/reviveThrall(null))
target.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/reviveThrall(null))
if(thralls < victory_threshold)
to_chat(target, "<span class='shadowling'>You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present.</span>")
@@ -570,169 +531,170 @@
/obj/effect/proc_holder/spell/targeted/reviveThrall
/obj/effect/proc_holder/spell/targeted/click/reviveThrall
name = "Black Recuperation"
desc = "Revives or empowers a thrall."
panel = "Shadowling Abilities"
range = 1
charge_max = 600
clothes_req = 0
include_user = 0
clothes_req = FALSE
include_user = FALSE
action_icon_state = "revive_thrall"
humans_only = 1
click_radius = -1 // Precision baby
selection_activated_message = "<span class='notice'>You start focusing your powers on mending wounds of allies. <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>Your mind relaxes.</span>"
allowed_type = /mob/living/carbon/human
/obj/effect/proc_holder/spell/targeted/reviveThrall/cast(list/targets, mob/user = usr)
/obj/effect/proc_holder/spell/targeted/click/reviveThrall/can_cast(mob/user = usr)
if(!shadowling_check(user))
charge_counter = charge_max
return
for(var/mob/living/carbon/human/thrallToRevive in targets)
var/choice = alert(user,"Empower a living thrall or revive a dead one?",,"Empower","Revive","Cancel")
switch(choice)
if("Empower")
if(!is_thrall(thrallToRevive))
to_chat(user, "<span class='warning'>[thrallToRevive] is not a thrall.</span>")
charge_counter = charge_max
return
if(thrallToRevive.stat != CONSCIOUS)
to_chat(user, "<span class='warning'>[thrallToRevive] must be conscious to become empowered.</span>")
charge_counter = charge_max
return
if(isshadowlinglesser(thrallToRevive))
to_chat(user, "<span class='warning'>[thrallToRevive] is already empowered.</span>")
charge_counter = charge_max
return
var/empowered_thralls = 0
for(var/datum/mind/M in SSticker.mode.shadowling_thralls)
if(!ishuman(M.current))
return
var/mob/living/carbon/human/H = M.current
if(isshadowlinglesser(H))
empowered_thralls++
if(empowered_thralls >= EMPOWERED_THRALL_LIMIT)
to_chat(user, "<span class='warning'>You cannot spare this much energy. There are too many empowered thralls.</span>")
charge_counter = charge_max
return
user.visible_message("<span class='danger'>[user] places [user.p_their()] hands over [thrallToRevive]'s face, red light shining from beneath.</span>", \
"<span class='shadowling'>You place your hands on [thrallToRevive]'s face and begin gathering energy...</span>")
to_chat(thrallToRevive, "<span class='userdanger'>[user] places [user.p_their()] hands over your face. You feel energy gathering. Stand still...</span>")
if(!do_mob(user, thrallToRevive, 80))
to_chat(user, "<span class='warning'>Your concentration snaps. The flow of energy ebbs.</span>")
charge_counter = charge_max
return
to_chat(user, "<span class='shadowling'><b><i>You release a massive surge of power into [thrallToRevive]!</b></i></span>")
user.visible_message("<span class='boldannounce'><i>Red lightning surges into [thrallToRevive]'s face!</i></span>")
playsound(thrallToRevive, 'sound/weapons/egloves.ogg', 50, 1)
playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
user.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
thrallToRevive.Weaken(5)
thrallToRevive.visible_message("<span class='warning'><b>[thrallToRevive] collapses, [thrallToRevive.p_their()] skin and face distorting!</span>", \
"<span class='userdanger'><i>AAAAAAAAAAAAAAAAAAAGH-</i></span>")
sleep(20)
thrallToRevive.visible_message("<span class='warning'>[thrallToRevive] slowly rises, no longer recognizable as human.</span>", \
"<span class='shadowling'><b>You feel new power flow into you. You have been gifted by your masters. You now closely resemble them. You are empowered in \
darkness but wither slowly in light. In addition, you now have glare and true shadow walk.</b></span>")
thrallToRevive.set_species(/datum/species/shadow/ling/lesser)
thrallToRevive.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk)
thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare(null))
thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null))
if("Revive")
if(!is_thrall(thrallToRevive))
to_chat(user, "<span class='warning'>[thrallToRevive] is not a thrall.</span>")
charge_counter = charge_max
return
if(thrallToRevive.stat != DEAD)
to_chat(user, "<span class='warning'>[thrallToRevive] is not dead.</span>")
charge_counter = charge_max
return
user.visible_message("<span class='danger'>[user] kneels over [thrallToRevive], placing [user.p_their()] hands on [thrallToRevive.p_their()] chest.</span>", \
"<span class='shadowling'>You crouch over the body of your thrall and begin gathering energy...</span>")
thrallToRevive.notify_ghost_cloning("Your masters are resuscitating you! Re-enter your corpse if you wish to be brought to life.", source = thrallToRevive)
if(!do_mob(user, thrallToRevive, 30))
to_chat(user, "<span class='warning'>Your concentration snaps. The flow of energy ebbs.</span>")
charge_counter = charge_max
return
to_chat(user, "<span class='shadowling'><b><i>You release a massive surge of power into [thrallToRevive]!</b></i></span>")
user.visible_message("<span class='boldannounce'><i>Red lightning surges from [user]'s hands into [thrallToRevive]'s chest!</i></span>")
playsound(thrallToRevive, 'sound/weapons/egloves.ogg', 50, 1)
playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
user.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
sleep(10)
if(thrallToRevive.revive())
thrallToRevive.visible_message("<span class='boldannounce'>[thrallToRevive] heaves in breath, dim red light shining in [thrallToRevive.p_their()] eyes.</span>", \
"<span class='shadowling'><b><i>You have returned. One of your masters has brought you from the darkness beyond.</b></i></span>")
thrallToRevive.Weaken(4)
thrallToRevive.emote("gasp")
playsound(thrallToRevive, "bodyfall", 50, 1)
else
charge_counter = charge_max
return
return FALSE
return ..()
/obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle
/obj/effect/proc_holder/spell/targeted/click/reviveThrall/valid_target(mob/living/carbon/human/target, user)
if(!..())
return FALSE
return is_thrall(target)
/obj/effect/proc_holder/spell/targeted/click/reviveThrall/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/thrallToRevive = targets[1]
if(thrallToRevive.stat == CONSCIOUS)
if(isshadowlinglesser(thrallToRevive))
to_chat(user, "<span class='warning'>[thrallToRevive] is already empowered.</span>")
revert_cast(user)
return
var/empowered_thralls = 0
for(var/datum/mind/M in SSticker.mode.shadowling_thralls)
if(!ishuman(M.current))
return
var/mob/living/carbon/human/H = M.current
if(isshadowlinglesser(H))
empowered_thralls++
if(empowered_thralls >= EMPOWERED_THRALL_LIMIT)
to_chat(user, "<span class='warning'>You cannot spare this much energy. There are too many empowered thralls.</span>")
revert_cast(user)
return
user.visible_message("<span class='danger'>[user] places [user.p_their()] hands over [thrallToRevive]'s face, red light shining from beneath.</span>", \
"<span class='shadowling'>You place your hands on [thrallToRevive]'s face and begin gathering energy...</span>")
to_chat(thrallToRevive, "<span class='userdanger'>[user] places [user.p_their()] hands over your face. You feel energy gathering. Stand still...</span>")
if(!do_mob(user, thrallToRevive, 80))
to_chat(user, "<span class='warning'>Your concentration snaps. The flow of energy ebbs.</span>")
revert_cast(user)
return
to_chat(user, "<span class='shadowling'><b><i>You release a massive surge of power into [thrallToRevive]!</b></i></span>")
user.visible_message("<span class='boldannounce'><i>Red lightning surges into [thrallToRevive]'s face!</i></span>")
playsound(thrallToRevive, 'sound/weapons/egloves.ogg', 50, 1)
playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
user.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
thrallToRevive.Weaken(5)
thrallToRevive.visible_message("<span class='warning'><b>[thrallToRevive] collapses, [thrallToRevive.p_their()] skin and face distorting!</span>", \
"<span class='userdanger'><i>AAAAAAAAAAAAAAAAAAAGH-</i></span>")
sleep(20)
thrallToRevive.visible_message("<span class='warning'>[thrallToRevive] slowly rises, no longer recognizable as human.</span>", \
"<span class='shadowling'><b>You feel new power flow into you. You have been gifted by your masters. You now closely resemble them. You are empowered in \
darkness but wither slowly in light. In addition, you now have glare and true shadow walk.</b></span>")
thrallToRevive.set_species(/datum/species/shadow/ling/lesser)
thrallToRevive.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk)
thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/glare(null))
thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null))
else if(thrallToRevive.stat == DEAD)
user.visible_message("<span class='danger'>[user] kneels over [thrallToRevive], placing [user.p_their()] hands on [thrallToRevive.p_their()] chest.</span>", \
"<span class='shadowling'>You crouch over the body of your thrall and begin gathering energy...</span>")
thrallToRevive.notify_ghost_cloning("Your masters are resuscitating you! Re-enter your corpse if you wish to be brought to life.", source = thrallToRevive)
if(!do_mob(user, thrallToRevive, 30))
to_chat(user, "<span class='warning'>Your concentration snaps. The flow of energy ebbs.</span>")
revert_cast(user)
return
to_chat(user, "<span class='shadowling'><b><i>You release a massive surge of power into [thrallToRevive]!</b></i></span>")
user.visible_message("<span class='boldannounce'><i>Red lightning surges from [user]'s hands into [thrallToRevive]'s chest!</i></span>")
playsound(thrallToRevive, 'sound/weapons/egloves.ogg', 50, 1)
playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1)
user.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1)
sleep(10)
if(thrallToRevive.revive())
thrallToRevive.visible_message("<span class='boldannounce'>[thrallToRevive] heaves in breath, dim red light shining in [thrallToRevive.p_their()] eyes.</span>", \
"<span class='shadowling'><b><i>You have returned. One of your masters has brought you from the darkness beyond.</b></i></span>")
thrallToRevive.Weaken(4)
thrallToRevive.emote("gasp")
playsound(thrallToRevive, "bodyfall", 50, 1)
else
to_chat(user, "<span class='warning'>The target must be awake to empower or dead to revive.</span>")
revert_cast(user)
/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle
name = "Destroy Engines"
desc = "Extends the time of the emergency shuttle's arrival by ten minutes using a life force of our enemy. Shuttle will be unable to be recalled. This can only be used once."
panel = "Shadowling Abilities"
range = 1
clothes_req = 0
clothes_req = FALSE
charge_max = 600
click_radius = -1 // Precision baby
selection_activated_message = "<span class='notice'>You start gathering destructive powers to delay the shuttle. <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>Your mind relaxes.</span>"
allowed_type = /mob/living/carbon/human
action_icon_state = "extend_shuttle"
var/global/extendlimit = 0
/obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle/cast(list/targets, mob/user = usr)
/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/can_cast(mob/user = usr, charge_check = TRUE, show_message = FALSE)
if(!shadowling_check(user))
charge_counter = charge_max
return
return FALSE
if(extendlimit == 1)
to_chat(user, "<span class='warning'>Shuttle was already delayed.</span>")
charge_counter = charge_max
return
for(var/mob/living/carbon/human/target in targets)
if(target.stat)
charge_counter = charge_max
return
if(is_shadow_or_thrall(target))
to_chat(user, "<span class='warning'>[target] must not be an ally.</span>")
charge_counter = charge_max
return
if(SSshuttle.emergency.mode != SHUTTLE_CALL)
if(show_message)
to_chat(user, "<span class='warning'>Shuttle was already delayed.</span>")
return FALSE
if(SSshuttle.emergency.mode != SHUTTLE_CALL)
if(show_message)
to_chat(user, "<span class='warning'>The shuttle must be inbound only to the station.</span>")
charge_counter = charge_max
return
var/mob/living/carbon/human/M = target
user.visible_message("<span class='warning'>[user]'s eyes flash a bright red!</span>", \
"<span class='notice'>You begin to draw [M]'s life force.</span>")
M.visible_message("<span class='warning'>[M]'s face falls slack, [M.p_their()] jaw slightly distending.</span>", \
"<span class='boldannounce'>You are suddenly transported... far, far away...</span>")
extendlimit = 1
if(!do_after(user, 150, target = M))
extendlimit = 0
to_chat(M, "<span class='warning'>You are snapped back to reality, your haze dissipating!</span>")
to_chat(user, "<span class='warning'>You have been interrupted. The draw has failed.</span>")
return
to_chat(user, "<span class='notice'>You project [M]'s life force toward the approaching shuttle, extending its arrival duration!</span>")
M.visible_message("<span class='warning'>[M]'s eyes suddenly flare red. They proceed to collapse on the floor, not breathing.</span>", \
"<span class='warning'><b>...speeding by... ...pretty blue glow... ...touch it... ...no glow now... ...no light... ...nothing at all...</span>")
M.death()
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
var/more_minutes = 6000
var/timer = SSshuttle.emergency.timeLeft(1) + more_minutes
GLOB.event_announcement.Announce("Major system failure aboard the emergency shuttle. This will extend its arrival time by approximately 10 minutes and the shuttle is unable to be recalled.", "System Failure", 'sound/misc/notice1.ogg')
SSshuttle.emergency.setTimer(timer)
SSshuttle.emergency.canRecall = FALSE
user.mind.spell_list.Remove(src) //Can only be used once!
qdel(src)
return FALSE
return ..()
/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/valid_target(mob/living/carbon/human/target, user)
if(!..())
return FALSE
return !target.stat && !is_shadow_or_thrall(target)
/obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/target = targets[1]
user.visible_message("<span class='warning'>[user]'s eyes flash a bright red!</span>", \
"<span class='notice'>You begin to draw [target]'s life force.</span>")
target.visible_message("<span class='warning'>[target]'s face falls slack, [target.p_their()] jaw slightly distending.</span>", \
"<span class='boldannounce'>You are suddenly transported... far, far away...</span>")
extendlimit = 1
if(!do_after(user, 150, target = target))
extendlimit = 0
to_chat(target, "<span class='warning'>You are snapped back to reality, your haze dissipating!</span>")
to_chat(user, "<span class='warning'>You have been interrupted. The draw has failed.</span>")
return
to_chat(user, "<span class='notice'>You project [target]'s life force toward the approaching shuttle, extending its arrival duration!</span>")
target.visible_message("<span class='warning'>[target]'s eyes suddenly flare red. They proceed to collapse on the floor, not breathing.</span>", \
"<span class='warning'><b>...speeding by... ...pretty blue glow... ...touch it... ...no glow now... ...no light... ...nothing at all...</span>")
target.death()
if(SSshuttle.emergency.mode == SHUTTLE_CALL)
var/more_minutes = 6000
var/timer = SSshuttle.emergency.timeLeft(1) + more_minutes
GLOB.event_announcement.Announce("Major system failure aboard the emergency shuttle. This will extend its arrival time by approximately 10 minutes and the shuttle is unable to be recalled.", "System Failure", 'sound/misc/notice1.ogg')
SSshuttle.emergency.setTimer(timer)
SSshuttle.emergency.canRecall = FALSE
user.mind.spell_list.Remove(src) //Can only be used once!
qdel(src)
// ASCENDANT ABILITIES BEYOND THIS POINT //
/obj/effect/proc_holder/spell/targeted/annihilate
/obj/effect/proc_holder/spell/targeted/click/annihilate
name = "Annihilate"
desc = "Gibs someone instantly."
panel = "Ascendant"
range = 7
charge_max = 0
clothes_req = 0
charge_max = FALSE
clothes_req = FALSE
action_icon_state = "annihilate"
selection_activated_message = "<span class='notice'>You start thinking about gibs. <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>Your mind relaxes.</span>"
allowed_type = /mob/living/carbon/human
/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets, mob/user = usr)
/obj/effect/proc_holder/spell/targeted/click/annihilate/cast(list/targets, mob/user = usr)
var/mob/living/simple_animal/ascendant_shadowling/SHA = user
if(SHA.phasing)
to_chat(user, "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>")
@@ -755,45 +717,42 @@
/obj/effect/proc_holder/spell/targeted/hypnosis
/obj/effect/proc_holder/spell/targeted/click/hypnosis
name = "Hypnosis"
desc = "Instantly enthralls a human."
panel = "Ascendant"
range = 7
charge_max = 0
clothes_req = 0
charge_max = FALSE
clothes_req = FALSE
action_icon_state = "enthrall"
/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets, mob/user = usr)
var/mob/living/simple_animal/ascendant_shadowling/SHA = user
if(SHA.phasing)
charge_counter = charge_max
to_chat(user, "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>")
return
click_radius = -1
selection_activated_message = "<span class='notice'>You start preparing to mindwash over a mortal mind. <B>Left-click to cast at a target!</B></span>"
selection_deactivated_message = "<span class='notice'>Your mind relaxes.</span>"
allowed_type = /mob/living/carbon/human
for(var/mob/living/carbon/human/target in targets)
if(is_shadow_or_thrall(target))
to_chat(user, "<span class='warning'>You cannot enthrall an ally.</span>")
charge_counter = charge_max
return
if(!target.ckey || !target.mind)
to_chat(user, "<span class='warning'>The target has no mind.</span>")
charge_counter = charge_max
return
if(target.stat)
to_chat(user, "<span class='warning'>The target must be conscious.</span>")
charge_counter = charge_max
return
if(!ishuman(target))
to_chat(user, "<span class='warning'>You can only enthrall humans.</span>")
charge_counter = charge_max
return
/obj/effect/proc_holder/spell/targeted/click/hypnosis/can_cast(mob/living/simple_animal/ascendant_shadowling/user = usr, charge_check = TRUE, show_message = FALSE)
if(!istype(user))
return FALSE
if(user.phasing)
if(show_message)
to_chat(user, "<span class='warning'>You are not in the same plane of existence. Unphase first.</span>")
return FALSE
return ..()
to_chat(user, "<span class='shadowling'>You instantly rearrange <b>[target]</b>'s memories, hyptonitizing [target.p_them()] into a thrall.</span>")
to_chat(target, "<span class='userdanger'><font size=3>An agonizing spike of pain drives into your mind, and--</font></span>")
SSticker.mode.add_thrall(target.mind)
target.mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL
target.add_language("Shadowling Hivemind")
/obj/effect/proc_holder/spell/targeted/click/hypnosis/valid_target(mob/living/carbon/human/target, user)
if(!..())
return FALSE
return !is_shadow_or_thrall(target) && target.ckey && target.mind && !target.stat
/obj/effect/proc_holder/spell/targeted/click/hypnosis/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/target = targets[1]
to_chat(user, "<span class='shadowling'>You instantly rearrange <b>[target]</b>'s memories, hyptonitizing [target.p_them()] into a thrall.</span>")
to_chat(target, "<span class='userdanger'><font size=3>An agonizing spike of pain drives into your mind, and--</font></span>")
SSticker.mode.add_thrall(target.mind)
target.mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL
target.add_language("Shadowling Hivemind")
@@ -99,14 +99,14 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u
to_chat(H, "<span class='shadowling'><b><i>Your powers are awoken. You may now live to your fullest extent. Remember your goal. Cooperate with your thralls and allies.</b></i></span>")
H.ExtinguishMob()
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_vision(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/enthrall(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/glare(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/enthrall(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/glare(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/veil(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/flashfreeze(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/collective_mind(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_regenarmor(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle(null))
H.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/shadowling_extend_shuttle(null))
QDEL_NULL(H.hud_used)
H.hud_used = new /datum/hud/human(H, ui_style2icon(H.client.prefs.UI_style), H.client.prefs.UI_style_color, H.client.prefs.UI_style_alpha)
@@ -163,7 +163,7 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u
to_chat(M, "<span class='userdanger'>An immense pressure slams you onto the ground!</span>")
for(var/thing in GLOB.apcs)
var/obj/machinery/power/apc/A = thing
A.overload_lighting()
INVOKE_ASYNC(A, /obj/machinery/power/apc.proc/overload_lighting)
var/mob/living/simple_animal/ascendant_shadowling/A = new /mob/living/simple_animal/ascendant_shadowling(H.loc)
A.announce("VYSHA NERADA YEKHEZET U'RUU!!", 5, 'sound/hallucinations/veryfar_noise.ogg')
for(var/obj/effect/proc_holder/spell/S in H.mind.spell_list)
@@ -172,8 +172,8 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u
H.mind.transfer_to(A)
A.name = H.real_name
A.languages = H.languages
A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/annihilate(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/hypnosis(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/annihilate(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/hypnosis(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_phase_shift(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/ascendant_storm(null))
A.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit(null))
+1 -1
View File
@@ -57,7 +57,7 @@
typepath = /obj/item/aicard
location_override = "AI Satellite. An intellicard for transportation can be found in Tech Storage, Science Department or manufactured"
datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C)
/datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C)
if(..())
for(var/mob/living/silicon/ai/A in C)
if(istype(A, /mob/living/silicon/ai) && A.stat != 2) //See if any AI's are alive inside that card.
+12 -16
View File
@@ -82,22 +82,10 @@
/datum/game_mode/proc/auto_declare_completion_traitor()
if(traitors.len)
var/text = "<FONT size = 2><B>The traitors were:</B></FONT>"
var/text = "<FONT size = 2><B>The traitors were:</B></FONT><br>"
for(var/datum/mind/traitor in traitors)
var/traitorwin = 1
text += "<br>[traitor.key] was [traitor.name] ("
if(traitor.current)
if(traitor.current.stat == DEAD)
text += "died"
else
text += "survived"
if(traitor.current.real_name != traitor.name)
text += " as [traitor.current.real_name]"
else
text += "body destroyed"
text += ")"
text += printplayer(traitor)
var/TC_uses = 0
var/uplink_true = 0
@@ -131,12 +119,20 @@
if(traitorwin)
text += "<br><font color='green'><B>The [special_role_text] was successful!</B></font>"
text += "<br><font color='green'><B>The [special_role_text] was successful!</B></font><br>"
feedback_add_details("traitor_success","SUCCESS")
else
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font>"
text += "<br><font color='red'><B>The [special_role_text] has failed!</B></font><br>"
feedback_add_details("traitor_success","FAIL")
if(length(SSticker.mode.implanted))
text += "<br><br><FONT size = 2><B>The mindslaves were:</B></FONT><br>"
for(var/datum/mind/mindslave in SSticker.mode.implanted)
text += printplayer(mindslave)
var/datum/mind/master_mind = SSticker.mode.implanted[mindslave]
var/mob/living/carbon/human/master = master_mind.current
text += " (slaved by: <b>[master]</b>)<br>"
var/phrases = jointext(GLOB.syndicate_code_phrase, ", ")
var/responses = jointext(GLOB.syndicate_code_response, ", ")
+13 -4
View File
@@ -279,6 +279,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
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>")
draining = null
@@ -291,13 +292,10 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
H.LAssailant = owner
while(do_mob(owner, H, 50))
if(!(owner.mind in SSticker.mode.vampires))
to_chat(owner, "<span class='warning'>Your fangs have disappeared!</span>")
to_chat(owner, "<span class='userdanger'>Your fangs have disappeared!</span>")
return
old_bloodtotal = bloodtotal
old_bloodusable = bloodusable
if(!H.blood_volume)
to_chat(owner, "<span class='warning'>They've got no blood left to give.</span>")
break
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
@@ -312,6 +310,17 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha
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()
H.blood_volume = max(H.blood_volume - 25, 0)
//Blood level warnings (Code 'borrowed' from Fulp)
if(H.blood_volume)
if(H.blood_volume <= BLOOD_VOLUME_BAD && blood_volume_warning > BLOOD_VOLUME_BAD)
to_chat(owner, "<span class='danger'>Your victim's blood volume is dangerously low.</span>")
else if(H.blood_volume <= BLOOD_VOLUME_OKAY && blood_volume_warning > BLOOD_VOLUME_OKAY)
to_chat(owner, "<span class='warning'>Your victim's blood is at an unsafe level.</span>")
blood_volume_warning = H.blood_volume //Set to blood volume, so that you only get the message once
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
@@ -15,7 +15,7 @@
if(!gain_desc)
gain_desc = "You have gained \the [src] ability."
/obj/effect/proc_holder/spell/vampire/cast_check(skipcharge = 0, mob/living/user = usr)
/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))
@@ -45,7 +45,7 @@
return 0
return ..()
/obj/effect/proc_holder/spell/vampire/can_cast(mob/user = usr)
/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))
+6 -2
View File
@@ -61,7 +61,7 @@
switch(href_list["school"])
if("destruction")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/fireball(null))
to_chat(M, "<B>Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball.")
if("bluespace")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
@@ -74,7 +74,7 @@
to_chat(M, "<B>Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall.")
if("robeless")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/click/mind_transfer(null))
to_chat(M, "<B>Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
M.equip_to_slot_or_del(new /obj/item/radio/headset(M), slot_l_ear)
@@ -836,6 +836,10 @@ GLOBAL_LIST_EMPTY(multiverse)
var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
target.say(wgw)
log_game("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.")
log_say("Wicker doll say to [target][target.key]: [wgw]", user)
log_admin("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.")
user.create_log(SAY_LOG, "forced [target] to say [wgw] through [src].", target)
target.create_log(SAY_LOG, "was forced to say [wgw] through [src] by [user].", user)
if("eyes")
user.set_machine(src)
user.reset_perspective(target)
+8 -8
View File
@@ -132,7 +132,7 @@
/datum/spellbook_entry/horseman
name = "Curse of the Horseman"
spell_type = /obj/effect/proc_holder/spell/targeted/horsemask
spell_type = /obj/effect/proc_holder/spell/targeted/click/horsemask
log_name = "HH"
category = "Offensive"
@@ -144,7 +144,7 @@
/datum/spellbook_entry/fireball
name = "Fireball"
spell_type = /obj/effect/proc_holder/spell/fireball
spell_type = /obj/effect/proc_holder/spell/targeted/click/fireball
log_name = "FB"
category = "Offensive"
@@ -257,7 +257,7 @@
/datum/spellbook_entry/mindswap
name = "Mindswap"
spell_type = /obj/effect/proc_holder/spell/targeted/mind_transfer
spell_type = /obj/effect/proc_holder/spell/targeted/click/mind_transfer
log_name = "MT"
category = "Mobility"
@@ -877,7 +877,7 @@
return
/obj/item/spellbook/oneuse/fireball
spell = /obj/effect/proc_holder/spell/fireball
spell = /obj/effect/proc_holder/spell/targeted/click/fireball
spellname = "fireball"
icon_state = "bookfireball"
desc = "This book feels warm to the touch."
@@ -910,7 +910,7 @@
user.EyeBlind(10)
/obj/item/spellbook/oneuse/mindswap
spell = /obj/effect/proc_holder/spell/targeted/mind_transfer
spell = /obj/effect/proc_holder/spell/targeted/click/mind_transfer
spellname = "mindswap"
icon_state = "bookmindswap"
desc = "This book's cover is pristine, though its pages look ragged and torn."
@@ -934,8 +934,8 @@
to_chat(user, "<span class='notice'>You stare at the book some more, but there doesn't seem to be anything else to learn...</span>")
return
var/obj/effect/proc_holder/spell/targeted/mind_transfer/swapper = new
swapper.cast(user, stored_swap, 1)
var/obj/effect/proc_holder/spell/targeted/click/mind_transfer/swapper = new
swapper.cast(user, stored_swap)
to_chat(stored_swap, "<span class='warning'>You're suddenly somewhere else... and someone else?!</span>")
to_chat(user, "<span class='warning'>Suddenly you're staring at [src] again... where are you, who are you?!</span>")
@@ -966,7 +966,7 @@
user.Weaken(20)
/obj/item/spellbook/oneuse/horsemask
spell = /obj/effect/proc_holder/spell/targeted/horsemask
spell = /obj/effect/proc_holder/spell/targeted/click/horsemask
spellname = "horses"
icon_state = "bookhorses"
desc = "This book is more horse than your mind has room for."
+8 -11
View File
@@ -45,9 +45,8 @@
for(var/datum/mind/wizard in wizards)
log_game("[key_name(wizard)] has been selected as a Wizard")
forge_wizard_objectives(wizard)
//learn_basic_spells(wizard.current)
equip_wizard(wizard.current)
name_wizard(wizard.current)
INVOKE_ASYNC(src, .proc/name_wizard, wizard.current)
greet_wizard(wizard)
if(use_huds)
update_wiz_icons_added(wizard)
@@ -89,17 +88,15 @@
var/wizard_name_first = pick(GLOB.wizard_first)
var/wizard_name_second = pick(GLOB.wizard_second)
var/randomname = "[wizard_name_first] [wizard_name_second]"
spawn(0)
var/newname = sanitize(copytext(input(wizard_mob, "You are the Space Wizard. Would you like to change your name to something else?", "Name change", randomname) as null|text,1,MAX_NAME_LEN))
var/newname = sanitize(copytext(input(wizard_mob, "You are the Space Wizard. Would you like to change your name to something else?", "Name change", randomname) as null|text,1,MAX_NAME_LEN))
if(!newname)
newname = randomname
if(!newname)
newname = randomname
wizard_mob.real_name = newname
wizard_mob.name = newname
if(wizard_mob.mind)
wizard_mob.mind.name = newname
return
wizard_mob.real_name = newname
wizard_mob.name = newname
if(wizard_mob.mind)
wizard_mob.mind.name = newname
/datum/game_mode/proc/greet_wizard(var/datum/mind/wizard, var/you_are=1)
addtimer(CALLBACK(wizard.current, /mob/.proc/playsound_local, null, 'sound/ambience/antag/ragesmages.ogg', 100, 0), 30)
+1 -1
View File
@@ -18,7 +18,7 @@
Care should be taken in hiding the item you choose as your phylactery after using Bind Soul, as you cannot revive if it destroyed or too far from your body! <br><br> \
</i>Provides Bind Soul, Ethereal Jaunt, Fireball, Rod Form, Disable Tech, and Greater Forcewall.<i>"
log_name = "DL"
spells_path = list(/obj/effect/proc_holder/spell/targeted/lichdom, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/fireball, \
spells_path = list(/obj/effect/proc_holder/spell/targeted/lichdom, /obj/effect/proc_holder/spell/targeted/ethereal_jaunt, /obj/effect/proc_holder/spell/targeted/click/fireball, \
/obj/effect/proc_holder/spell/targeted/rod_form, /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech, /obj/effect/proc_holder/spell/targeted/forcewall/greater)
is_ragin_restricted = TRUE
+5 -4
View File
@@ -426,6 +426,7 @@
//gets the alt title, failing that the actual job rank
//this is unused
// THEN WHY IS IT STILL HERE?? -AA07, 2020-07-31
/obj/proc/sdsdsd() //GetJobDisplayName
if(!istype(src, /obj/item/pda) && !istype(src,/obj/item/card/id))
return
@@ -442,7 +443,7 @@
return "Unknown"
proc/GetIdCard(var/mob/living/carbon/human/H)
/proc/GetIdCard(var/mob/living/carbon/human/H)
if(H.wear_id)
var/id = H.wear_id.GetID()
if(id)
@@ -451,7 +452,7 @@ proc/GetIdCard(var/mob/living/carbon/human/H)
var/obj/item/I = H.get_active_hand()
return I.GetID()
proc/FindNameFromID(var/mob/living/carbon/human/H)
/proc/FindNameFromID(var/mob/living/carbon/human/H)
ASSERT(istype(H))
var/obj/item/card/id/C = H.get_active_hand()
if( istype(C) || istype(C, /obj/item/pda) )
@@ -480,7 +481,7 @@ proc/FindNameFromID(var/mob/living/carbon/human/H)
if(ID)
return ID.registered_name
proc/get_all_job_icons() //For all existing HUD icons
/proc/get_all_job_icons() //For all existing HUD icons
return GLOB.joblist + list("Prisoner")
/obj/proc/GetJobName() //Used in secHUD icon generation
@@ -511,7 +512,7 @@ proc/get_all_job_icons() //For all existing HUD icons
return "Unknown" //Return unknown if none of the above apply
proc/get_accesslist_static_data(num_min_region = REGION_GENERAL, num_max_region = REGION_COMMAND)
/proc/get_accesslist_static_data(num_min_region = REGION_GENERAL, num_max_region = REGION_COMMAND)
var/list/retval
for(var/i in num_min_region to num_max_region)
var/list/accesses = list()
+1 -1
View File
@@ -94,7 +94,7 @@
)
cybernetic_implants = list(
/obj/item/organ/internal/cyberimp/eyes/xray,
/obj/item/organ/internal/cyberimp/brain/anti_stun,
/obj/item/organ/internal/cyberimp/brain/anti_stun/hardened,
/obj/item/organ/internal/cyberimp/chest/nutriment/plus,
/obj/item/organ/internal/cyberimp/arm/combat/centcom
)
+1 -1
View File
@@ -18,7 +18,7 @@
ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS,
ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINISAT, ACCESS_MECHANIC, ACCESS_MINERAL_STOREROOM)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_ENGINEERING
outfit = /datum/outfit/job/chief_engineer
+1 -1
View File
@@ -16,7 +16,7 @@
ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_PSYCHIATRIST, ACCESS_MAINT_TUNNELS, ACCESS_PARAMEDIC, ACCESS_MINERAL_STOREROOM)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_MEDICAL
outfit = /datum/outfit/job/cmo
+1 -1
View File
@@ -18,7 +18,7 @@
ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_GATEWAY, ACCESS_XENOARCH, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_NETWORK)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_SCIENCE
// All science-y guys get bonuses for maxing out their tech.
required_objectives = list(
+2 -2
View File
@@ -18,7 +18,7 @@
ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_PILOT, ACCESS_WEAPONS)
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_SECURITY
disabilities_allowed = 0
outfit = /datum/outfit/job/hos
@@ -64,7 +64,7 @@
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_WEAPONS)
minimal_player_age = 21
exp_requirements = 600
exp_type = EXP_TYPE_CREW
exp_type = EXP_TYPE_SECURITY
outfit = /datum/outfit/job/warden
/datum/outfit/job/warden
+2 -2
View File
@@ -13,7 +13,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
access = list() //See get_access()
minimal_access = list() //See get_access()
minimal_player_age = 30
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_COMMAND
disabilities_allowed = 0
outfit = /datum/outfit/job/captain
@@ -67,7 +67,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca
req_admin_notify = 1
is_command = 1
minimal_player_age = 21
exp_requirements = 300
exp_requirements = 1200
exp_type = EXP_TYPE_COMMAND
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,

Some files were not shown because too many files have changed in this diff Show More