Merge branch 'master' into placeholder

This commit is contained in:
Ferner
2021-01-02 23:21:47 +01:00
117 changed files with 2994 additions and 11056 deletions
+12
View File
@@ -81,6 +81,18 @@ For a basic setup, simply copy every file from config/example to config.
For more advanced setups, setting the server `tick_lag` in the config as well as configuring SQL are good first steps.
#### Permissions
Permissions with file-based config are handled through `admin_ranks.json`
and `admins.txt`. To add yourself as the admin, simply find the rank with
the suitable permissions from the `admin_ranks.json` file, copy its `"name"`
field value, and input that into `admins.txt` like so:
```cfg
myckeyhere - Head Admin/Dev
```
---
### SQL Setup
@@ -0,0 +1,19 @@
--
-- Implemented in PR TODO.
-- Adds a `ss13_characters_custom_items` table to replace the old custom item system.
--
CREATE TABLE `ss13_characters_custom_items` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`char_id` INT(11) NOT NULL,
`item_path` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_ci',
`item_data` LONGTEXT NOT NULL COLLATE 'utf8mb4_bin',
`req_titles` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8mb4_bin',
`additional_data` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_ci',
PRIMARY KEY (`id`) USING BTREE,
INDEX `FK_ss13_characters_custom_items_ss13_characters` (`char_id`) USING BTREE,
CONSTRAINT `FK_ss13_characters_custom_items_ss13_characters` FOREIGN KEY (`char_id`) REFERENCES `ss13_characters` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
@@ -0,0 +1,8 @@
--
-- Implemented in PR #10718.
-- Adds a `Hair Gradient Style and Hair Gradient Color` columns for hair gradient preferences.
--
ALTER TABLE `ss13_characters`
ADD COLUMN `grad_colour` varchar(7) DEFAULT NULL AFTER `facial_colour`,
ADD COLUMN `gradient_style` varchar(32) DEFAULT NULL AFTER `facial_style`;
+2 -1
View File
@@ -1183,7 +1183,6 @@
#include "code\modules\admin\verbs\bluespacetech.dm"
#include "code\modules\admin\verbs\BrokenInhands.dm"
#include "code\modules\admin\verbs\buildmode.dm"
#include "code\modules\admin\verbs\check_customitem_activity.dm"
#include "code\modules\admin\verbs\cinematic.dm"
#include "code\modules\admin\verbs\clear_toxins.dm"
#include "code\modules\admin\verbs\custom_event.dm"
@@ -1378,6 +1377,7 @@
#include "code\modules\clothing\factions\gadpathur.dm"
#include "code\modules\clothing\factions\goldendeep.dm"
#include "code\modules\clothing\factions\himeo.dm"
#include "code\modules\clothing\factions\idris.dm"
#include "code\modules\clothing\factions\konyang.dm"
#include "code\modules\clothing\factions\vysoka.dm"
#include "code\modules\clothing\glasses\glasses.dm"
@@ -1661,6 +1661,7 @@
#include "code\modules\heavy_vehicle\mech_construction.dm"
#include "code\modules\heavy_vehicle\mech_damage.dm"
#include "code\modules\heavy_vehicle\mech_damage_immunity.dm"
#include "code\modules\heavy_vehicle\mech_helpers.dm"
#include "code\modules\heavy_vehicle\mech_icon.dm"
#include "code\modules\heavy_vehicle\mech_interaction.dm"
#include "code\modules\heavy_vehicle\mech_life.dm"
+1
View File
@@ -75,6 +75,7 @@
#define CE_BLOODRESTORE "bloodrestore" // Iron/nutriment
#define CE_BRAIN_REGEN "brainfix" // Alkysine
#define CE_OXYGENATED "oxygenated" // Dexalin
#define CE_BLOODCLOT "bloodclot" // Coagzolug
// Deal damage
#define CE_BREATHLOSS "breathloss"
+1
View File
@@ -38,6 +38,7 @@
#define BLOCK_GAS_SMOKE_EFFECT 0x10 // Blocks the effect that chemical clouds would have on a mob -- glasses, mask and helmets ONLY! (NOTE: flag shared with ONESIZEFITSALL)
#define FLEXIBLEMATERIAL 0x20 // At the moment, masks with this flag will not prevent eating even if they are covering your face.
#define SOUNDPROTECTION 0x40 // whether wearing this item will protect you from loud noises such as flashbangs | this only works for ear slots or the head slot
#define LIGHTSTEP 0x80 // When applied to footwear, this makes it so that they don't trigger things like landmines and mouse traps
// Flags for pass_flags.
#define PASSTABLE 0x1
+9
View File
@@ -49,6 +49,7 @@ var/list/obj/item/device/uplink/world_uplinks = list()
var/global/list/hair_styles_list = list() //stores /datum/sprite_accessory/hair indexed by name
var/global/list/hair_styles_male_list = list()
var/global/list/hair_styles_female_list = list()
var/global/list/hair_gradient_styles_list = list()
var/global/list/facial_hair_styles_list = list() //stores /datum/sprite_accessory/facial_hair indexed by name
var/global/list/facial_hair_styles_male_list = list()
var/global/list/facial_hair_styles_female_list = list()
@@ -105,6 +106,14 @@ var/global/list/cloaking_devices = list()
sortTim(hair_styles_male_list, /proc/cmp_text_asc)
sortTim(hair_styles_female_list, /proc/cmp_text_asc)
//Gradients - Initialise all /datum/sprite_accessory/hair_gradients into an list indexed by hairgradient-style name
paths = subtypesof(/datum/sprite_accessory/hair_gradients)
for(var/path in paths)
var/datum/sprite_accessory/hair_gradients/H = new path()
hair_gradient_styles_list[H.name] = H
sortTim(hair_gradient_styles_list, /proc/cmp_text_asc)
//Facial Hair - Initialise all /datum/sprite_accessory/facial_hair into an list indexed by facialhair-style name
paths = subtypesof(/datum/sprite_accessory/facial_hair)
for(var/path in paths)
+1
View File
@@ -78,6 +78,7 @@
#define ui_fire "EAST-1:28,NORTH-3:25"
#define ui_oxygen "EAST-1:28,NORTH-4:23"
#define ui_pressure "EAST-1:28,NORTH-5:21"
#define ui_paralysis "EAST-1:28,NORTH-10:23"
#define ui_alien_toxin "EAST-1:28,NORTH-2:25"
#define ui_alien_fire "EAST-1:28,NORTH-3:25"
+3
View File
@@ -22,6 +22,7 @@
var/obj/screen/movable/action_button/button = null
var/button_icon = 'icons/obj/action_buttons/actions.dmi'
var/button_icon_state = "default"
var/button_icon_color
var/background_icon_state = "bg_default"
var/mob/living/owner
@@ -146,6 +147,8 @@
img = image(owner.button_icon,src,owner.button_icon_state)
img.pixel_x = 0
img.pixel_y = 0
if(owner.button_icon_color)
img.color = owner.button_icon_color
add_overlay(img)
if(!owner.IsAvailable())
+15 -1
View File
@@ -270,6 +270,13 @@
mymob.fire.screen_loc = ui_fire
hud_elements |= mymob.fire
mymob.paralysis_indicator = new /obj/screen/paralysis()
mymob.paralysis_indicator.icon = 'icons/mob/status_indicators.dmi'
mymob.paralysis_indicator.icon_state = "paralysis0"
mymob.paralysis_indicator.name = "paralysis"
mymob.paralysis_indicator.screen_loc = ui_paralysis
hud_elements |= mymob.paralysis_indicator
mymob.healths = new /obj/screen()
mymob.healths.icon = ui_style
mymob.healths.icon_state = "health0"
@@ -484,4 +491,11 @@
if(icon_state == "oxy0")
to_chat(usr, SPAN_NOTICE("You are breathing easy."))
else
to_chat(usr, SPAN_DANGER("You cannot breathe!"))
to_chat(usr, SPAN_DANGER("You cannot breathe!"))
/obj/screen/paralysis/Click(var/location, var/control, var/params)
if(istype(usr) && usr.paralysis_indicator == src)
if(usr.paralysis)
to_chat(usr, SPAN_WARNING("You are completely paralyzed and cannot move!"))
else
to_chat(usr, SPAN_NOTICE("You are walking around completely fine."))
+3 -4
View File
@@ -24,9 +24,8 @@ var/datum/controller/subsystem/economy/SSeconomy
create_station_account()
for(var/department in station_departments)
create_department_account(department)
create_department_account("Vendor")
for(var/account in department_funds)
create_department_account(account)
..()
@@ -77,7 +76,7 @@ var/datum/controller/subsystem/economy/SSeconomy
department_account.account_number = next_account_number
next_account_number += rand(1,500)
department_account.remote_access_pin = rand(1111, 111111)
department_account.money = 5000
department_account.money = department_funds[department]
//create an entry in the account transaction log for when it was created
var/datum/transaction/T = new()
+1
View File
@@ -363,6 +363,7 @@ var/datum/controller/subsystem/ticker/SSticker
to_world("<B><span class='notice'>Welcome to the pre-game lobby!</span></B>")
to_world("Please, setup your character and select ready. Game will start in [pregame_timeleft] seconds.")
callHook("pregame_start")
/datum/controller/subsystem/ticker/proc/setup()
//Create and announce mode
+4 -1
View File
@@ -365,4 +365,7 @@
M.Turn(pick(-30, 30))
animate(I, alpha = 175, pixel_x = to_x, pixel_y = to_y, time = 3, transform = M, easing = CUBIC_EASING)
sleep(1)
animate(I, alpha = 0, transform = matrix(), time = 1)
animate(I, alpha = 0, transform = matrix(), time = 1)
/atom/movable/proc/get_floating_chat_x_offset()
return 0
+39 -39
View File
@@ -12,42 +12,49 @@
/obj/machinery/cablelayer/Initialize()
. = ..()
cable = new(src)
cable.amount = 100
cable.amount = max_cable
/obj/machinery/cablelayer/Move(new_turf,M_Dir)
..()
layCable(new_turf,M_Dir)
if(on)
layCable(new_turf,M_Dir)
/obj/machinery/cablelayer/attack_hand(mob/user as mob)
if(!cable&&!on)
to_chat(user, "<span class='warning'>\The [src] doesn't have any cable loaded.</span>")
/obj/machinery/cablelayer/attack_hand(mob/user)
if(!cable && !on)
to_chat(user, SPAN_WARNING("\The [src] doesn't have any cable loaded."))
return
on=!on
user.visible_message("\The [user] [!on?"dea":"a"]ctivates \the [src].", "You switch [src] [on? "on" : "off"]")
on = !on
user.visible_message("\The [user] [!on ? "de" : ""]activates \the [src].", SPAN_NOTICE("You switch \the [src] [on ? "on" : "off"]."))
return
/obj/machinery/cablelayer/attackby(var/obj/item/O as obj, var/mob/user as mob)
/obj/machinery/cablelayer/attackby(var/obj/item/O, var/mob/user)
if(O.iscoil())
var/result = load_cable(O)
if(!result)
to_chat(user, "<span class='warning'>\The [src]'s cable reel is full.</span>")
to_chat(user, SPAN_WARNING("\The [src]'s cable reel is full."))
else
to_chat(user, "You load [result] lengths of cable into [src].")
to_chat(user, SPAN_NOTICE("You load [result] lengths of cable into \the [src]."))
return
if(O.iswirecutter())
if(cable && cable.amount)
var/m = round(input(usr,"Please specify the length of cable to cut","Cut cable",min(cable.amount,30)) as num, 1)
var/m = round(input(usr,"Please specify the length of cable to cut.", "Cut Cable",min(cable.amount,30)) as num, 1)
m = min(m, cable.amount)
m = min(m, 30)
if(m)
playsound(loc, 'sound/items/wirecutter.ogg', 50, 1)
use_cable(m)
var/obj/item/stack/cable_coil/CC = new (get_turf(src))
CC.amount = m
var/cable_color = use_cable(m)
var/obj/item/stack/cable_coil/CC = new(get_turf(src), m, cable_color)
user.put_in_hands(CC)
else
to_chat(usr, "<span class='warning'>There's no more cable on the reel.</span>")
to_chat(user, SPAN_WARNING("There's no more cable on the reel."))
return
if(O.ismultitool())
if(!cable)
to_chat(user, SPAN_WARNING("\The [src] doesn't have any cable loaded!"))
return
cable.attackby(O, user)
/obj/machinery/cablelayer/examine(mob/user)
..()
@@ -60,49 +67,43 @@
if(to_load)
to_load = min(CC.amount, to_load)
if(!cable)
cable = new(src)
cable.amount = 0
cable.amount += to_load
cable = new(src, 0, CC.color)
cable.amount = to_load
CC.use(to_load)
return to_load
else
return 0
return
return FALSE
/obj/machinery/cablelayer/proc/use_cable(amount)
if(!cable || cable.amount<1)
visible_message("A red light flashes on \the [src].")
if(!cable || cable.amount < 1)
on = FALSE
reset()
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
visible_message(SPAN_WARNING("A red light flashes on \the [src]."))
return
var/cable_color = cable.color
cable.use(amount)
if(QDELETED(cable))
cable = null
return 1
return cable_color
/obj/machinery/cablelayer/proc/reset()
last_piece = null
/obj/machinery/cablelayer/proc/dismantleFloor(var/turf/new_turf)
if(istype(new_turf, /turf/simulated/floor))
var/turf/simulated/floor/T = new_turf
if(!T.is_plating())
T.make_plating(!(T.broken || T.burnt))
return new_turf.is_plating()
/obj/machinery/cablelayer/proc/layCable(var/turf/new_turf,var/M_Dir)
if(!on)
if(!istype(new_turf))
return reset()
else
dismantleFloor(new_turf)
if(!istype(new_turf) || !dismantleFloor(new_turf))
if(!new_turf.is_plating())
return reset()
var/fdirn = turn(M_Dir,180)
for(var/obj/structure/cable/LC in new_turf) // check to make sure there's not a cable there already
if(LC.d1 == fdirn || LC.d2 == fdirn)
return reset()
if(!use_cable(1))
var/cable_color = use_cable(1)
if(!cable_color)
return reset()
var/obj/structure/cable/NC = new(new_turf)
NC.cableColor("red")
NC.cableColor(cable_color)
NC.d1 = 0
NC.d2 = fdirn
NC.update_icon()
@@ -119,6 +120,5 @@
PN.add_cable(NC)
NC.mergeConnectedNetworks(NC.d2)
//NC.mergeConnectedNetworksOnTurf()
last_piece = NC
return 1
return TRUE
+2 -1
View File
@@ -306,7 +306,8 @@
for(var/obj/machinery/bodyscanner/C in orange(1,src))
connected = C
break
connected.connected = src
if(connected)
connected.connected = src
update_icon()
/obj/machinery/body_scanconsole/attack_ai(var/mob/user)
+19 -1
View File
@@ -110,4 +110,22 @@
/obj/machinery/mech_recharger/proc/stop_charging()
update_use_power(1)
charging = null
charging = null
/obj/machinery/mech_recharger/hephaestus
name = "hephaestus exosuit dock"
desc = "A massive vehicle dock elevated slightly above the ground, constructed for equally massive charging speeds."
icon_state = "supermechcharger"
idle_power_usage = 400
active_power_usage = 120 KILOWATTS
base_charge_rate = 120 KILOWATTS
repair = 1
component_types = list(
/obj/item/circuitboard/mech_recharger/hephaestus,
/obj/item/stock_parts/capacitor = 3,
/obj/item/stock_parts/scanning_module = 2,
/obj/item/stock_parts/manipulator = 3
)
@@ -83,6 +83,8 @@
if(perp.shoes && !perp.buckled)//Adding blood to shoes
var/obj/item/clothing/shoes/S = perp.shoes
if(istype(S))
if(S.item_flags & LIGHTSTEP)
return
S.blood_color = basecolor
S.track_footprint = max(amount, S.track_footprint)
if(!S.blood_overlay)
@@ -625,3 +625,78 @@ BREATH ANALYZER
++unknown
if(unknown)
to_chat(user,"<span class='warning'>Non-medical reagent[(unknown > 1)?"s":""] found in subject's respitory system.</span>")
/obj/item/device/advanced_healthanalyzer
name = "zeng-hu body analyzer"
desc = "An expensive and varied-use health analyzer that prints full-body scans after a short scanning delay."
icon_state = "zh-analyzer"
item_state = "healthanalyzer"
slot_flags = SLOT_BELT
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 3)
var/obj/machinery/body_scanconsole/internal_bodyscanner = null //this is used to print the date and to deal with extra
/obj/item/device/advanced_healthanalyzer/Initialize()
. = ..()
if(!internal_bodyscanner)
var/obj/machinery/body_scanconsole/S = new (src)
S.forceMove(src)
S.use_power = FALSE
internal_bodyscanner = S
/obj/item/device/advanced_healthanalyzer/Destroy()
if(internal_bodyscanner)
QDEL_NULL(internal_bodyscanner)
return ..()
/obj/item/device/advanced_healthanalyzer/attack(mob/living/M, mob/living/user)
if(!internal_bodyscanner)
return
if(do_after(user, 7 SECONDS, TRUE))
print_scan(M, user)
add_fingerprint(user)
/obj/item/device/advanced_healthanalyzer/proc/print_scan(var/mob/M, var/mob/living/user)
var/obj/item/paper/R = new(user.loc)
R.color = "#eeffe8"
R.set_content_unsafe("Scan ([M.name])", internal_bodyscanner.format_occupant_data(get_medical_data(M)))
if(ishuman(user) && !(user.l_hand && user.r_hand))
user.put_in_hands(R)
user.visible_message("\The [src] spits out a piece of paper.")
/obj/item/device/advanced_healthanalyzer/proc/get_medical_data(var/mob/living/carbon/human/H)
if (!ishuman(H))
return
var/list/medical_data = list(
"stationtime" = worldtime2text(),
"brain_activity" = H.get_brain_status(),
"blood_volume" = H.get_blood_volume(),
"blood_oxygenation" = H.get_blood_oxygenation(),
"blood_pressure" = H.get_blood_pressure(),
"bruteloss" = get_severity(H.getBruteLoss(), TRUE),
"fireloss" = get_severity(H.getFireLoss(), TRUE),
"oxyloss" = get_severity(H.getOxyLoss(), TRUE),
"toxloss" = get_severity(H.getToxLoss(), TRUE),
"cloneloss" = get_severity(H.getCloneLoss(), TRUE),
"rads" = H.total_radiation,
"paralysis" = H.paralysis,
"bodytemp" = H.bodytemperature,
"borer_present" = H.has_brain_worms(),
"inaprovaline_amount" = H.reagents.get_reagent_amount(/datum/reagent/inaprovaline),
"dexalin_amount" = H.reagents.get_reagent_amount(/datum/reagent/dexalin),
"stoxin_amount" = H.reagents.get_reagent_amount(/datum/reagent/soporific),
"bicaridine_amount" = H.reagents.get_reagent_amount(/datum/reagent/bicaridine),
"dermaline_amount" = H.reagents.get_reagent_amount(/datum/reagent/dermaline),
"blood_amount" = H.vessel.get_reagent_amount(/datum/reagent/blood),
"disabilities" = H.sdisabilities,
"lung_ruptured" = H.is_lung_ruptured(),
"external_organs" = H.organs.Copy(),
"internal_organs" = H.internal_organs.Copy(),
"species_organs" = H.species.has_organ
)
return medical_data
+2
View File
@@ -219,6 +219,8 @@
for(var/i = 1 to GUMBALL_MAX)
var/obj/item/clothing/mask/chewable/candy/gum/gumball/medical/G = new(src)
contained += G
return INITIALIZE_HINT_LATELOAD
#undef JAR_NOTHING
#undef JAR_MONEY
+3 -1
View File
@@ -503,7 +503,9 @@
/obj/item/toy/snappop/Crossed(H as mob|obj)
if((ishuman(H))) //i guess carp and shit shouldn't set them off
var/mob/living/carbon/M = H
var/mob/living/carbon/human/M = H
if(M.shoes?.item_flags & LIGHTSTEP)
return
if(M.m_intent == M_RUN)
to_chat(M, SPAN_WARNING("You step on the snap pop!"))
do_pop()
+1
View File
@@ -336,6 +336,7 @@ RFD Construction-Class
/obj/item/rfd/construction/mounted/can_use(var/mob/user,var/turf/T)
return (user.Adjacent(T) && !user.stat && !user.restrained())
/*
RFD Service-Class
*/
@@ -1,5 +1,5 @@
#ifndef T_BOARD
#error T_BOARD macro is not defined but we need it!
#error T_BOARD macro is not defined but we need it!
#endif
/obj/item/circuitboard/mech_recharger
@@ -10,4 +10,13 @@
req_components = list(
"/obj/item/stock_parts/capacitor" = 2,
"/obj/item/stock_parts/scanning_module" = 1,
"/obj/item/stock_parts/manipulator" = 2)
"/obj/item/stock_parts/manipulator" = 2)
/obj/item/circuitboard/mech_recharger/hephaestus
name = T_BOARD("hephaestus mech recharger")
build_path = /obj/machinery/mech_recharger/hephaestus
origin_tech = list(TECH_DATA = 2, TECH_POWER = 3, TECH_ENGINEERING = 3)
req_components = list(
"/obj/item/stock_parts/capacitor" = 3,
"/obj/item/stock_parts/scanning_module" = 2,
"/obj/item/stock_parts/manipulator" = 3)
@@ -57,6 +57,11 @@
/obj/item/landmine/Crossed(AM as mob|obj)
if(deployed)
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(H.shoes?.item_flags & LIGHTSTEP)
..()
return
if(isliving(AM))
var/mob/living/L = AM
if(L.mob_size >= 5)
@@ -22,9 +22,10 @@
var/damage_coef = 1
if(H.buckled)
return
if(H.resting)
return
if(H.shoes?.item_flags & LIGHTSTEP)
return
to_chat(H, SPAN_DANGER("You step on \the [src]!"))
playsound(get_turf(src), 'sound/effects/glass_step.ogg', 50, TRUE)
@@ -82,6 +82,7 @@
)
sharp = 1
edge = 1
force_divisor = 0.25
/obj/item/material/minihoe // -- Numbers
name = "mini hoe"
+19 -1
View File
@@ -71,8 +71,26 @@ var/list/tape_roll_applications = list()
/obj/item/tape/engineering
name = "engineering tape"
desc = "A length of engineering tape. Better not cross it."
req_one_access = list(access_engine,access_atmospherics)
desc_info = "You can use a multitool on this tape to allow emergency shield generators to deploy shields on this tile."
req_one_access = list(access_engine, access_atmospherics)
icon_base = "engineering"
var/shield_marker = FALSE
/obj/item/tape/engineering/examine(mob/user, distance)
. = ..()
if(shield_marker)
to_chat(user, SPAN_NOTICE("This strip of tape has been modified to serve as a marker for emergency shield generators to lock onto."))
/obj/item/tape/engineering/attackby(obj/item/W, mob/user)
if(W.ismultitool())
shield_marker = !shield_marker
to_chat(user, SPAN_NOTICE("You [shield_marker ? "" : "un"]designate \the [src] as a target for an emergency shield generator."))
if(shield_marker)
animate(src, 1 SECOND, color = color_rotation(-60))
else
animate(src, 1 SECOND, color = initial(color))
return
return ..()
/obj/item/taperoll/attack_self(mob/user as mob)
if(icon_state == "[icon_base]_start")
+5 -1
View File
@@ -47,7 +47,11 @@
overlays += image('icons/obj/items.dmi', icon_state = "soap_key_overlay")
/obj/item/soap/Crossed(AM as mob|obj)
if (istype(AM, /mob/living))
if(isliving(AM))
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(H.shoes?.item_flags & LIGHTSTEP)
return
var/mob/living/M = AM
M.slip("the [src.name]",3)
@@ -513,3 +513,20 @@
canremove = 0
species_restricted = list(BODYTYPE_VAURCA_BREEDER)
sprite_sheets = list(BODYTYPE_VAURCA_BREEDER = 'icons/mob/species/breeder/back.dmi')
/obj/item/storage/backpack/service
name = "idris service backpack"
desc = "The infamously Idris Service Standard refers to this monstrous, self-stabilizing back-mounted utensil and service item holder, not anything professional."
icon_state = "idris_backpack"
storage_slots = 6
max_w_class = ITEMSIZE_LARGE
can_hold = list(
/obj/item/tray,
/obj/item/material/kitchen/utensil/fork,
/obj/item/material/kitchen/utensil/knife,
/obj/item/material/kitchen/utensil/spoon,
/obj/item/material/knife,
/obj/item/material/hatchet/butch,
/obj/item/reagent_containers/food/drinks/drinkingglass,
/obj/item/storage/toolbox/lunchbox/nt
)
@@ -137,7 +137,8 @@
starts_with = list(
/obj/item/stack/medical/bruise_pack = 2,
/obj/item/stack/medical/advanced/bruise_pack = 2,
/obj/item/reagent_containers/pill/bicaridine = 2,
/obj/item/reagent_containers/pill/bicaridine = 1,
/obj/item/reagent_containers/hypospray/autoinjector/coagzolug = 1,
/obj/item/device/healthanalyzer = 1
)
@@ -84,3 +84,16 @@
/obj/item/storage/internal/Adjacent(var/atom/neighbor)
return master_item.Adjacent(neighbor)
/obj/item/storage/internal/skrell
name = "headtail storage"
icon = 'icons/obj/action_buttons/organs.dmi'
icon_state = "skrell_headpocket"
storage_slots = 1
max_storage_space = 2
max_w_class = ITEMSIZE_SMALL
use_sound = null
/obj/item/storage/internal/skrell/Initialize()
. = ..()
name = initial(name)
@@ -118,6 +118,7 @@
new /obj/item/storage/box/inhalers(src)
new /obj/item/clothing/glasses/hud/health/aviator(src)
new /obj/item/storage/box/fancy/keypouch/med(src)
new /obj/item/device/advanced_healthanalyzer(src)
/obj/structure/closet/secure_closet/CMO2
name = "chief medical officer's attire"
@@ -82,6 +82,11 @@
desc += padding_material ? " It's made of [material.use_name] and covered with [padding_material.use_name]." : " It's made of [material.use_name]."
/obj/structure/bed/forceMove(atom/dest)
. = ..()
if(buckled_mob)
buckled_mob.forceMove(dest)
/obj/structure/bed/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(istype(mover) && mover.checkpass(PASSTABLE))
return 1
+12 -2
View File
@@ -146,7 +146,17 @@ var/max_explosion_range = 14
// Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it.
var/global/obj/item/device/radio/intercom/global_announcer = new(null)
var/list/station_departments = list("Command", "Medical", "Engineering", "Science", "Security", "Cargo", "Civilian")
// the number next to it denotes how much money the department receives when its account is generated
var/list/department_funds = list(
"Command" = 10000,
"Medical" = 10000,
"Engineering" = 10000,
"Science" = 10000,
"Security" = 10000,
"Cargo" = 5000,
"Civilian" = 10000,
"Vendor" = 0
)
//List of exosuit tracking beacons, to save performance
var/global/list/exo_beacons = list()
var/global/list/exo_beacons = list()
-21
View File
@@ -1010,27 +1010,6 @@ proc/admin_notice(var/message, var/rights)
item_to_spawn.spawn_item(get_turf(usr))
/datum/admins/proc/check_custom_items()
set category = "Debug"
set desc = "Check the custom item list."
set name = "Check Custom Items"
if(!check_rights(R_SPAWN)) return
if(!custom_items)
to_chat(usr, "Custom item list is null.")
return
if(!custom_items.len)
to_chat(usr, "Custom item list not populated.")
return
for(var/assoc_key in custom_items)
to_chat(usr, "[assoc_key] has:")
var/list/current_items = custom_items[assoc_key]
for(var/datum/custom_item/item in current_items)
to_chat(usr, "- name: [item.name] icon: [item.item_icon] path: [item.item_path] desc: [item.item_desc]")
/datum/admins/proc/spawn_plant(seedtype in SSplants.seeds)
set category = "Debug"
-5
View File
@@ -72,7 +72,6 @@ var/list/admin_verbs_admin = list(
/client/proc/toggleghostwriters,
/client/proc/toggledrones,
/datum/admins/proc/show_skills,
/client/proc/check_customitem_activity,
/client/proc/man_up,
/client/proc/global_man_up,
/client/proc/response_team, // Response Teams admin verb,
@@ -145,7 +144,6 @@ var/list/admin_verbs_spawn = list(
/client/proc/game_panel,
/datum/admins/proc/spawn_fruit,
/datum/admins/proc/spawn_custom_item,
/datum/admins/proc/check_custom_items,
/datum/admins/proc/spawn_plant,
/datum/admins/proc/spawn_atom, // allows us to spawn instances,
/client/proc/respawn_character,
@@ -171,7 +169,6 @@ var/list/admin_verbs_server = list(
/datum/admins/proc/toggle_round_spookyness,
/datum/admins/proc/toggle_space_ninja,
/client/proc/toggle_random_events,
/client/proc/check_customitem_activity,
/client/proc/nanomapgen_DumpImage,
/client/proc/toggle_recursive_explosions,
/client/proc/restart_controller,
@@ -350,7 +347,6 @@ var/list/admin_verbs_hideable = list(
/datum/admins/proc/call_drop_pod,
/datum/admins/proc/spawn_fruit,
/datum/admins/proc/spawn_custom_item,
/datum/admins/proc/check_custom_items,
/datum/admins/proc/spawn_plant,
/client/proc/show_plant_genes,
/datum/admins/proc/spawn_atom,
@@ -400,7 +396,6 @@ var/list/admin_verbs_hideable = list(
/client/proc/callproc,
/client/proc/callproc_target,
/client/proc/debug_controller,
/client/proc/check_customitem_activity,
/client/proc/print_logout_report,
/client/proc/edit_admin_permissions,
/proc/possess,
-4
View File
@@ -1460,10 +1460,6 @@
src.admincaster_screen = 20
src.access_news_network()
else if(href_list["populate_inactive_customitems"])
if(check_rights(R_ADMIN|R_SERVER))
populate_inactive_customitems_list(src.owner)
else if(href_list["vsc"])
if(check_rights(R_ADMIN|R_SERVER))
if(href_list["vsc"] == "airflow")
@@ -1,85 +0,0 @@
var/checked_for_inactives = 0
var/inactive_keys = "None<br>"
/client/proc/check_customitem_activity()
set category = "Admin"
set name = "Check activity of players with custom items"
var/dat = "<b>Inactive players with custom items</b><br>"
dat += "<br>"
dat += "The list below contains players with custom items that have not logged\
in for the past two months, or have not logged in since this system was implemented.\
This system requires the feedback SQL database to be properly setup and linked.<br>"
dat += "<br>"
dat += "Populating this list is done automatically, but must be manually triggered on a per\
round basis. Populating the list may cause a lag spike, so use it sparingly.<br>"
dat += "<hr>"
if(checked_for_inactives)
dat += inactive_keys
dat += "<hr>"
dat += "This system was implemented on March 1 2013, and the database a few days before that. Root server access is required to add or disable access to specific custom items.<br>"
else
dat += "<a href='?src=\ref[src];_src_=holder;populate_inactive_customitems=1'>Populate list (requires an active database connection)</a><br>"
usr << browse(dat, "window=inactive_customitems;size=600x480")
/proc/populate_inactive_customitems_list(var/client/C)
set background = 1
if(checked_for_inactives)
return
establish_db_connection(dbcon)
if(!dbcon.IsConnected())
return
//grab all ckeys associated with custom items
var/list/ckeys_with_customitems = list()
var/file = file2text("config/custom_items.txt")
var/lines = text2list(file, "\n")
for(var/line in lines)
// split & clean up
var/list/Entry = text2list(line, ":")
for(var/i = 1 to Entry.len)
Entry[i] = trim(Entry[i])
if(Entry.len < 1)
continue
var/cur_key = Entry[1]
if(!ckeys_with_customitems.Find(cur_key))
ckeys_with_customitems.Add(cur_key)
//run a query to get all ckeys inactive for over 2 months
var/list/inactive_ckeys = list()
if(ckeys_with_customitems.len)
var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey, lastseen FROM ss13_player WHERE datediff(Now(), lastseen) > 60")
query_inactive.Execute()
while(query_inactive.NextRow())
var/cur_ckey = query_inactive.item[1]
//if the ckey has a custom item attached, output it
if(ckeys_with_customitems.Find(cur_ckey))
ckeys_with_customitems.Remove(cur_ckey)
inactive_ckeys[cur_ckey] = "last seen on [query_inactive.item[2]]"
//if there are ckeys left over, check whether they have a database entry at all
if(ckeys_with_customitems.len)
for(var/cur_ckey in ckeys_with_customitems)
var/DBQuery/query_inactive = dbcon.NewQuery("SELECT ckey FROM ss13_player WHERE ckey = '[cur_ckey]'")
query_inactive.Execute()
if(!query_inactive.RowCount())
inactive_ckeys += cur_ckey
if(inactive_ckeys.len)
inactive_keys = ""
for(var/cur_key in inactive_ckeys)
if(inactive_ckeys[cur_key])
inactive_keys += "<b>[cur_key]</b> - [inactive_ckeys[cur_key]]<br>"
else
inactive_keys += "[cur_key] - no database entry<br>"
checked_for_inactives = 1
if(C)
C.check_customitem_activity()
+2
View File
@@ -281,6 +281,8 @@
*/
/client/proc/fetch_unacked_warning_count()
establish_db_connection(dbcon)
if (!dbcon)
return
if (!dbcon.IsConnected())
return
var/DBQuery/warning_count_query = dbcon.NewQuery("SELECT COUNT(*) FROM ss13_warnings WHERE (visible = 1 AND acknowledged = 0 AND expired = 0) AND (ckey = :ckey: OR computerid = :computer_id: OR ip = :address:)")
+6 -1
View File
@@ -85,7 +85,12 @@
if(armed)
if(israt(AM))
triggered(AM)
else if(istype(AM, /mob/living))
else if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(!(H.shoes?.item_flags & LIGHTSTEP))
triggered(H)
H.visible_message(SPAN_WARNING("\The [H] accidentally steps on \the [src]."), SPAN_WARNING("You accidentally step on \the [src]."))
else if(isliving(AM))
var/mob/living/L = AM
triggered(L)
L.visible_message(SPAN_WARNING("\The [L] accidentally steps on \the [src]."), SPAN_WARNING("You accidentally step on \the [src]."))
+14 -20
View File
@@ -61,7 +61,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(t >= timeout_time)
log_admin(SPAN_DANGER("Timeout time [timeout_time] exceeded for asset: [asset_name] for client [client]. Please notify a developer."))
@@ -175,25 +175,6 @@ var/list/asset_datums = list()
/datum/asset/simple/send(client)
send_asset_list(client,assets,verify)
/datum/asset/chem_master
var/list/bottle_sprites = list("bottle-1", "bottle-2", "bottle-3", "bottle-4")
var/max_pill_sprite = 20
var/list/assets = list()
/datum/asset/chem_master/register()
for (var/i = 1 to max_pill_sprite)
var/name = "pill[i].png"
register_asset(name, icon('icons/obj/chemical.dmi', "pill[i]"))
assets += name
for (var/sprite in bottle_sprites)
var/name = "[sprite].png"
register_asset(name, icon('icons/obj/chemical.dmi', sprite))
assets += name
/datum/asset/chem_master/send(client)
send_asset_list(client, assets)
/datum/asset/group
_abstract = /datum/asset/group
var/list/children
@@ -528,3 +509,16 @@ var/list/asset_datums = list()
else
Insert(imgid, I)
return ..()
/datum/asset/spritesheet/chem_master
name = "chemmaster"
var/list/bottle_sprites = list("bottle-1", "bottle-2", "bottle-3", "bottle-4")
var/max_pill_sprite = 20
/datum/asset/spritesheet/chem_master/register()
for (var/i = 1 to max_pill_sprite)
Insert("pill[i]", 'icons/obj/chemical.dmi', "pill[i]")
for (var/sprite in bottle_sprites)
Insert(sprite, icon('icons/obj/chemical.dmi', sprite))
return ..()
@@ -181,10 +181,22 @@
if (!isnull(raw_name) && CanUseTopic(user))
var/new_name = sanitize_name(raw_name, pref.species)
if(new_name)
if(new_name == pref.real_name)
return TOPIC_NOACTION //If the name is the same do nothing
if(config.sql_saves)
//Check if the player already has a character with the same name. (We dont have to account for the current char in that query, as that is already handled by the condition above)
var/DBQuery/query = dbcon.NewQuery("SELECT COUNT(*) FROM ss13_characters WHERE ckey = :ckey: and name = :char_name:")
query.Execute(list("ckey" = user.client.ckey, "char_name" = new_name))
query.NextRow()
var/count = text2num(query.item[1])
if(count > 0)
to_chat(user, SPAN_WARNING("Invalid name. You have already used this name for another character. If you have deleted the character contact an admin to restore it."))
return TOPIC_NOACTION
pref.real_name = new_name
return TOPIC_REFRESH
else
to_chat(user, "<span class='warning'>Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .</span>")
to_chat(user, SPAN_WARNING("Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and ."))
return TOPIC_NOACTION
else if(href_list["namehelp"])
@@ -14,12 +14,16 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
S["facial_red"] >> pref.r_facial
S["facial_green"] >> pref.g_facial
S["facial_blue"] >> pref.b_facial
S["grad_red"] >> pref.r_grad
S["grad_green"] >> pref.g_grad
S["grad_blue"] >> pref.b_grad
S["skin_tone"] >> pref.s_tone
S["skin_red"] >> pref.r_skin
S["skin_green"] >> pref.g_skin
S["skin_blue"] >> pref.b_skin
S["hair_style_name"] >> pref.h_style
S["facial_style_name"] >> pref.f_style
S["grad_style_name"] >> pref.g_style
S["eyes_red"] >> pref.r_eyes
S["eyes_green"] >> pref.g_eyes
S["eyes_blue"] >> pref.b_eyes
@@ -36,12 +40,16 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
S["facial_red"] << pref.r_facial
S["facial_green"] << pref.g_facial
S["facial_blue"] << pref.b_facial
S["grad_red"] << pref.r_grad
S["grad_green"] << pref.g_grad
S["grad_blue"] << pref.b_grad
S["skin_tone"] << pref.s_tone
S["skin_red"] << pref.r_skin
S["skin_green"] << pref.g_skin
S["skin_blue"] << pref.b_skin
S["hair_style_name"] << pref.h_style
S["facial_style_name"] << pref.f_style
S["grad_style_name"] << pref.g_style
S["eyes_red"] << pref.r_eyes
S["eyes_green"] << pref.g_eyes
S["eyes_blue"] << pref.b_eyes
@@ -50,7 +58,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
S["organ_data"] << pref.organ_data
S["rlimb_data"] << pref.rlimb_data
S["body_markings"] << pref.body_markings
S["bgstate"] << pref.bgstate
S["bgstate"] << pref.bgstate
/datum/category_item/player_setup_item/general/body/gather_load_query()
return list(
@@ -58,10 +66,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
"vars" = list(
"hair_colour",
"facial_colour",
"grad_colour",
"skin_tone" = "s_tone",
"skin_colour",
"hair_style" = "h_style",
"facial_style" = "f_style",
"gradient_style" = "g_style",
"eyes_colour",
"b_type",
"disabilities",
@@ -82,10 +92,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
"ss13_characters" = list(
"hair_colour",
"facial_colour",
"grad_colour",
"skin_tone",
"skin_colour",
"hair_style",
"facial_style",
"gradient_style",
"eyes_colour",
"b_type",
"disabilities",
@@ -102,10 +114,12 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
return list(
"hair_colour" = rgb(pref.r_hair, pref.g_hair, pref.b_hair),
"facial_colour" = rgb(pref.r_facial, pref.g_facial, pref.b_facial),
"grad_colour" = rgb(pref.r_grad, pref.g_grad, pref.b_grad),
"skin_tone" = pref.s_tone,
"skin_colour" = rgb(pref.r_skin, pref.g_skin, pref.b_skin) ,
"hair_style" = pref.h_style,
"facial_style" = pref.f_style,
"gradient_style"= pref.g_style,
"eyes_colour" = rgb(pref.r_eyes, pref.g_eyes, pref.b_eyes),
"b_type" = pref.b_type,
"disabilities" = json_encode(pref.disabilities),
@@ -129,6 +143,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.g_facial = GetGreenPart(pref.facial_colour)
pref.b_facial = GetBluePart(pref.facial_colour)
pref.grad_colour = sanitize_hexcolor(pref.grad_colour)
pref.r_grad = GetRedPart(pref.grad_colour)
pref.g_grad = GetGreenPart(pref.grad_colour)
pref.b_grad = GetBluePart(pref.grad_colour)
pref.s_tone = text2num(pref.s_tone)
pref.skin_colour = sanitize_hexcolor(pref.skin_colour)
@@ -172,6 +191,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.b_skin = sanitize_integer(pref.b_skin, 0, 255, initial(pref.b_skin))
pref.h_style = sanitize_inlist(pref.h_style, hair_styles_list, initial(pref.h_style))
pref.f_style = sanitize_inlist(pref.f_style, facial_hair_styles_list, initial(pref.f_style))
pref.g_style = sanitize_inlist(pref.g_style, hair_gradient_styles_list, initial(pref.g_style))
pref.r_eyes = sanitize_integer(pref.r_eyes, 0, 255, initial(pref.r_eyes))
pref.g_eyes = sanitize_integer(pref.g_eyes, 0, 255, initial(pref.g_eyes))
pref.b_eyes = sanitize_integer(pref.b_eyes, 0, 255, initial(pref.b_eyes))
@@ -273,6 +293,11 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
out += "<a href='?src=\ref[src];facial_color=1'>Change Color</a> [HTML_RECT(rgb(pref.r_facial, pref.g_facial, pref.b_facial))] "
out += " Style: <a href='?src=\ref[src];facial_style=1'>[pref.f_style]</a><br>"
out += "<b>Gradient</b><br>"
if(has_flag(mob_species, HAS_HAIR_COLOR))
out += "<a href='?src=\ref[src];gradient_color=1'>Change Color</a> [HTML_RECT(rgb(pref.r_grad, pref.g_grad, pref.b_grad))] "
out += " Style: <a href='?src=\ref[src];gradient_style=1'>[pref.g_style]</a><br>"
if(has_flag(mob_species, HAS_EYE_COLOR))
out += "<br><b>Eyes</b><br>"
out += "<a href='?src=\ref[src];eye_color=1'>Change Color</a> [HTML_RECT(rgb(pref.r_eyes, pref.g_eyes, pref.b_eyes))] <br>"
@@ -402,6 +427,16 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.b_hair = GetBluePart(new_hair)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["gradient_color"])
if(!has_flag(mob_species, HAS_HAIR_COLOR))
return TOPIC_NOACTION
var/new_grad = input(user, "Choose your character's secondary hair color:", "Character Preference", rgb(pref.r_grad, pref.g_grad, pref.b_grad)) as color|null
if(new_grad && has_flag(mob_species, HAS_HAIR_COLOR) && CanUseTopic(user))
pref.r_grad = GetRedPart(new_grad)
pref.g_grad = GetGreenPart(new_grad)
pref.b_grad = GetBluePart(new_grad)
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["hair_style"])
if(mob_species.bald)
return
@@ -419,6 +454,20 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.h_style = new_h_style
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["gradient_style"])
var/list/valid_gradients = list()
for(var/gradstyle in hair_gradient_styles_list)
var/datum/sprite_accessory/S = hair_gradient_styles_list[gradstyle]
if(!(mob_species.type in S.species_allowed))
continue
valid_gradients[gradstyle] = hair_gradient_styles_list[gradstyle]
var/new_g_style = input(user, "Choose a color pattern for your hair:", "Character Preference", pref.g_style) as null|anything in valid_gradients
if(new_g_style && CanUseTopic(user))
pref.g_style = new_g_style
return TOPIC_REFRESH_UPDATE_PREVIEW
else if(href_list["facial_color"])
if(!has_flag(mob_species, HAS_HAIR_COLOR))
return TOPIC_NOACTION
@@ -23,6 +23,12 @@
path = /obj/item/clothing/accessory/armband/idris
faction = "Idris Incorporated"
/datum/gear/faction/idris_windbreaker
display_name = "idris jacket"
path = /obj/item/clothing/suit/storage/toggle/idris
slot = slot_wear_suit
faction = "Idris Incorporated"
/datum/gear/faction/zavodskoi_beret
display_name = "black zavodskoi beret"
path = /obj/item/clothing/head/beret/security/zavodskoi
+10 -3
View File
@@ -49,6 +49,11 @@ datum/preferences
var/r_hair = 0 //Hair color
var/g_hair = 0 //Hair color
var/b_hair = 0 //Hair color
var/g_style = "None" //Gradient style
var/grad_colour = "#000000" //Gradient colour hex value, for SQL loading
var/r_grad = 0 //Gradient color
var/g_grad = 0 //Gradient color
var/b_grad = 0 //Gradient color
var/f_style = "Shaved" //Face hair type
var/facial_colour = "#000000" //Facial colour hex value, for SQL loading
var/r_facial = 0 //Face hair color
@@ -436,15 +441,17 @@ datum/preferences
character.g_facial = g_facial
character.b_facial = b_facial
character.g_style = g_style
character.r_grad = r_grad
character.g_grad = g_grad
character.b_grad = b_grad
character.r_skin = r_skin
character.g_skin = g_skin
character.b_skin = b_skin
character.s_tone = s_tone
character.h_style = h_style
character.f_style = f_style
character.citizenship = citizenship
character.employer_faction = faction
character.religion = religion
+53
View File
@@ -0,0 +1,53 @@
//iru coats
/obj/item/clothing/suit/armor/vest/idris
name = "black Idris Unit coat"
desc = "A coat worn by the Idris units, notorious across space."
icon = 'icons/clothing/suits/coats/idris_iru_coats.dmi'
icon_state = "iru_coat"
item_state = "iru_coat"
cold_protection = 0
min_cold_protection_temperature = 0
heat_protection = 0
max_heat_protection_temperature = 0
contained_sprite = TRUE
/obj/item/clothing/suit/armor/vest/idris/brown
name = "brown Idris Unit coat"
desc = "A coat worn by the Idris units, notorious across space. This one is brown."
icon_state = "iru_coat_brown"
item_state = "iru_coat_brown"
/obj/item/clothing/suit/armor/vest/idris/trenchcoat/black
name = "black Idris Unit trench coat"
desc = "A trench coat worn by the Idris units, notorious across space. This one is black."
icon_state = "iru_trench_black"
item_state = "iru_trench_black"
/obj/item/clothing/suit/armor/vest/idris/trenchcoat/brown
name = "brown Idris Unit trench coat"
desc = "A trench coat worn by the Idris units, notorious across space. This one is brown."
icon_state = "iru_trench_brown"
item_state = "iru_trench_brown"
/obj/item/clothing/suit/armor/vest/idris/duster/black
name = "black Idris Unit duster coat"
desc = "A duster coat worn by the Idris units, notorious across space. This one is black."
icon_state = "iru_duster_black"
item_state = "iru_duster_black"
/obj/item/clothing/suit/armor/vest/idris/duster/brown
name = "brown Idris Unit duster coat"
desc = "A duster coat worn by the Idris units, notorious across space. This one is brown."
icon_state = "iru_duster_brown"
item_state = "iru_duster_brown"
//windbreaker
/obj/item/clothing/suit/storage/toggle/idris
name = "\improper Idris Incorporated jacket"
desc = "A comfortable windbreaker for Idris Incorporated investigations staff styled after the coats of Idris reclamation units. Many of the Idris patches and badges on the coat are holographic."
icon = 'icons/clothing/suits/coats/idris_windbreaker.dmi'
icon_state = "idris_windbreaker"
item_state = "idris_windbreaker"
contained_sprite = TRUE
+1 -1
View File
@@ -4,7 +4,7 @@
icon_state = "brown"
item_state = "brown"
permeability_coefficient = 0.05
item_flags = NOSLIP
item_flags = NOSLIP|LIGHTSTEP
origin_tech = list(TECH_ILLEGAL = 3)
var/list/clothing_choices = list()
siemens_coefficient = 0.75
-40
View File
@@ -576,46 +576,6 @@
pockets.max_w_class = ITEMSIZE_SMALL
pockets.max_storage_space = 8
/obj/item/clothing/suit/armor/vest/idris
name = "black Idris Unit coat"
desc = "A coat worn by the Idris units, notorious across space."
icon_state = "iru_coat"
item_state = "iru_coat"
cold_protection = 0
min_cold_protection_temperature = 0
heat_protection = 0
max_heat_protection_temperature = 0
/obj/item/clothing/suit/armor/vest/idris/brown
name = "brown Idris Unit coat"
desc = "A coat worn by the Idris units, notorious across space. This one is brown."
icon_state = "iru_coat_brown"
item_state = "iru_coat_brown"
/obj/item/clothing/suit/armor/vest/idris/trenchcoat/black
name = "black Idris Unit trench coat"
desc = "A trench coat worn by the Idris units, notorious across space. This one is black."
icon_state = "iru_trench_black"
item_state = "iru_trench_black"
/obj/item/clothing/suit/armor/vest/idris/trenchcoat/brown
name = "brown Idris Unit trench coat"
desc = "A trench coat worn by the Idris units, notorious across space. This one is brown."
icon_state = "iru_trench_brown"
item_state = "iru_trench_brown"
/obj/item/clothing/suit/armor/vest/idris/duster/black
name = "black Idris Unit duster coat"
desc = "A duster coat worn by the Idris units, notorious across space. This one is black."
icon_state = "iru_duster_black"
item_state = "iru_duster_black"
/obj/item/clothing/suit/armor/vest/idris/duster/brown
name = "brown Idris Unit duster coat"
desc = "A duster coat worn by the Idris units, notorious across space. This one is brown."
icon_state = "iru_duster_brown"
item_state = "iru_duster_brown"
/obj/item/clothing/suit/storage/vest/sol
name = "sol heavy armor vest"
desc = "A high-quality armor vest in a deep green. It is surprisingly flexible and light, even with the added webbing and armor plating."
+250 -213
View File
@@ -1,40 +1,194 @@
// Switch this out to use a database at some point. Each ckey is
// associated with a list of custom item datums. When the character
// spawns, the list is checked and all appropriate datums are spawned.
// See config/example/custom_items.txt for a more detailed overview
// of how the config system works.
//This is the custom items system.
//There are two main modes of operation: database-based and file-based
//The operating mode is decided by the config.sql_enabled parameter
//
/// File
// In File mode the system loads all the custom items from the custom_items.json into the custom_items list at roundstart
// There is also a fallback mode for the DEPRECATED custom_items.txt. This fallback mode will be removed at some point.
// You SHOULD migrate to json file (manually) or the db using the automatic migration feature described in the db section
// When the equip_custom_items() proc is called for a specified mob, the custom_items list is iteraed over to determine which
// custom items belong to that mob of the player. Afterwards the items are spawned and applied to the mob (if the role matches)
//
/// Database
// In the database mode the custom items are NOT preloaded but fetched on demand based on the character id.
// If the database is empty and one of the configuration files exists the configuration file is loaded into the custom_items list.
// Afterwards a attempt is made to migrate the custom items into the database.
// Once there are entries in the ss13_characters_custom_items table no more attempts to migrate the data are made.
// To make it easier to find the round when that migration occured, the feedback variables
// custom_item_migration_success and custom_item_migration_error are set.
//
/// Removed Features
// The kits have been removed without replacement
// The icon manipulation features have been removed without replacement
// The required access has been removed without replacement
// The name/desc field have been removed and replaced with the item_data system
// This allows to modify any (string/int) variable of a existing item via the custom_item system.
// The key in the item_data list is the name of the variable, and the value is the value of the variable.
// i.e. `item_data = list("name"="asdf")` would set the name of the item to asdf when its spawned in
// CUSTOM ITEM ICONS:
// Inventory icons must be in CUSTOM_ITEM_OBJ with state name [item_icon].
// On-mob icons must be in CUSTOM_ITEM_MOB with state name [item_icon].
// Inhands must be in CUSTOM_ITEM_MOB as [icon_state]_l and [icon_state]_r.
// Kits must have mech icons in CUSTOM_ITEM_OBJ under [kit_icon].
// Broken must be [kit_icon]-broken and open must be [kit_icon]-open.
// Kits must also have hardsuit icons in CUSTOM_ITEM_MOB as [kit_icon]_suit
// and [kit_icon]_helmet, and in CUSTOM_ITEM_OBJ as [kit_icon].
//ITEM_ICONS ARE DEPRECATED. USE CONTAINED SPRITES IN FUTURE
/var/list/custom_items = list()
//Loads the custom items from the json file if the db backend is disabled
/hook/pregame_start/proc/load_custom_items()
var/load_from_file = 0
if (config.sql_enabled)
log_debug("Custom Items: Loading from SQL")
//If we have sql enabled we check if the db is empty. If so we migrate the json file to the db
//If the db is not empty we dont load the json file
if(!establish_db_connection(dbcon))
log_debug("Custom Items: Unable to establish database connection. - Aborting")
return 1
var/DBQuery/query = dbcon.NewQuery("SELECT COUNT(*) FROM ss13_characters_custom_items")
query.Execute()
if (!query.NextRow())
log_debug("Custom Items: Unable to fetch custom item count from database. - Aborting")
return 1
var/item_count = text2num(query.item[1])
if(item_count > 0)
return 1
//If there are no items in the db, migrate them
load_from_file = 2
log_debug("Custom Items: No items found in the database - attempting migration")
else
//If we dont have a db, we need to load the json file
load_from_file = 1
if(load_from_file)
log_debug("Custom Items: Loading from File")
//Check if the json file exists
if(fexists("config/custom_items.json"))
log_debug("Custom Items: Loading from json")
var/list/loaded_items = list()
var/item_id = 0
try
loaded_items = json_decode(return_file_text("config/custom_items.json"))
catch(var/exception/e)
log_debug("Custom Items: Failed to load custom_items.json: [e]")
for(var/item in loaded_items)
//TODO: Check for existance of the vars first
item_id += 1
var/datum/custom_item/ci = new()
ci.id = item_id
ci.usr_ckey = item["ckey"]
ci.usr_charname = item["character_name"]
ci.item_path = text2path(item["item_path"])
if(item["item_data"])
ci.item_data = item["item_data"]
if(item["item_name"])
ci.item_data["name"] = item["item_name"]
if(item["item_desc"])
ci.item_data["desc"] = item["item_desc"]
ci.additional_data = item["additional_data"]
ci.req_titles = item["req_titles"]
custom_items.Add(ci)
log_debug("Custom Items: Loaded [length(custom_items)] custom items")
else if(fexists("config/custom_items.txt")) //TODO: Retire that at some point down the line
log_debug("Custom Items: Loading from txt")
log_and_message_admins("The deprecated custom_items.txt file is used. Migrate to SQL or JSON.")
//If we dont have the json file, we might have the old file so lets try that
var/datum/custom_item/current_data
for(var/line in text2list(file2text("config/custom_items.txt"), "\n"))
line = trim(line)
if(line == "" || !line || findtext(line, "#", 1, 2))
continue
if(findtext(line, "{", 1, 2) || findtext(line, "}", 1, 2)) // New block!
if(current_data && current_data.usr_ckey && current_data.usr_charname)
custom_items.Add(current_data)
current_data = null
var/split = findtext(line,":")
if(!split)
continue
var/field = trim(copytext(line,1,split))
var/field_data = trim(copytext(line,(split+1)))
if(!field || !field_data)
continue
if(!current_data)
current_data = new()
switch(field)
if("ckey")
current_data.usr_ckey = ckey(field_data)
if("character_name")
current_data.usr_charname = lowertext(field_data)
if("item_path")
current_data.item_path = text2path(field_data)
if("item_name")
current_data.item_data["name"] = field_data
if("item_icon")
continue
if("inherit_inhands")
continue
if("item_desc")
current_data.item_data["desc"] = field_data
if("req_access")
continue
if("req_titles")
current_data.req_titles = text2list(field_data,", ")
if("kit_name")
continue
if("kit_desc")
continue
if("kit_icon")
continue
if("additional_data")
current_data.additional_data = field_data
if(load_from_file == 2 && length(custom_items)) //insert the item into the db
log_debug("Custom Items: Migrating custom_items to database")
var/success_count = 0
var/error_count = 0
for(var/item in custom_items)
var/datum/custom_item/ci = item
log_debug("Custom Items: Migrating Item for: [ci.usr_ckey] - [ci.usr_charname]")
if(!ci.item_path || ci.item_path == "")
log_debug("Custom Items: Invalid Item path")
error_count += 1
continue
//Fetch the character id of the character
var/DBQuery/char_query = dbcon.NewQuery("SELECT id FROM ss13_characters WHERE ckey = :ckey: AND name = :name: AND deleted_at IS NULL ORDER BY id DESC")
char_query.Execute(list("ckey"=ckey(ci.usr_ckey),"name"=ci.usr_charname))
if (!char_query.NextRow())
log_debug("Custom Items: Unable to find matching character for: ckey: [ci.usr_ckey] name: [ci.usr_charname]")
error_count += 1
continue
var/char_id = text2num(char_query.item[1])
try
var/DBQuery/item_insert_query = dbcon.NewQuery("INSERT INTO ss13_characters_custom_items (`char_id`, `item_path`, `item_data`, `req_titles`, `additional_data`) VALUES (:char_id:, :item_path:, :item_data:, :req_titles:, :additional_data:)")
item_insert_query.Execute(list("char_id"=char_id,"item_path"="[ci.item_path]","item_data"=json_encode(ci.item_data),"req_titles"=json_encode(ci.req_titles),"additional_data"=ci.additional_data))
catch(var/exception/e)
log_debug("Custom Items: Failed to save item to db: [e]")
error_count += 1
success_count += 1
feedback_set("custom_item_migration_success",success_count)
feedback_set("custom_item_migration_error",error_count)
return 1
/datum/custom_item
var/assoc_key
var/character_name
var/inherit_inhands = 1 //if unset, and inhands are not provided, then the inhand overlays will be invisible.
var/item_icon
var/item_desc
var/name
var/item_path = /obj/item
var/req_access = 0
var/id
//the character_id is used with the db setup
var/character_id
//the char_name/ckey is used with the disk based setup (and auto-generated from the char id for the db based setup)
var/usr_ckey
var/usr_charname
var/item_path
var/list/item_data = list()
var/list/req_titles = list()
var/kit_name
var/kit_desc
var/kit_icon
var/additional_data
/datum/custom_item/proc/spawn_item(var/newloc)
/datum/custom_item/proc/spawn_item(var/newloc) //TODO: pass mob its spawned for as parameter
var/obj/item/citem = new item_path(newloc)
apply_to_item(citem)
return citem
@@ -42,207 +196,90 @@
/datum/custom_item/proc/apply_to_item(var/obj/item/item)
if(!item)
return
if(name)
item.name = name
if(item_desc)
item.desc = item_desc
if(item_icon)
if(!istype(item))
item.icon = CUSTOM_ITEM_OBJ
item.icon_state = item_icon
return
else
if(inherit_inhands)
apply_inherit_inhands(item)
else
item.item_state_slots = null
item.item_icons = null
item.icon = CUSTOM_ITEM_OBJ
item.icon_state = item_icon
item.item_state = null
item.icon_override = CUSTOM_ITEM_MOB
var/obj/item/clothing/under/U = item
if(istype(U))
U.worn_state = U.icon_state
U.update_rolldown_status()
// Kits are dumb so this is going to have to be hardcoded/snowflake.
if(istype(item, /obj/item/device/kit))
var/obj/item/device/kit/K = item
K.new_name = kit_name
K.new_desc = kit_desc
K.new_icon = kit_icon
K.new_icon_file = CUSTOM_ITEM_OBJ
if(istype(item, /obj/item/device/kit/suit))
var/obj/item/device/kit/suit/kit = item
kit.new_light_overlay = additional_data
kit.new_mob_icon_file = CUSTOM_ITEM_MOB
//Customize the item with the item_data
for(var/var_name in item_data)
try
item.vars[var_name] = item_data[var_name]
catch(var/exception/e)
log_debug("Custom Item: Bad variable name [var_name] in custom item with id [id]: [e]")
// for snowflake implants
else if(istype(item, /obj/item/implanter/fluff))
if(istype(item, /obj/item/implanter/fluff))
var/obj/item/implanter/fluff/L = item
L.allowed_ckey = assoc_key
L.allowed_ckey = usr_ckey
L.implant_type = text2path(additional_data)
L.create_implant()
return item
/datum/custom_item/proc/apply_inherit_inhands(var/obj/item/item)
var/list/new_item_icons = list()
var/list/new_item_state_slots = list()
var/list/available_states = icon_states(CUSTOM_ITEM_MOB)
//If l_hand or r_hand are not present, preserve them using item_icons/item_state_slots
//Then use icon_override to make every other slot use the custom sprites by default.
//This has to be done before we touch any of item's vars
if(!("[item_icon]_l" in available_states))
new_item_state_slots[slot_l_hand_str] = get_state(item, slot_l_hand_str, "_l")
new_item_icons[slot_l_hand_str] = get_icon(item, slot_l_hand_str, 'icons/mob/items/lefthand.dmi')
if(!("[item_icon]_r" in available_states))
new_item_state_slots[slot_r_hand_str] = get_state(item, slot_r_hand_str, "_r")
new_item_icons[slot_r_hand_str] = get_icon(item, slot_r_hand_str, 'icons/mob/items/righthand.dmi')
item.item_state_slots = new_item_state_slots
item.item_icons = new_item_icons
//this has to mirror the way update_inv_*_hand() selects the state
/datum/custom_item/proc/get_state(var/obj/item/item, var/slot_str, var/hand_str)
var/t_state
if(item.item_state_slots && item.item_state_slots[slot_str])
t_state = item.item_state_slots[slot_str]
else if(item.item_state)
t_state = item.item_state
else
t_state = item.icon_state
if(item.icon_override)
t_state += hand_str
return t_state
//this has to mirror the way update_inv_*_hand() selects the icon
/datum/custom_item/proc/get_icon(var/obj/item/item, var/slot_str, var/icon/hand_icon)
var/icon/t_icon
if(item.icon_override)
t_icon = item.icon_override
else if(item.item_icons && (slot_str in item.item_icons))
t_icon = item.item_icons[slot_str]
else
t_icon = hand_icon
return t_icon
// Parses the config file into the custom_items list.
/hook/startup/proc/load_custom_items()
var/datum/custom_item/current_data
for(var/line in text2list(file2text("config/custom_items.txt"), "\n"))
line = trim(line)
if(line == "" || !line || findtext(line, "#", 1, 2))
continue
if(findtext(line, "{", 1, 2) || findtext(line, "}", 1, 2)) // New block!
if(current_data && current_data.assoc_key)
if(!custom_items[current_data.assoc_key])
custom_items[current_data.assoc_key] = list()
var/list/L = custom_items[current_data.assoc_key]
L |= current_data
current_data = null
var/split = findtext(line,":")
if(!split)
continue
var/field = trim(copytext(line,1,split))
var/field_data = trim(copytext(line,(split+1)))
if(!field || !field_data)
continue
if(!current_data)
current_data = new()
switch(field)
if("ckey")
current_data.assoc_key = lowertext(field_data)
if("character_name")
current_data.character_name = lowertext(field_data)
if("item_path")
current_data.item_path = text2path(field_data)
if("item_name")
current_data.name = field_data
if("item_icon")
current_data.item_icon = field_data
if("inherit_inhands")
current_data.inherit_inhands = text2num(field_data)
if("item_desc")
current_data.item_desc = field_data
if("req_access")
current_data.req_access = text2num(field_data)
if("req_titles")
current_data.req_titles = text2list(field_data,", ")
if("kit_name")
current_data.kit_name = field_data
if("kit_desc")
current_data.kit_desc = field_data
if("kit_icon")
current_data.kit_icon = field_data
if("additional_data")
current_data.additional_data = field_data
return 1
//gets the relevant list for the key from the listlist if it exists, check to make sure they are meant to have it and then calls the giving function
/proc/equip_custom_items(mob/living/carbon/human/M)
var/list/key_list = custom_items[M.ckey]
if(!key_list || key_list.len < 1)
return
/proc/equip_custom_items(var/mob/living/carbon/human/M)
//Fetch the custom items for the mob
if(config.sql_enabled)
if(!establish_db_connection(dbcon))
log_debug("Custom Items: Unable to establish database connection while loading item. - Aborting")
return
for(var/datum/custom_item/citem in key_list)
var/DBQuery/char_item_query = dbcon.NewQuery("SELECT ss13_characters_custom_items.id, ss13_characters_custom_items.char_id, ss13_characters.ckey as usr_ckey, ss13_characters.name as usr_charname, item_path, item_data, req_titles, additional_data FROM ss13_characters_custom_items LEFT JOIN ss13_characters ON ss13_characters.id = ss13_characters_custom_items.char_id WHERE char_id = :char_id:")
char_item_query.Execute(list("char_id"=M.character_id))
while(char_item_query.NextRow())
CHECK_TICK
var/datum/custom_item/ci = new()
ci.id = text2num(char_item_query.item[1])
ci.character_id = text2num(char_item_query.item[2])
ci.usr_ckey = char_item_query.item[3]
ci.usr_charname = char_item_query.item[4]
ci.item_path = text2path(char_item_query.item[5])
ci.item_data = json_decode(char_item_query.item[6]) //TODO: try/catch
ci.req_titles = json_decode(char_item_query.item[7]) //TODO: try/catch
ci.additional_data = char_item_query.item[8]
// Check for requisite ckey and character name.
if((lowertext(citem.assoc_key) != lowertext(M.ckey)) || (lowertext(citem.character_name) != lowertext(M.real_name)))
continue
// Check for required access.
var/obj/item/I = M.wear_id
if(citem.req_access && citem.req_access > 0)
if(!(istype(I) && (citem.req_access in I.GetAccess())))
equip_custom_item_to_mob(ci,M)
else
for(var/item in custom_items)
CHECK_TICK
var/datum/custom_item/ci = item
if(lowertext(ci.usr_ckey) != lowertext(M.ckey))
continue
// Check for required job title.
if(citem.req_titles && citem.req_titles.len > 0)
var/has_title
var/current_title = M.mind.role_alt_title ? M.mind.role_alt_title : M.mind.assigned_role
for(var/title in citem.req_titles)
if(title == current_title)
has_title = 1
break
if(!has_title)
if(lowertext(ci.usr_charname) != lowertext(M.real_name))
continue
equip_custom_item_to_mob(ci,M)
// ID cards and MCs are applied directly to the existing object rather than spawned fresh.
var/obj/item/existing_item
if(citem.item_path == /obj/item/card/id)
existing_item = locate(/obj/item/card/id) in M.get_contents() //TODO: Improve this ?
else if(citem.item_path == /obj/item/modular_computer)
existing_item = locate(/obj/item/modular_computer) in M.contents
// Spawn and equip the item.
if(existing_item)
citem.apply_to_item(existing_item)
else
place_custom_item(M,citem)
/proc/equip_custom_item_to_mob(var/datum/custom_item/citem, var/mob/living/carbon/human/M)
// Check for required job title.
if(citem.req_titles && length(citem.req_titles) > 0)
var/has_title
var/current_title = M.mind.role_alt_title ? M.mind.role_alt_title : M.mind.assigned_role
for(var/title in citem.req_titles)
if(title == current_title)
has_title = 1
break
if(!has_title)
to_chat(M, "A custom item could not be equipped as you have joined with the wrong role.")
return FALSE
// Places the item on the target mob.
/proc/place_custom_item(mob/living/carbon/human/M, var/datum/custom_item/citem)
// ID cards and MCs are applied directly to the existing object rather than spawned fresh.
var/obj/item/existing_item
if(citem.item_path == /obj/item/card/id)
existing_item = locate(/obj/item/card/id) in M.get_contents() //TODO: Improve this ?
else if(citem.item_path == /obj/item/modular_computer)
existing_item = locate(/obj/item/modular_computer) in M.contents
if(!citem) return
var/obj/item/newitem = citem.spawn_item()
// Spawn and equip the item.
if(existing_item)
citem.apply_to_item(existing_item)
return TRUE
else
var/obj/item/newitem = citem.spawn_item()
if(M.equip_to_appropriate_slot(newitem))
return newitem
if(M.equip_to_appropriate_slot(newitem))
return TRUE
if(M.equip_to_storage(newitem))
return newitem
if(M.equip_to_storage(newitem))
return TRUE
newitem.forceMove(get_turf(M.loc))
return newitem
newitem.forceMove(get_turf(M.loc))
to_chat(M, "A custom item has been placed on the floor as there was no space for it on your mob.")
return TRUE
+1 -1
View File
@@ -168,7 +168,7 @@ proc/spawn_money(var/sum, spawnloc, mob/living/carbon/human/human_user as mob)
return
/obj/item/spacecash/ewallet
name = "Charge card"
name = "charge card"
icon_state = "efundcard"
desc = "A card that holds an amount of money."
var/owner_name = "" //So the ATM can set it so the EFTPOS can put a valid name on transactions.
@@ -6,6 +6,10 @@
var/mob/living/heavy_vehicle/owner
maptext_y = 11
/obj/screen/mecha/proc/notify_user(var/mob/user, var/text)
if(user.loc == owner)
to_chat(user, text)
/obj/screen/mecha/radio
name = "radio"
icon_state = "base"
@@ -136,12 +140,12 @@
var/modifiers = params2list(params)
if(modifiers["ctrl"])
if(owner.hardpoints_locked)
to_chat(usr, "<span class='warning'>Hardpoint ejection system is locked.</span>")
notify_user(usr, SPAN_WARNING("The hardpoint ejection system is locked."))
return
if(owner.remove_system(hardpoint_tag))
to_chat(usr, "<span class='notice'>You disengage and discard the system mounted to your [hardpoint_tag] hardpoint.</span>")
notify_user(usr, SPAN_NOTICE("You disengage and discard the system mounted to your [hardpoint_tag] hardpoint."))
else
to_chat(usr, "<span class='danger'>You fail to remove the system mounted to your [hardpoint_tag] hardpoint.</span>")
notify_user(usr, SPAN_DANGER("You fail to remove the system mounted to your [hardpoint_tag] hardpoint."))
return
if(owner.selected_hardpoint == hardpoint_tag)
@@ -203,7 +207,7 @@
owner.use_air = toggled
var/main_color = owner.use_air ? "#d1d1d1" : "#525252"
maptext = "<span style=\"font-family: 'Small Fonts'; color: [main_color]; -dm-text-outline: 1 #242424; font-size: 6px;\">AIR</span>"
to_chat(usr, "<span class='notice'>Auxiliary atmospheric system [owner.use_air ? "enabled" : "disabled"].</span>")
notify_user(usr, SPAN_NOTICE("Auxiliary atmospheric system [owner.use_air ? "enabled" : "disabled"]."))
/obj/screen/mecha/toggle/maint
name = "toggle maintenance protocol"
@@ -217,7 +221,7 @@
owner.maintenance_protocols = toggled
var/main_color = owner.maintenance_protocols ? "#d1d1d1" : "#525252"
maptext = "<span style=\"font-family: 'Small Fonts'; color: [main_color]; -dm-text-outline: 1 #242424; font-size: 6px;\">MAINT</span>"
to_chat(usr, "<span class='notice'>Maintenance protocols [owner.maintenance_protocols ? "enabled" : "disabled"].</span>")
notify_user(usr, SPAN_NOTICE("Maintenance protocols [owner.maintenance_protocols ? "enabled" : "disabled"]."))
/obj/screen/mecha/toggle/hardpoint
name = "toggle hardpoint lock"
@@ -227,13 +231,13 @@
/obj/screen/mecha/toggle/hardpoint/toggled()
if(owner.force_locked)
to_chat(usr, "<span class='warning'>The locking system cannot be operated due to software restriction. Contact the manufacturer for more details.</span>")
notify_user(usr, SPAN_WARNING("The locking system cannot be operated due to software restriction. Contact the manufacturer for more details."))
return
toggled = !toggled
owner.hardpoints_locked = toggled
var/main_color = owner.hardpoints_locked ? "#d1d1d1" : "#525252"
maptext = "<span style=\"font-family: 'Small Fonts'; color: [main_color]; -dm-text-outline: 1 #242424; font-size: 6px;\">GEAR</span>"
to_chat(usr, "<span class='notice'>Hardpoint system access is now [owner.hardpoints_locked ? "disabled" : "enabled"].</span>")
notify_user(usr, SPAN_NOTICE("Hardpoint system access is now [owner.hardpoints_locked ? "disabled" : "enabled"]."))
/obj/screen/mecha/toggle/hatch
name = "toggle hatch lock"
@@ -243,10 +247,10 @@
/obj/screen/mecha/toggle/hatch/toggled()
if(!owner.hatch_locked && !owner.hatch_closed)
to_chat(usr, "<span class='warning'>You cannot lock the hatch while it is open.</span>")
notify_user(usr, SPAN_WARNING("You cannot lock the hatch while it is open."))
return
if(owner.force_locked)
to_chat(usr, "<span class='warning'>The locking system cannot be operated due to software restriction. Contact the manufacturer for more details.</span>")
notify_user(usr, SPAN_WARNING("The locking system cannot be operated due to software restriction. Contact the manufacturer for more details."))
return
toggled = !toggled
owner.hatch_locked = toggled
@@ -258,7 +262,7 @@
maptext = "<span style=\"font-family: 'Small Fonts'; -dm-text-outline: 1 #242424; font-size: 6px;\">LOCK</span>"
maptext_y = 11
maptext_x = 5
to_chat(usr, "<span class='notice'>The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked.</span>")
notify_user(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked."))
/obj/screen/mecha/toggle/hatch_open
name = "open or close hatch"
@@ -268,13 +272,13 @@
/obj/screen/mecha/toggle/hatch_open/toggled()
if(owner.hatch_locked && owner.hatch_closed)
to_chat(usr, "<span class='warning'>You cannot open the hatch while it is locked.</span>")
notify_user(usr, SPAN_WARNING("You cannot open the hatch while it is locked."))
return
toggled = !toggled
owner.hatch_closed = toggled
maptext = "<span style=\"font-family: 'Small Fonts'; -dm-text-outline: 1 #242424; font-size: 6px;\">[owner.hatch_closed ? "OPEN" : "CLOSE"]</span>"
maptext_x = owner.hatch_closed ? 4 : 3
to_chat(usr, "<span class='notice'>The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ].</span>")
notify_user(usr, SPAN_NOTICE("The [owner.body.hatch_descriptor] is now [owner.hatch_closed ? "closed" : "open" ]."))
owner.update_icon()
// This is basically just a holder for the updates the mech does.
@@ -291,15 +295,15 @@
/obj/screen/mecha/toggle/sensor/toggled()
if(!owner.head)
to_chat(usr, "<span class='warning'>I/O Error: Sensor systems not found.</span>")
notify_user(usr, SPAN_WARNING("I/O Error: Sensor systems not found."))
return
if(!owner.head.vision_flags)
to_chat(usr, "<span class='warning'>\The [owner.head] does not have any special sensor configurations.</span>")
notify_user(usr, SPAN_WARNING("\The [owner.head] does not have any special sensor configurations."))
return
toggled = !toggled
owner.head.active_sensors = toggled
var/main_color = owner.head.active_sensors ? "#d1d1d1" : "#525252"
maptext = "<span style=\"font-family: 'Small Fonts'; color: [main_color]; -dm-text-outline: 1 #242424; font-size: 5px;\">SENSOR</span>"
to_chat(usr, "<span class='notice'>[capitalize_first_letters(owner.head.name)] Advanced Sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active.</span>")
notify_user(usr, SPAN_NOTICE("[capitalize_first_letters(owner.head.name)] Advanced Sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active."))
#undef BAR_CAP
#undef BAR_CAP
@@ -0,0 +1,74 @@
/mob/living/heavy_vehicle/proc/can_move(var/mob/user)
. = 0
if(world.time < next_mecha_move)
return
if(incapacitated() || (user && user.incapacitated()) || lockdown)
return
if(!legs)
if(user)
to_chat(user, "<span class='warning'>\The [src] has no means of propulsion!</span>")
next_mecha_move = world.time + 3 // Just to stop them from getting spammed with messages.
return
if(!legs.motivator || legs.total_damage > 45)
if(user)
to_chat(user, "<span class='warning'>Your motivators are damaged! You can't move!</span>")
next_mecha_move = world.time + 15
return
next_mecha_move = world.time + legs.move_delay
if(maintenance_protocols)
if(user)
to_chat(user, "<span class='warning'>Maintenance protocols are in effect.</span>")
return
var/obj/item/cell/C = get_cell()
if(!C || !C.check_charge(legs.power_use * CELLRATE))
if(user)
to_chat(user, "<span class='warning'>The power indicator flashes briefly.</span>")
return
return TRUE
/mob/living/heavy_vehicle/proc/toggle_maintenance_protocols()
var/obj/screen/mecha/toggle/maint/M = locate() in hud_elements
M.toggled()
return TRUE
/mob/living/heavy_vehicle/proc/toggle_hatch()
var/obj/screen/mecha/toggle/hatch_open/H = locate() in hud_elements
H.toggled()
return TRUE
/mob/living/heavy_vehicle/proc/toggle_lock()
var/obj/screen/mecha/toggle/hatch/L = locate() in hud_elements
L.toggled()
return TRUE
/mob/living/heavy_vehicle/proc/can_listen()
return TRUE
/mob/living/heavy_vehicle/proc/assign_leader(var/mob/living/carbon/human/H)
leader_name = H.name
leader = WEAKREF(H)
/mob/living/heavy_vehicle/proc/unassign_leader()
leader = null
leader_name = null
/mob/living/heavy_vehicle/proc/assign_following(var/mob/living/carbon/human/H)
following_name = H.name
following = WEAKREF(H)
/mob/living/heavy_vehicle/proc/unassign_following()
following = null
following_name = null
/mob/living/heavy_vehicle/proc/prepare_nickname(var/text)
text = replacemany(text, list("\"" = "", "." = "", "," = ""))
text = trim_left(text)
text = trim_right(text)
return text
+153 -25
View File
@@ -238,6 +238,7 @@
if(user.client) user.client.screen |= hud_elements
LAZYDISTINCTADD(user.additional_vision_handlers, src)
update_icon()
walk(src, 0) // stop it from auto moving when the pilot gets in
return 1
/mob/living/heavy_vehicle/proc/sync_access()
@@ -275,31 +276,7 @@
UNSETEMPTY(pilots)
/mob/living/heavy_vehicle/relaymove(var/mob/living/user, var/direction)
if(world.time < next_mecha_move)
return 0
if(!user || incapacitated() || user.incapacitated() || lockdown)
return
if(!legs)
to_chat(user, "<span class='warning'>\The [src] has no means of propulsion!</span>")
next_mecha_move = world.time + 3 // Just to stop them from getting spammed with messages.
return
if(!legs.motivator || legs.total_damage > 45)
to_chat(user, "<span class='warning'>Your motivators are damaged! You can't move!</span>")
next_mecha_move = world.time + 15
return
next_mecha_move = world.time + legs.move_delay
if(maintenance_protocols)
to_chat(user, "<span class='warning'>Maintenance protocols are in effect.</span>")
return
var/obj/item/cell/C = get_cell()
if(!C || !C.check_charge(legs.power_use * CELLRATE))
to_chat(user, "<span class='warning'>The power indicator flashes briefly.</span>")
if(!can_move(user))
return
if(hallucination >= EMP_MOVE_DISRUPT && prob(30))
@@ -565,3 +542,154 @@
src.visible_message("<span class='warning'>\The [src] beeps loudly as its servos sieze up, and it enters lockdown mode!</span>")
else
src.visible_message("<span class='warning'>\The [src] hums with life as it is released from its lockdown mode!</span>")
/mob/living/heavy_vehicle/get_floating_chat_x_offset()
return 8
/mob/living/heavy_vehicle/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
if(can_listen())
addtimer(CALLBACK(src, .proc/handle_hear_say, speaker, message), 0.5 SECONDS)
return ..()
// heavily commented so it doesn't look like one fat chunk of code, which it still does - Geeves
/mob/living/heavy_vehicle/proc/handle_hear_say(var/mob/speaker, var/text)
var/found_text = findtext(text, name)
if(!found_text)
found_text = findtext(text, nickname)
if(found_text)
text = copytext(text, found_text) // I'm trimming the text each time so only information stated after eachother is valid
// a quick way to figure out the remote control status of the mech
if(findtext(text, "report diagnostics"))
var/has_leader = FALSE
if(leader)
var/mob/resolved_leader = leader.resolve()
if(!resolved_leader)
say("Error, leader not found. Unassigning...")
unassign_leader()
return
has_leader = TRUE
say("Currently [has_leader ? "paired with [leader_name]" : "unpaired"].")
if(following)
var/mob/resolved_following = following.resolve()
if(!resolved_following)
say("Error, follow target not found. Unassigning...")
unassign_following()
else
say("Currently following [resolved_following.name].")
if(nickname)
say("Nickname set to [nickname].")
say("Maintenance protocols, [maintenance_protocols ? "active" : "disabled"].")
return
// Checking whether we have a leader or not
if(!leader)
if(!maintenance_protocols) // don't select a leader unless we have maintenance protocols set
return
// If we have no leader, we listen to the keywords 'listen to'
if(findtext(text, "listen to"))
text = copytext(text, found_text)
found_text = findtext(text, "me") // if they say listen to me, we listen to them
if(found_text)
assign_leader(speaker)
say("New paired leader, [leader_name], confirmed and added to temporary biometric database.")
return
// check for humans and their IDs
for(var/mob/living/carbon/human/H in view(world.view, src))
var/obj/item/card/id/ID = H.GetIdCard(TRUE)
if(ID?.registered_name) // we ID people based on their... ID
if(findtext(text, ID.registered_name))
assign_leader(H)
say("New paired leader, [ID.registered_name], confirmed and added to temporary biometric database.")
break
return
else
var/mob/resolved_leader = leader.resolve()
if(!resolved_leader)
say("Error, leader not found. Unassigning...")
unassign_leader()
return
if(speaker != resolved_leader || (speaker in pilots))
return
found_text = findtext(text, "set nickname to")
if(found_text)
text = copytext(text, found_text + 15)
text = prepare_nickname(text)
if(lowertext(text) == "null")
nickname = null
say("Nickname removed.")
else
nickname = text
say("Nickname set to [text].")
return
// simply toggle maintenance protocols
if(findtext(text, "toggle maintenance protocols"))
if(toggle_maintenance_protocols())
say("Maintenance protocols toggled [maintenance_protocols ? "on" : "off"].")
return
// simply open or close the hatch
if(findtext(text, "toggle hatch"))
if(hatch_locked || force_locked)
say("Hatch locked, cannot toggle status.")
return
if(toggle_hatch())
say("Hatch [hatch_closed ? "closed" : "opened"].")
return
// simply toggle the lock status
if(findtext(text, "toggle lock"))
if(!hatch_closed)
say("Hatch lock cannot be toggled while the hatch is open.")
return
if(force_locked)
say("Hatch lock forced on, cannot override.")
return
if(toggle_lock())
say("Hatch [hatch_locked ? "locked" : "unlocked"].")
return
// unlink the leader to get a new one
if(findtext(text, "unlink"))
unassign_leader()
say("Leader dropped, awaiting new leader.")
return
// stop following who you were assigned to follow
if(findtext(text, "stop"))
unassign_following()
walk(src, 0)
say("Holding position.")
return
// set a follow range for the mecha, one to three, at which point it stops approaching
found_text = findtext(text, "follow range")
if(found_text)
text = copytext(text, found_text)
var/list/follow_range = list("one", "two", "three")
for(var/i = 1 to length(follow_range))
if(findtext(text, follow_range[i]))
say("Follow range set to [follow_range[i]] units.")
follow_distance = i
break
return
// set who it has to follow, broken into two steps to make it more versatile
found_text = findtext(text, "follow")
if(found_text)
text = copytext(text, found_text)
found_text = findtext(text, "me")
if(found_text)
assign_following(speaker)
say("Following [speaker.name].")
return
for(var/mob/living/carbon/human/H in view(world.view, src))
var/obj/item/card/id/ID = H.GetIdCard(TRUE)
if(ID?.registered_name) // we ID people based on their... ID
if(findtext(text, ID.registered_name))
assign_following(H)
say("Following [ID.registered_name].")
break
return
+19
View File
@@ -41,6 +41,25 @@
handle_vision()
handle_hud_icons()
/mob/living/heavy_vehicle/think()
var/mob/resolved_following
if(following)
resolved_following = following.resolve()
if(length(pilots))
if(resolved_following && !(resolved_following in pilots)) // if the person we're following is our pilot, we keep following them, otherwise we drop them
unassign_following()
return
if(following)
if(isturf(loc) && can_move())
if(resolved_following)
walk_to(src, resolved_following, follow_distance, legs.move_delay)
else
unassign_following()
else
walk(src, 0) // this stops them from moving
/mob/living/heavy_vehicle/get_cell()
RETURN_TYPE(/obj/item/cell)
return body?.cell
+16
View File
@@ -9,6 +9,7 @@
mob_size = MOB_LARGE
mob_push_flags = ALLMOBS
can_buckle = FALSE
accent = ACCENT_TTS
var/decal
var/emp_damage = 0
@@ -27,6 +28,16 @@
var/list/saved_access = list()
var/sync_access = TRUE
// Mob we're currently paired with or following | the names are saved to prevent metagaming when returning diagnostics
var/datum/weakref/leader
var/leader_name
var/datum/weakref/following
var/following_name
// Orders from our leader
var/nickname // we'll respond to our name or our nickname
var/follow_distance = 3
// Mob currently piloting the mech.
var/list/pilots
var/list/pilot_overlays
@@ -75,6 +86,8 @@
var/obj/screen/mecha/power/hud_power
/mob/living/heavy_vehicle/Destroy()
unassign_leader()
unassign_following()
selected_system = null
@@ -199,6 +212,9 @@
// Build icon.
update_icon()
add_language(LANGUAGE_TCB)
set_default_language(LANGUAGE_TCB)
. = INITIALIZE_HINT_LATELOAD
/mob/living/heavy_vehicle/LateInitialize()
+6 -2
View File
@@ -70,6 +70,10 @@
throw_range = 20
/obj/item/bananapeel/Crossed(AM as mob|obj)
if (istype(AM, /mob/living))
if(isliving(AM))
if(ishuman(AM))
var/mob/living/carbon/human/H = AM
if(H.shoes?.item_flags & LIGHTSTEP)
return
var/mob/living/M = AM
M.slip("the [src.name]",4)
M.slip("the [src.name]",4)
+31 -26
View File
@@ -15,7 +15,7 @@
var/obj/machinery/mineral/processing_unit/machine
var/show_all_ores = FALSE
var/points = 0
var/obj/item/card/id/inserted_id
var/datum/weakref/scanned_id
var/list/ore/input_mats = list()
var/list/material/output_mats = list()
@@ -46,17 +46,25 @@
/obj/machinery/mineral/processing_unit_console/attack_hand(mob/user)
add_fingerprint(user)
if(!scanned_id)
get_user_id(user)
else
var/obj/item/card/id/ID = scanned_id.resolve()
if(!ID)
scanned_id = null
get_user_id(user)
else
var/turf/id_turf = get_turf(ID)
if(!id_turf.Adjacent(loc))
scanned_id = null
get_user_id(user)
interact(user)
/obj/machinery/mineral/processing_unit_console/attackby(obj/item/I, mob/user)
if(istype(I,/obj/item/card/id))
var/obj/item/card/id/C = user.get_active_hand()
if(istype(C) && !istype(inserted_id))
user.drop_from_inventory(C, src)
inserted_id = C
interact(user)
else
..()
/obj/machinery/mineral/processing_unit_console/proc/get_user_id(var/mob/user)
if(!scanned_id && !isDrone(user))
var/obj/item/card/id/ID = user.GetIdCard()
if(ID)
scanned_id = WEAKREF(ID)
/obj/machinery/mineral/processing_unit_console/interact(mob/user)
if(..())
@@ -75,8 +83,9 @@
dat += "Current unclaimed points: [points]<br>"
if(istype(inserted_id))
dat += "You have [inserted_id.mining_points] mining points collected. <A href='?src=\ref[src];choice=eject'>Eject ID.</A><br>"
var/obj/item/card/id/ID = scanned_id.resolve()
if(ID)
dat += "You have [ID.mining_points] mining points collected. <A href='?src=\ref[src];choice=eject'>Eject ID.</A><br>"
dat += "<A href='?src=\ref[src];choice=claim'>Claim points.</A><br>"
dat += "<A href='?src=\ref[src];choice=print_report'>Print yield declaration.</A><br>"
else
@@ -121,15 +130,14 @@
src.add_fingerprint(usr)
if(href_list["choice"])
if(istype(inserted_id))
var/obj/item/card/id/ID = scanned_id.resolve()
if(ID)
if(href_list["choice"] == "eject")
inserted_id.forceMove(loc)
usr.put_in_hands(inserted_id)
inserted_id = null
scanned_id = null
if(href_list["choice"] == "claim")
if(access_mining_station in inserted_id.access)
if(access_mining_station in ID.access)
if(points >= 0)
inserted_id.mining_points += points
ID.mining_points += points
if(points != 0)
ping("\The [src] pings, \"Point transfer complete! Transaction total: [points] points!\"")
points = 0
@@ -138,7 +146,7 @@
else
to_chat(usr, SPAN_WARNING("Required access not found."))
if(href_list["choice"] == "print_report")
if(access_mining_station in inserted_id.access)
if(access_mining_station in ID.access)
print_report(usr)
else
to_chat(usr, SPAN_WARNING("Required access not found."))
@@ -146,10 +154,7 @@
else if(href_list["choice"] == "insert")
var/obj/item/card/id/I = usr.get_active_hand()
if(istype(I))
usr.drop_from_inventory(I,src)
inserted_id = I
else
to_chat(usr, SPAN_WARNING("No valid ID."))
scanned_id = WEAKREF(I)
if(href_list["toggle_smelting"])
var/choice = input("What setting do you wish to use for processing [href_list["toggle_smelting"]]?") as null|anything in list("Smelting","Compressing","Alloying","Nothing")
@@ -183,7 +188,8 @@
return
/obj/machinery/mineral/processing_unit_console/proc/print_report(var/mob/living/user)
if(!inserted_id)
var/obj/item/card/id/ID = scanned_id.resolve()
if(!ID)
to_chat(user, SPAN_WARNING("No ID inserted. Cannot digitally sign."))
return
if(!input_mats.len && !output_mats.len && !alloy_mats)
@@ -270,8 +276,7 @@
input_mats = list()
waste = 0
if(ishuman(user) && !(user.l_hand && user.r_hand))
user.put_in_hands(P)
user.put_in_hands(P)
printing = FALSE
return
+31 -26
View File
@@ -66,7 +66,7 @@ var/global/list/minevendor_list = list( //keep in order of price
icon_state = "mining"
density = TRUE
anchored = TRUE
var/obj/item/card/id/inserted_id
var/datum/weakref/scanned_id
/datum/data/mining_equipment
var/equipment_name = "generic"
@@ -103,13 +103,32 @@ var/global/list/minevendor_list = list( //keep in order of price
/obj/machinery/mineral/equipment_vendor/attack_hand(mob/user)
if(..())
return
if(!scanned_id)
get_user_id(user)
else
var/obj/item/card/id/ID = scanned_id.resolve()
if(!ID)
scanned_id = null
get_user_id(user)
else
var/turf/id_turf = get_turf(ID)
if(!id_turf.Adjacent(loc))
scanned_id = null
get_user_id(user)
interact(user)
/obj/machinery/mineral/equipment_vendor/proc/get_user_id(var/mob/user)
if(!scanned_id && !isDrone(user))
var/obj/item/card/id/ID = user.GetIdCard()
if(ID)
scanned_id = WEAKREF(ID)
/obj/machinery/mineral/equipment_vendor/interact(mob/user)
var/dat
dat +="<div class='statusDisplay'>"
if(istype(inserted_id))
dat += "You have [inserted_id.mining_points ? inserted_id.mining_points : 0] mining points collected. <A href='?src=\ref[src];choice=eject'>Eject ID.</A><br>"
var/obj/item/card/id/ID = scanned_id.resolve()
if(ID)
dat += "You have [ID.mining_points ? ID.mining_points : 0] mining points collected. <A href='?src=\ref[src];choice=eject'>Eject ID.</A><br>"
else
dat += "No ID inserted. <A href='?src=\ref[src];choice=insert'>Insert ID.</A><br>"
dat += "</div>"
@@ -132,30 +151,23 @@ var/global/list/minevendor_list = list( //keep in order of price
if(..())
return
if(href_list["choice"])
if(istype(inserted_id))
var/obj/item/card/id/ID = scanned_id.resolve()
if(ID)
if(href_list["choice"] == "eject")
inserted_id.forceMove(loc)
if(ishuman(usr))
if(!usr.get_active_hand())
usr.put_in_hands(inserted_id)
else
inserted_id.forceMove(get_turf(src))
inserted_id = null
scanned_id = null
else if(href_list["choice"] == "insert")
var/obj/item/card/id/I = usr.get_active_hand()
if(istype(I))
usr.drop_from_inventory(I,src)
inserted_id = I
else
to_chat(usr, SPAN_DANGER("No valid ID."))
scanned_id = WEAKREF(I)
if(href_list["purchase"])
if(istype(inserted_id))
var/obj/item/card/id/ID = scanned_id.resolve()
if(ID)
var/datum/data/mining_equipment/prize = locate(href_list["purchase"])
if(!prize || !(prize in minevendor_list))
return
if(prize.amount <= 0 && prize.amount != -1)
return
if(prize.cost > inserted_id.mining_points)
if(prize.cost > ID.mining_points)
else
if(prize.shuttle)
var/datum/shuttle/autodock/ferry/supply/shuttle = SScargo.shuttle
@@ -185,7 +197,7 @@ var/global/list/minevendor_list = list( //keep in order of price
var/turf/pickedloc = clear_turfs[i]
if(pickedloc)
inserted_id.mining_points -= prize.cost
ID.mining_points -= prize.cost
new prize.equipment_path(pickedloc)
to_chat(usr, SPAN_NOTICE("Order passed. Your order has been placed on the next available supply shuttle."))
else
@@ -195,7 +207,7 @@ var/global/list/minevendor_list = list( //keep in order of price
to_chat(usr, SPAN_DANGER("{ERR Code: NO_SHUTTLE} Order failed! Please try again."))
return
else
inserted_id.mining_points -= prize.cost
ID.mining_points -= prize.cost
if(prize.amount != -1)
prize.amount--
new prize.equipment_path(get_turf(src))
@@ -219,13 +231,6 @@ var/global/list/minevendor_list = list( //keep in order of price
qdel(I)
user.put_in_hands(dispensed_equipment)
return
else if(istype(I,/obj/item/card/id))
var/obj/item/card/id/C = usr.get_active_hand()
if(istype(C) && !istype(inserted_id))
usr.drop_from_inventory(C,src)
inserted_id = C
interact(user)
return
if(default_deconstruction_screwdriver(user, "mining-open", "mining", I))
updateUsrDialog()
return
@@ -1712,7 +1712,48 @@ Follow by example and make good judgement based on length which list to include
length = 2
chatname = "ponytail"
/*
/////////////////////////////////////
/ =-----------------------------= /
/ == Hair Gradient Definitions == /
/ =-----------------------------= /
/////////////////////////////////////
*/
/datum/sprite_accessory/hair_gradients
icon = 'icons/mob/hair_gradients.dmi'
none
name = "None"
icon_state = "none"
fade_up
name = "Fade (Up)"
icon_state = "fadeup"
fade_down
name = "Fade (Down)"
icon_state = "fadedown"
fade_right
name = "Fade (Right)"
icon_state = "faderight"
fade_left
name = "Fade (Left)"
icon_state = "fadeleft"
vertical_split_right
name = "Vertical Split (Right)"
icon_state = "vsplit_right"
vertical_split_left
name = "Vertical Split (Left)"
icon_state = "vsplit_left"
horizontal
name = "Horizontal Split"
icon_state = "hsplit"
/*
///////////////////////////////////
/ =---------------------------= /
@@ -3155,4 +3196,4 @@ Follow by example and make good judgement based on length which list to include
xion_lights
name = "Xion - Lights Color"
icon_state = "xion_lights"
body_parts = list(BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_CHEST,BP_HEAD)
body_parts = list(BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_CHEST,BP_HEAD)
+2 -2
View File
@@ -51,7 +51,7 @@ var/list/floating_chat_colors = list()
I.maptext_height = 64
I.plane = FLOAT_PLANE
I.layer = HUD_LAYER - 0.01
I.pixel_x = -round(I.maptext_width/2) + 16
I.pixel_x = (-round(I.maptext_width/2) + 16) + holder.get_floating_chat_x_offset()
I.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM
style = "font-family: 'Small Fonts'; -dm-text-outline: 1 black; font-size: [size]px; [style]"
@@ -69,4 +69,4 @@ var/list/floating_chat_colors = list()
/proc/remove_floating_text(atom/movable/holder, image/I)
animate(I, 2, pixel_y = I.pixel_y + 10, alpha = 0)
LAZYREMOVE(holder.stored_chat_text, I)
LAZYREMOVE(holder.stored_chat_text, I)
+3 -2
View File
@@ -1,11 +1,12 @@
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
/obj/item/device/mmi/digital/New()
/obj/item/device/mmi/digital/Initialize(mapload, ...)
. = ..()
src.brainmob = new(src)
brainmob.add_language(LANGUAGE_EAL)
src.brainmob.stat = CONSCIOUS
src.brainmob.container = src
src.brainmob.silent = 0
..()
/obj/item/device/mmi/digital/transfer_identity(var/mob/living/carbon/H)
brainmob.dna = H.dna
+6 -28
View File
@@ -8,6 +8,12 @@
use_me = 0 //Can't use the me verb, it's a freaking immobile brain
icon = 'icons/obj/surgery.dmi'
icon_state = "brain"
accent = ACCENT_TTS
/mob/living/carbon/brain/Initialize()
. = ..()
add_language(LANGUAGE_TCB)
set_default_language(all_languages[LANGUAGE_TCB])
/mob/living/carbon/brain/Destroy()
if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
@@ -17,34 +23,6 @@
container = null
return ..()
/mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd
if (istype(other, /mob/living/silicon/ai))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
else if (istype(other, /mob/living/silicon/decoy))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
else if (istype(other, /mob/living/silicon/pai))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
else if (istype(other, /mob/living/silicon/robot))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
else if (istype(other, /mob/living/carbon/human))
return 1
else if (istype(other, /mob/living/carbon/slime))
return 1
return ..()
/mob/living/carbon/brain/update_canmove()
if(istype(loc, /obj/item/device/mmi))
canmove = 1
@@ -405,6 +405,7 @@
dat += "<BR><A href='?src=\ref[src];item=tie'>Remove accessory</A>"
dat += "<BR><A href='?src=\ref[src];item=splints'>Remove splints</A>"
dat += "<BR><A href='?src=\ref[src];item=pockets'>Empty pockets</A>"
dat += species.get_strip_info("\ref[src]")
dat += "<BR><A href='?src=\ref[user];refresh=1'>Refresh</A>"
dat += "<BR><A href='?src=\ref[user];mach_close=mob[name]'>Close</A>"
@@ -591,6 +592,9 @@
if(href_list["item"])
handle_strip(href_list["item"],usr)
if(href_list["species"])
species.handle_strip(usr, src, href_list["species"])
if(href_list["criminal"])
if(hasHUD(usr,"security"))
@@ -5,6 +5,12 @@
var/b_hair = 0
var/h_style = "Bald"
//Hair gradient color and style
var/r_grad = 0
var/g_grad = 0
var/b_grad = 0
var/g_style = "None"
//Facial hair colour and style
var/r_facial = 0
var/g_facial = 0
@@ -116,4 +122,4 @@
var/datum/unarmed_attack/default_attack //default unarmed attack
var/datum/martial_art/primary_martial_art = null
var/list/datum/martial_art/known_martial_arts = null
var/list/datum/martial_art/known_martial_arts = null
@@ -19,7 +19,7 @@
if(can_feel_pain())
if(get_shock() >= 10)
tally += (get_shock() / 10) //pain shouldn't slow you down if you can't even feel it
tally += (get_shock() / 30) //pain shouldn't slow you down if you can't even feel it
tally += ClothesSlowdown()
+15 -5
View File
@@ -728,8 +728,10 @@
if(paralysis || sleeping || InStasis())
blinded = TRUE
stat = UNCONSCIOUS
adjustHalLoss(-3)
if(sleeping)
stat = UNCONSCIOUS
adjustHalLoss(-7)
if (species.tail)
animate_tail_reset()
if(prob(2) && is_asystole() && isSynthetic())
@@ -765,11 +767,11 @@
if(resting)
dizziness = max(0, dizziness - 15)
jitteriness = max(0, jitteriness - 15)
adjustHalLoss(-3)
adjustHalLoss(-5)
else
dizziness = max(0, dizziness - 3)
jitteriness = max(0, jitteriness - 3)
adjustHalLoss(-1)
adjustHalLoss(-3)
//Other
handle_statuses()
@@ -810,7 +812,7 @@
return
if(stat != DEAD)
if(stat == UNCONSCIOUS && health < maxHealth / 2)
if((stat == UNCONSCIOUS && health < maxHealth / 2) || paralysis || InStasis())
//Critical damage passage overlay
var/severity = 0
switch(health - maxHealth/2)
@@ -824,6 +826,8 @@
if(-90 to -80) severity = 8
if(-95 to -90) severity = 9
if(-INFINITY to -95) severity = 10
if(paralysis || InStasis())
severity = max(severity, 8)
overlay_fullscreen("crit", /obj/screen/fullscreen/crit, severity)
else
clear_fullscreen("crit")
@@ -858,6 +862,12 @@
else
clear_fullscreen("brute")
if(paralysis_indicator)
if(paralysis)
paralysis_indicator.icon_state = "paralysis1"
else
paralysis_indicator.icon_state = "paralysis0"
if(healths)
healths.overlays.Cut()
if (chem_effects[CE_PAINKILLER] > 100)
@@ -150,6 +150,9 @@
return returns
/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, successful_radio)
if(paralysis || InStasis())
whisper_say(message, speaking, alt_name)
return TRUE
switch(message_mode)
if("intercom")
for(var/obj/item/device/radio/intercom/I in view(1))
@@ -236,6 +236,7 @@
var/default_h_style = "Bald"
var/default_f_style = "Shaved"
var/default_g_style = "None"
var/list/allowed_citizenships = list(CITIZENSHIP_BIESEL, CITIZENSHIP_SOL, CITIZENSHIP_COALITION, CITIZENSHIP_ELYRA, CITIZENSHIP_ERIDANI, CITIZENSHIP_DOMINIA)
var/list/allowed_religions = list(RELIGION_NONE, RELIGION_OTHER, RELIGION_CHRISTIANITY, RELIGION_ISLAM, RELIGION_JUDAISM, RELIGION_HINDU, RELIGION_BUDDHISM, RELIGION_MOROZ, RELIGION_TRINARY, RELIGION_SCARAB, RELIGION_TAOISM)
@@ -607,6 +608,7 @@
/datum/species/proc/set_default_hair(var/mob/living/carbon/human/H)
H.h_style = H.species.default_h_style
H.f_style = H.species.default_f_style
H.g_style = H.species.default_g_style
H.update_hair()
/datum/species/proc/get_species_tally(var/mob/living/carbon/human/H)
@@ -633,6 +635,12 @@
/datum/species/proc/handle_despawn()
return
/datum/species/proc/handle_strip(var/mob/user, var/mob/living/carbon/human/H, var/action)
return
/datum/species/proc/get_strip_info(var/reference)
return ""
/datum/species/proc/get_pain_emote(var/mob/living/carbon/human/H, var/pain_power)
if(flags & NO_PAIN)
return
@@ -34,6 +34,20 @@
appearance_flags = HAS_HAIR_COLOR | HAS_LIPS | HAS_UNDERWEAR | HAS_SKIN_COLOR | HAS_SOCKS
flags = NO_SLIP
has_limbs = list(
BP_CHEST = list("path" = /obj/item/organ/external/chest),
BP_GROIN = list("path" = /obj/item/organ/external/groin),
BP_HEAD = list("path" = /obj/item/organ/external/head/skrell),
BP_L_ARM = list("path" = /obj/item/organ/external/arm),
BP_R_ARM = list("path" = /obj/item/organ/external/arm/right),
BP_L_LEG = list("path" = /obj/item/organ/external/leg),
BP_R_LEG = list("path" = /obj/item/organ/external/leg/right),
BP_L_HAND = list("path" = /obj/item/organ/external/hand),
BP_R_HAND = list("path" = /obj/item/organ/external/hand/right),
BP_L_FOOT = list("path" = /obj/item/organ/external/foot),
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right)
)
has_organ = list(
BP_HEART = /obj/item/organ/internal/heart/skrell,
BP_LUNGS = /obj/item/organ/internal/lungs/skrell,
@@ -71,6 +85,25 @@
/datum/species/skrell/handle_post_spawn(mob/living/carbon/human/H)
H.set_psi_rank(PSI_COERCION, PSI_RANK_OPERANT)
/datum/species/skrell/handle_strip(var/mob/user, var/mob/living/carbon/human/H, var/action)
switch(action)
if("headtail")
if(!H.head)
to_chat(user, SPAN_WARNING("\The [H] doesn't have a head!"))
return
user.visible_message(SPAN_WARNING("\The [user] is trying to remove something from \the [H]'s headtails!"))
if(do_after(usr, HUMAN_STRIP_DELAY, act_target = H))
var/obj/item/storage/internal/skrell/S = locate() in H.head
var/obj/item/I = locate() in S
if(!I)
to_chat(usr, SPAN_WARNING("\The [H] had nothing in their headtail storage."))
return
S.remove_from_storage(I, get_turf(H))
return
/datum/species/skrell/get_strip_info(var/reference)
return "<BR><A href='?src=[reference];species=headtail'>Empty Headtail Storage</A>"
/datum/species/skrell/can_breathe_water()
return TRUE
@@ -370,7 +370,7 @@ There are several things that need to be remembered:
// This proc generates & returns an icon representing a human's hair, using a cached icon from SSicon_cache if possible.
// If `hair_is_visible` is FALSE, only facial hair will be drawn.
/mob/living/carbon/human/proc/generate_hair_icon(hair_is_visible = TRUE)
var/cache_key = "[f_style ? "[f_style][r_facial][g_facial][b_facial]" : "nofacial"]_[(h_style && hair_is_visible) ? "[h_style][r_hair][g_hair][b_hair]" : "nohair"]"
var/cache_key = "[f_style ? "[f_style][r_facial][g_facial][b_facial]" : "nofacial"]_[(h_style && hair_is_visible) ? "[h_style][r_hair][g_hair][b_hair]" : "nohair"]_[(g_style && g_style != "None" && hair_is_visible) ? "[g_style][r_grad][g_grad][b_grad]" : "nograd"]"
var/icon/face_standing = SSicon_cache.human_hair_cache[cache_key]
if (!face_standing) // Not cached, generate it from scratch.
@@ -387,11 +387,19 @@ There are several things that need to be remembered:
// Hair.
if(hair_is_visible)
var/icon/grad_s = null
var/datum/sprite_accessory/hair_style = hair_styles_list[h_style]
if(hair_style && (species.type in hair_style.species_allowed))
var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = hair_style.icon_state)
if(hair_style.do_colouration)
if(g_style)
var/datum/sprite_accessory/gradient_style = hair_gradient_styles_list[g_style]
grad_s = new/icon("icon" = gradient_style.icon, "icon_state" = gradient_style.icon_state)
grad_s.Blend(hair_s, ICON_AND)
grad_s.Blend(rgb(r_grad, g_grad, b_grad), ICON_MULTIPLY)
hair_s.Blend(rgb(r_hair, g_hair, b_hair), hair_style.icon_blend_mode)
if(!isnull(grad_s))
hair_s.Blend(grad_s, ICON_OVERLAY)
face_standing.Blend(hair_s, ICON_OVERLAY)
+25 -4
View File
@@ -98,11 +98,29 @@ default behaviour is:
return
if(can_swap_with(tmob)) // mutual brohugs all around!
var/turf/oldloc = loc
forceMove(tmob.loc)
tmob.forceMove(oldloc)
var/turf/tmob_oldloc = tmob.loc
var/turf/src_oldloc = loc
if(pulling?.density)
tmob.forceMove(pulling.loc)
forceMove(tmob_oldloc)
pulling.forceMove(src_oldloc)
else if(tmob.pulling?.density)
forceMove(tmob.pulling.loc)
tmob.forceMove(src_oldloc)
tmob.pulling.forceMove(tmob_oldloc)
else
forceMove(tmob_oldloc)
if(pulling)
pulling.forceMove(src_oldloc)
tmob.forceMove(src_oldloc)
if(tmob.pulling)
tmob.pulling.forceMove(tmob_oldloc)
for(var/obj/item/grab/G in list(l_hand, r_hand))
G.affecting.forceMove(loc)
for(var/obj/item/grab/G in list(tmob.l_hand, tmob.r_hand))
G.affecting.forceMove(tmob.loc)
now_pushing = FALSE
for(var/mob/living/carbon/slime/slime in view(1,tmob))
for(var/mob/living/carbon/slime/slime in view(2, tmob))
if(slime.victim == tmob)
slime.UpdateFeed()
return
@@ -191,6 +209,9 @@ default behaviour is:
if(swap_density_check(tmob, src))
return 0
if(pulling?.density && tmob.pulling?.density) // if both are pulling, don't shuffle
return FALSE
return can_move_mob(tmob, 1, 0)
/mob/living/verb/succumb()
+2 -1
View File
@@ -8,7 +8,8 @@
SSfeedback.update_status()
if(admin_datums[src.ckey])
if (SSticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing.
var/datum/admins/A = admin_datums[src.ckey]
if (A.rights & (R_MOD|R_ADMIN) && SSticker.current_state == GAME_STATE_PLAYING) //Only report this stuff if we are currently playing.
var/admins_number = 0
var/admins_number_afk = 0
for (var/client/C in clients)
+1
View File
@@ -17,6 +17,7 @@
var/obj/screen/purged = null
var/obj/screen/internals/internals = null
var/obj/screen/oxygen = null
var/obj/screen/paralysis_indicator = null
var/obj/screen/i_select = null
var/obj/screen/m_select = null
var/obj/screen/toxin = null
@@ -24,7 +24,7 @@ var/global/ntnrc_uid = 0
for(var/datum/computer_file/program/chatclient/C in clients)
if(C.program_state > PROGRAM_STATE_KILLED)
C.computer.output_message("<b>([get_title(C)]) <i>[username]</i>:</b> [message] (<a href='byond://?src=\ref[C];Reply=1;target=[src.title]'>Reply</a>)", 0)
C.computer.output_message("<b>([get_title(C)]) <i>[username]</i>:</b> [message] (<a href='byond://?src=\ref[C];Reply=\ref[src]'>Reply</a>)", 0)
if(!C.silent && C.username != username && C.program_state == PROGRAM_STATE_BACKGROUND)
playsound(C.computer, 'sound/machines/twobeep.ogg', 50, 1)
C.computer.output_message("*[C.ringtone]*")
@@ -74,10 +74,22 @@
return TRUE
if(program && program.computer && program.computer.card_slot && program.computer.network_card)
var/obj/item/card/id/id_card = program.computer.card_slot.stored_card
var/using_id = FALSE
var/obj/item/card/id/id_card
if(program.computer.card_slot?.stored_card)
using_id = TRUE
id_card = program.computer.card_slot.stored_card
if(!id_card?.registered_name)
using_id = FALSE
status_message = "Card Error: Invalid ID Card in Card Reader"
return TRUE
var/obj/item/spacecash/ewallet/charge_card
if(!using_id)
if(isliving(usr))
var/mob/living/L = usr
charge_card = L.get_active_hand()
if(!istype(charge_card))
return TRUE
//Check if a payment is required
if(order_details["needs_payment"])
@@ -85,11 +97,19 @@
var/transaction_purpose = "Cargo Order #[order_details["order_id"]]"
var/transaction_terminal = "Modular Computer #[program.computer.network_card.identification_id]"
var/status = SSeconomy.transfer_money(id_card.associated_account_number, SScargo.supply_account.account_number,transaction_purpose,transaction_terminal,transaction_amount,null,usr)
if(status)
status_message = status
return TRUE
if(using_id)
var/status = SSeconomy.transfer_money(id_card.associated_account_number, SScargo.supply_account.account_number,transaction_purpose,transaction_terminal,transaction_amount,null,usr)
if(status)
status_message = status
return TRUE
else
if(charge_card.worth < transaction_amount)
status_message = "Insufficient Funds in Charge Card"
return TRUE
if(!SSeconomy.charge_to_account(SScargo.supply_account.account_number, charge_card.owner_name, transaction_purpose, transaction_terminal, transaction_amount))
status_message = "Account Error: Failed to Deposit Credits into Cargo Account"
return TRUE
charge_card.worth -= transaction_amount
playsound(program.computer, 'sound/machines/chime.ogg', 50, TRUE)
@@ -61,14 +61,15 @@
if(href_list["Reply"])
. = TRUE
if(!channel || channel.title != href_list["target"])
to_chat(usr, SPAN_WARNING("The target chat isn't active on your program anymore!"))
var/datum/ntnet_conversation/C = locate(href_list["Reply"]) in ntnet_global.chat_channels
if(!istype(C))
to_chat(usr, SPAN_WARNING("The target channel couldn't be found and has likely been deleted!"))
return
var/message = send_message()
if(!channel || channel.title != href_list["target"])
to_chat(usr, SPAN_WARNING("The target chat isn't active on your program anymore!"))
if(!(C in ntnet_global.chat_channels))
to_chat(usr, SPAN_WARNING("The target channel couldn't be found and has likely been deleted!"))
return
add_message(message)
add_message(message, C)
if(href_list["PRG_joinchannel"])
. = TRUE
@@ -219,11 +220,16 @@
return
return message
/datum/computer_file/program/chatclient/proc/add_message(var/message)
/datum/computer_file/program/chatclient/proc/add_message(var/message, var/datum/ntnet_conversation/specific_channel)
if(!message)
return
channel.add_message(message, username, usr)
message_dead(FONT_SMALL("<b>([channel.get_dead_title()]) [username]:</b> [message]"))
var/datum/ntnet_conversation/sent_channel
if(specific_channel)
sent_channel = specific_channel
else
sent_channel = channel
sent_channel.add_message(message, username, usr)
message_dead(FONT_SMALL("<b>([sent_channel.get_dead_title()]) [username]:</b> [message]"))
/datum/computer_file/program/chatclient/proc/direct_message()
var/clients = list()
+6 -2
View File
@@ -139,7 +139,7 @@
var/blood_max = 0
var/open_wound
var/list/do_spray = list()
for(var/obj/item/organ/external/temp in owner.organs)
for(var/obj/item/organ/external/temp in owner.bad_external_organs)
if((temp.status & ORGAN_BLEEDING) && !BP_IS_ROBOTIC(temp))
for(var/datum/wound/W in temp.wounds)
if(W.bleeding())
@@ -156,6 +156,8 @@
if(temp.status & ORGAN_ARTERY_CUT)
var/bleed_amount = Floor(owner.vessel.total_volume / (temp.applied_pressure || !open_wound ? 450 : 250))
if(bleed_amount)
if(CE_BLOODCLOT in owner.chem_effects)
bleed_amount *= 0.8 // won't do much, but it'll help
if(open_wound)
blood_max += bleed_amount
do_spray += "[temp.name]"
@@ -170,7 +172,9 @@
if(PULSE_2FAST, PULSE_THREADY)
blood_max *= 1.5
if(CE_STABLE in owner.chem_effects)
if(CE_BLOODCLOT in owner.chem_effects)
blood_max *= 0.7
else if(CE_STABLE in owner.chem_effects)
blood_max *= 0.8
if(world.time >= next_blood_squirt && istype(owner.loc, /turf) && do_spray.len)
+1
View File
@@ -73,6 +73,7 @@ mob/var/next_pain_time = 0
if(maxdam > 10 && paralysis)
paralysis = max(0, paralysis - round(maxdam / 10))
if(maxdam > 50 && prob(maxdam / 5))
to_chat(src, SPAN_WARNING("A bolt of pain shoots through your body, causing your hands to spasm!"))
drop_item()
var/burning = damaged_organ.burn_dam > damaged_organ.brute_dam
var/msg
+30
View File
@@ -16,3 +16,33 @@
/obj/item/organ/internal/brain/skrell
icon_state = "brain_skrell"
/obj/item/organ/external/head/skrell
var/obj/item/storage/internal/skrell/storage
action_button_name = "Headtail Pocket"
/obj/item/organ/external/head/skrell/Initialize(mapload)
. = ..()
addtimer(CALLBACK(src, .proc/setup_storage), 3 SECONDS)
/obj/item/organ/external/head/skrell/proc/setup_storage()
storage = new /obj/item/storage/internal/skrell(src)
if(owner)
storage.color = rgb(owner.r_hair, owner.g_hair, owner.b_hair)
refresh_action_button()
/obj/item/organ/external/head/skrell/refresh_action_button()
. = ..()
if(. && storage)
action.button_icon_state = storage.icon_state
action.button_icon_color = storage.color
if(action.button)
action.button.update_icon()
/obj/item/organ/external/head/skrell/removed()
. = ..()
for(var/thing in storage)
storage.remove_from_storage(thing, get_turf(src))
/obj/item/organ/external/head/skrell/attack_self(mob/user)
storage.open(user)
@@ -15,7 +15,7 @@
matter = list(DEFAULT_WALL_MATERIAL = 2000)
projectile_type = /obj/item/projectile/energy/disruptorstun
secondary_projectile_type = /obj/item/projectile/energy/blaster
max_shots = 12 //12 shots stun, 8 shots lethal.
max_shots = 8
charge_cost = 150
fire_delay = 8
accuracy = 1
@@ -24,8 +24,8 @@
sel_mode = 1
var/selectframecheck = FALSE
firemodes = list(
list(mode_name="stun", projectile_type=/obj/item/projectile/energy/disruptorstun, modifystate="disruptorpistolstun", charge_cost = 150, fire_sound = 'sound/weapons/gunshot/bolter.ogg'),
list(mode_name="lethal", projectile_type=/obj/item/projectile/energy/blaster, modifystate="disruptorpistolkill", recoil = 1, charge_cost = 225, fire_sound = 'sound/weapons/gunshot/bolter.ogg')
list(mode_name="stun", projectile_type=/obj/item/projectile/energy/disruptorstun, modifystate="disruptorpistolstun", fire_sound = 'sound/weapons/gunshot/bolter.ogg'),
list(mode_name="lethal", projectile_type=/obj/item/projectile/energy/blaster/disruptor, modifystate="disruptorpistolkill", recoil = 1, fire_sound = 'sound/weapons/gunshot/bolter.ogg')
)
/obj/item/gun/energy/disruptorpistol/security
@@ -35,7 +35,7 @@
name = "miniature disruptor pistol"
desc = "A Nanotrasen designed blaster pistol with two settings: stun and lethal. This is the miniature version."
icon = 'icons/obj/guns/disruptorpistol/disruptorpistolc.dmi'
max_shots = 7
max_shots = 5
force = 3
slot_flags = SLOT_BELT|SLOT_HOLSTER|SLOT_POCKET
w_class = ITEMSIZE_SMALL
@@ -47,7 +47,7 @@
name = "magnum disruptor pistol"
desc = "A Nanotrasen designed blaster pistol with two settings: stun and lethal. This is the magnum version."
icon = 'icons/obj/guns/disruptorpistol/disruptorpistolm.dmi'
max_shots = 20
max_shots = 12
force = 6
/obj/item/gun/energy/disruptorpistol/magnum/security
@@ -201,10 +201,14 @@
muzzle_type = /obj/effect/projectile/muzzle/bolt
hit_effect = /obj/effect/temp_visual/blaster_effect
/obj/item/projectile/energy/blaster/disruptor
damage = 20
pass_flags = PASSTABLE
/obj/item/projectile/energy/disruptorstun
name = "disruptor bolt"
icon_state = "blue_laser"
agony = 45
agony = 25
speed = 0.4
damage_type = PAIN // Can't blow your own head off with a stunbolt.
taser_effect = TRUE
+17 -10
View File
@@ -26,6 +26,7 @@
var/pillsprite = "1"
var/max_pill_count = 20
flags = OPENCONTAINER
var/datum/asset/spritesheet/chem_master/chem_asset
/obj/machinery/chem_master/Initialize()
. = ..()
@@ -202,16 +203,23 @@
var/obj/item/reagent_containers/food/condiment/P = new/obj/item/reagent_containers/food/condiment(get_turf(src))
reagents.trans_to_obj(P,50)
else if(href_list["change_pill"])
var/dat = "<table>"
if(!chem_asset)
chem_asset = get_asset_datum(/datum/asset/spritesheet/chem_master)
var/dat = chem_asset.css_tag()
dat += "<table>"
for(var/i = 1 to MAX_PILL_SPRITE)
dat += "<tr><td><a href=\"?src=\ref[src]&pill_sprite=[i]\"><img src=\"pill[i].png\" /></a></td></tr>"
var/pillicon = "pill[i]"
dat += "<tr><td><a href=\"?src=\ref[src]&pill_sprite=[i]\">[chem_asset.icon_tag(pillicon)]</a></td></tr>"
dat += "</table>"
usr << browse(dat, "window=chem_master")
return
else if(href_list["change_bottle"])
var/dat = "<table>"
if(!chem_asset)
chem_asset = get_asset_datum(/datum/asset/spritesheet/chem_master)
var/dat = chem_asset.css_tag()
dat += "<table>"
for(var/sprite in BOTTLE_SPRITES)
dat += "<tr><td><a href=\"?src=\ref[src]&bottle_sprite=[sprite]\"><img src=\"[sprite].png\" /></a></td></tr>"
dat += "<tr><td><a href=\"?src=\ref[src]&bottle_sprite=[sprite]\">[chem_asset.icon_tag(sprite)]</a></td></tr>"
dat += "</table>"
usr << browse(dat, "window=chem_master")
return
@@ -233,10 +241,9 @@
return
user.set_machine(src)
var/datum/asset/pill_icons = get_asset_datum(/datum/asset/chem_master)
pill_icons.send(user.client)
var/dat = ""
if(!chem_asset)
chem_asset = get_asset_datum(/datum/asset/spritesheet/chem_master)
var/dat = chem_asset.css_tag()
if(!beaker)
dat = "Please insert beaker.<BR>"
if(src.loaded_pill_bottle)
@@ -277,9 +284,9 @@
else
dat += "Empty<BR>"
if(!condi)
dat += "<HR><BR><A href='?src=\ref[src];createpill=1'>Create pill (60 units max)</A><a href=\"?src=\ref[src]&change_pill=1\"><img src=\"pill[pillsprite].png\" /></a><BR>"
dat += "<HR><BR><A href='?src=\ref[src];createpill=1'>Create pill (60 units max)</A><a href=\"?src=\ref[src]&change_pill=1\">[chem_asset.icon_tag("pill[pillsprite]")]</a><BR>"
dat += "<A href='?src=\ref[src];createpill_multiple=1'>Create multiple pills</A><BR>"
dat += "<A href='?src=\ref[src];createbottle=1'>Create bottle (60 units max)<a href=\"?src=\ref[src]&change_bottle=1\"><img src=\"[bottlesprite].png\" /></A>"
dat += "<A href='?src=\ref[src];createbottle=1'>Create bottle (60 units max)<a href=\"?src=\ref[src]&change_bottle=1\">[chem_asset.icon_tag(bottlesprite)]</A>"
else
dat += "<A href='?src=\ref[src];createbottle=1'>Create bottle (50 units max)</A>"
if(!condi)
@@ -2937,7 +2937,7 @@
caffeine = 0.3
taste_description = "giving up on peaceful coexistence"
glass_icon_state = "giscoffeeglass"
glass_icon_state = "fiscoffeeglass"
glass_name = "glass of Fisanduhian coffee"
glass_desc = "It's like an Irish coffee, but spicy and angry about Dominia."
glass_center_of_mass = list("x"=15, "y"=10)
@@ -1677,3 +1677,25 @@
/datum/reagent/rmt/overdose(var/mob/living/carbon/H, var/alien)
if(prob(2))
to_chat(H, SPAN_WARNING(pick("Your muscles are stinging a bit.", "Your muscles ache.")))
/datum/reagent/coagzolug
name = "Coagzolug"
description = "A medicine that was stumbled upon by accident, coagzolug encourages blood to clot and slow down bleeding. An overdose causes dangerous blood clots capable of harming the heart."
reagent_state = LIQUID
scannable = TRUE
color = "#bd5eb5"
overdose = 10
metabolism = REM / 3.33
taste_description = "throat-clenching sourness"
fallback_specific_heat = 1
/datum/reagent/coagzolug/affect_blood(mob/living/carbon/M, alien, removed)
. = ..()
M.add_chemical_effect(CE_BLOODCLOT)
M.make_dizzy(5)
/datum/reagent/coagzolug/overdose(var/mob/living/carbon/H, var/alien)
if(prob(2))
to_chat(H, SPAN_WARNING(pick("You feel a clot shoot through your heart!", "Your veins feel like they're being shredded!")))
var/obj/item/organ/internal/heart/heart = H.internal_organs_by_name[BP_HEART]
heart.take_internal_damage(1, TRUE)
@@ -478,6 +478,13 @@
required_reagents = list(/datum/reagent/sodiumchloride = 1, /datum/reagent/alcohol/ethanol = 1, /datum/reagent/radium = 1)
result_amount = 3
/datum/chemical_reaction/coagzolug
name = "Coagzolug"
id = "coagzolug"
result = /datum/reagent/coagzolug
required_reagents = list(/datum/reagent/tricordrazine = 1, /datum/reagent/coughsyrup = 1)
result_amount = 1 // result is 1. i imagine it's because of some whacky reaction
/datum/chemical_reaction/surfactant
name = "Azosurfactant"
id = "surfactant"
@@ -177,6 +177,17 @@
. = ..()
desc += " This auto-injector is to be used in emergencies. It contains a small amount of inaprovaline and dexalin."
/obj/item/reagent_containers/hypospray/autoinjector/coagzolug
name = "autoinjector (coagzolug)"
desc = "A rapid and safe way to administer small amounts of drugs by untrained or trained personnel. This one contains coagzolug, a quick-acting blood coagulant that will slow bleeding for as long as it's within the bloodstream."
volume = 5
flags = 0
/obj/item/reagent_containers/hypospray/autoinjector/coagzolug/Initialize()
. = ..()
reagents.add_reagent(/datum/reagent/coagzolug, 5)
update_icon()
/obj/item/reagent_containers/hypospray/autoinjector/sideeffectbgone
name = "sideeffects-be-gone! autoinjector"
desc = "A special cocktail designed to counter the side-effects of various drugs. Has 2 uses."
@@ -56,6 +56,11 @@
req_tech = list(TECH_DATA = 2, TECH_POWER = 2, TECH_ENGINEERING = 2)
build_path = /obj/item/circuitboard/mech_recharger
/datum/design/circuit/machine/heph_mech_recharger
name = "Hephaestus Mech Recharger"
req_tech = list(TECH_DATA = 3, TECH_POWER = 3, TECH_ENGINEERING = 4)
build_path = /obj/item/circuitboard/mech_recharger/hephaestus
/datum/design/circuit/machine/recharge_station
name = "Cyborg Recharge Station"
req_tech = list(TECH_DATA = 3, TECH_ENGINEERING = 2)
@@ -137,4 +137,10 @@ datum/design/item/tool/advanced_light_replacer
desc = "A heavily modified RFD, modified to construct pipes and piping accessories."
req_tech = list(TECH_ENGINEERING = 5, TECH_MATERIAL = 5)
materials = list(DEFAULT_WALL_MATERIAL = 3000, MATERIAL_GLASS = 2500, MATERIAL_SILVER = 2500)
build_path = /obj/item/rfd/piping
build_path = /obj/item/rfd/piping
/datum/design/item/tool/idris_backpack
desc = "The infamously Idris Service Standard refers to this monstrous, self-stabilizing back-mounted utensil and service item holder, not anything professional."
req_tech = list(TECH_ENGINEERING = 2, TECH_MATERIAL = 2)
materials = list(DEFAULT_WALL_MATERIAL = 1500, MATERIAL_GLASS = 1500)
build_path = /obj/item/storage/backpack/service
@@ -169,6 +169,12 @@ var/global/maint_all_access = 0
security_announcement.Announce("The maintenance access requirement has been readded on all maintenance airlocks.","Attention!")
/obj/machinery/door/airlock/allowed(mob/M)
if(maint_all_access && src.check_access_list(list(access_maint_tunnels)))
var/obj/item/I = M.GetIdCard()
if(!I)
return ..(M)
var/list/A = I.GetAccess()
var/maint_sec_access = ((security_level > SEC_LEVEL_GREEN) && has_access(access_security, accesses = A))
var/exceptional_circumstances = maint_all_access || maint_sec_access
if(exceptional_circumstances && src.check_access_list(list(access_maint_tunnels)))
return 1
return ..(M)
+43 -21
View File
@@ -1,5 +1,5 @@
/obj/machinery/shield
name = "Emergency energy shield"
name = "emergency energy shield"
desc = "An energy shield used to contain hull breaches."
icon = 'icons/effects/effects.dmi'
icon_state = "shield-old"
@@ -8,22 +8,38 @@
anchored = TRUE
unacidable = TRUE
atmos_canpass = CANPASS_NEVER
var/const/max_health = 200
var/health = max_health //The shield can only take so much beating (prevents perma-prisons)
var/health = 75 //The shield can only take so much beating (prevents perma-prisons)
var/shield_generate_power = 2500 //how much power we use when regenerating
var/shield_idle_power = 500 //how much power we use when just being sustained.
/obj/machinery/shield/malfai
name = "emergency forcefield"
desc = "A weak forcefield which seems to be projected by the station's emergency atmosphere containment field"
health = max_health/2 // Half health, it's not suposed to resist much.
desc = "A forcefield which seems to be projected by the station's emergency atmosphere containment field."
health = 100
/obj/machinery/shield/malfai/machinery_process()
health -= 0.5 // Slowly lose integrity over time
check_failure()
/obj/machinery/shield/proc/check_failure()
if (src.health <= 0)
var/health_percentage = (health / initial(health)) * 100
switch(health_percentage)
if(-INFINITY to 25)
if(alpha != 150)
animate(src, 1 SECOND, alpha = 150)
if(26 to 50)
if(alpha != 175)
animate(src, 1 SECOND, alpha = 175)
if(51 to 75)
if(alpha != 210)
animate(src, 1 SECOND, alpha = 210)
if(76 to 90)
if(alpha != 230)
animate(src, 1 SECOND, alpha = 230)
if(91 to INFINITY)
if(alpha != initial(alpha))
animate(src, 1 SECOND, alpha = initial(alpha))
if(health <= 0)
visible_message("<span class='notice'>\The [src] dissipates!</span>")
qdel(src)
return
@@ -43,19 +59,18 @@
if(!height || air_group) return FALSE
else return ..()
/obj/machinery/shield/attackby(obj/item/W as obj, mob/user as mob)
if(!istype(W)) return
/obj/machinery/shield/attackby(obj/item/W, mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
user.do_attack_animation(src, W)
//Calculate damage
var/aforce = W.force
if(W.damtype == BRUTE || W.damtype == BURN)
src.health -= aforce
health -= aforce
//Play a fitting sound
playsound(src.loc, 'sound/effects/EMPulse.ogg', 75, 1)
check_failure()
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
..()
@@ -112,8 +127,9 @@
..()
return
/obj/machinery/shieldgen
name = "Emergency shield projector"
name = "emergency shield projector"
desc = "Used to seal minor hull breaches."
icon = 'icons/obj/machines/shielding.dmi'
icon_state = "shieldoff"
@@ -121,8 +137,7 @@
opacity = FALSE
anchored = FALSE
req_access = list(access_engine)
var/const/max_health = 100
var/health = max_health
var/health = 100
var/active = FALSE
var/malfunction = FALSE //Malfunction causes parts of the shield to slowly dissapate
var/list/deployed_shields = list()
@@ -161,12 +176,19 @@
update_use_power(FALSE)
/obj/machinery/shieldgen/proc/create_shields()
for(var/turf/target_tile in range(2, src))
if (istype(target_tile,/turf/space) || istype(target_tile,/turf/simulated/open) || istype(target_tile,/turf/unsimulated/floor/asteroid/ash) || istype(target_tile,/turf/simulated/floor/airless) && !(locate(/obj/machinery/shield) in target_tile))
if (malfunction && prob(33) || !malfunction)
var/obj/machinery/shield/S = new /obj/machinery/shield(target_tile)
deployed_shields += S
use_power(S.shield_generate_power)
for(var/T in RANGE_TURFS(2, src))
var/turf/target_tile = T
var/obj/item/tape/engineering/E = locate() in target_tile
if(E?.shield_marker)
deploy_shield(target_tile)
else if(istype(target_tile,/turf/space) || istype(target_tile,/turf/simulated/open) || istype(target_tile,/turf/unsimulated/floor/asteroid/ash) || istype(target_tile,/turf/simulated/floor/airless) && !(locate(/obj/machinery/shield) in target_tile))
if(malfunction && prob(33) || !malfunction)
deploy_shield(target_tile)
/obj/machinery/shieldgen/proc/deploy_shield(var/turf/T)
var/obj/machinery/shield/S = new /obj/machinery/shield(T)
deployed_shields += S
use_power(S.shield_generate_power)
/obj/machinery/shieldgen/proc/collapse_shields()
for(var/obj/machinery/shield/shield_tile in deployed_shields)
@@ -286,7 +308,7 @@
//if(do_after(user, min(60, round( ((maxhealth/health)*10)+(malfunction*10) ))) //Take longer to repair heavier damage
if(do_after(user, 30))
if (coil.use(1))
health = max_health
health = initial(health)
malfunction = FALSE
to_chat(user, "<span class='notice'>You repair the [src]!</span>")
update_icon()
+2 -2
View File
@@ -2,7 +2,7 @@
# Basically, ckey goes first. Rank goes after the "-" #
# Case is not important for ckey. #
# Case IS important for the rank. However punctuation/spaces are not #
# Ranks can be anything defined in admin_ranks.txt ~Carn #
# Ranks can be anything defined in admin_ranks.json ~Carn #
######################################################################
# not_a_user - Admin
# not_a_user - Head Admin/Dev
+30
View File
@@ -0,0 +1,30 @@
[
{
"ckey": "arrow768",
"character_name": "Jane Doe",
"item_path": "/obj/item/toy/plushie",
"item_data": {"name":"ugly plush toy","desc":"It's truly hideous."},
"req_titles": ["Assistant", "Security Officer"]
},
{
"ckey": "arrow768",
"character_name": "Jane Doe",
"item_path": "/obj/item/device/kit/paint",
"item_data": {"name":"APLU customisation kit","desc":"It's truly hideous."},
"additional_data": "ripley, firefighter"
},
{
"ckey": "arrow768",
"character_name": "Jane Doe",
"item_path": "/obj/item/device/kit/suit",
"item_data": {"name":"salvage suit customisation kit","desc":"A customisation kit with all the parts needed to convert a suit."}
},
{
"ckey": "arrow768",
"character_name": "John Doe",
"item_path": "/obj/item/gun/energy/lawgiver",
"item_name":"Executioner",
"item_desc":"When you really need to motivate your crew."
}
]
-41
View File
@@ -1,41 +0,0 @@
##
# Custom items go here. They are modifications of existing paths; look at the example for details.
# Item will spawn if the target has one of the req_titles and if their on-spawn ID has the required access level.
# req_access is going to be a shit to maintain since the config file can't grab constants and has to use integers, use it minimally.
# Separate titles with a single comma and a space (', ') or they'll bork.
#
# EX:
# {
# ckey: zuhayr
# character_name: Jane Doe
# item_path: /obj/item/toy/plushie
# item_name: ugly plush toy
# item_icon: flagmask
# item_desc: It's truly hideous.
# req_titles: Assistant, Security Officer
# req_access: 1
# }
#
# {
# ckey: zuhayr
# character_name: Jane Doe
# item_path: /obj/item/device/kit/paint
# item_name: APLU customisation kit
# item_desc: A customisation kit with all the parts needed to turn an APLU into a "Titan's Fist" model.
# kit_name: APLU "Titan's Fist"
# kit_desc: Looks like an overworked, under-maintained Ripley with some horrific damage.
# kit_icon: titan
# additional_data: ripley, firefighter
# }
#
# {
# ckey: zuhayr
# character_name: Jane Doe
# item_path: /obj/item/device/kit/suit
# item_name: salvage suit customisation kit
# item_desc: A customisation kit with all the parts needed to convert a suit.
# kit_name: salvage
# kit_desc: An orange voidsuit. Reinforced!
# kit_icon: salvage
# }
##
+113
View File
@@ -35,10 +35,123 @@
-->
<div class="commit sansserif">
<h2 class="date">02 January 2021</h2>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added the ability for exosuits to respond to verbal commands.</li>
<li class="rscadd">The guide for the verbal commands will be on the Guide to Robotics wiki page.</li>
<li class="tweak">Standard disruptors now have enough charge capacity for 8 shots in general, lethal shots no longer drain more.</li>
<li class="tweak">Lethal disruptor shots now do 20 burn damage, down from 30.</li>
<li class="tweak">Lethal disruptor shots no longer pass through windows and grilles.</li>
<li class="tweak">Stun disruptor shots now do 25 agony damage, down from 45.</li>
</ul>
<h2 class="date">01 January 2021</h2>
<h3 class="author">Ferner updated:</h3>
<ul class="changes bgimages16">
<li class="maptweak">Removed Christmas.</li>
<li class="maptweak">The outer chapel windows can now be tinted.</li>
</ul>
<h3 class="author">Ferner, sekritsanter updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added a Idris windbreaker jacket to the faction loadout selection.</li>
</ul>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added a paralysis indicator to the HUD.</li>
<li class="tweak">Being paralyzed will no longer make you asleep, instead, you will be awake with a crit overlay, and you will only be able to whisper.</li>
<li class="tweak">Pain doesn&#x27;t slow you down as much anymore. It&#x27;s still pretty substantial, though.</li>
<li class="tweak">You now lose pain damage much faster.</li>
<li class="rscadd">A message now plays if you drop your items because of how much pain damage you have.</li>
</ul>
<h3 class="author">Sparky_hotdog updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Fixes the medical gumball jar not loading its underlay on roundstart.</li>
<li class="bugfix">Fixes Fisanduhian Coffee missing a sprite.</li>
</ul>
<h2 class="date">31 December 2020</h2>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Posibrains and MMI now get Tau Ceti Basic and EAL on spawn, as well as a TTS accent.</li>
<li class="rscadd">Cable layer code has been updated to be a little bit more sane. It will no longer tear up floor tiles to turn it into plating.</li>
<li class="rscadd">Cable layers can now use different colours of cable. Use a multitool on it to change the colour.</li>
<li class="rscadd">The cable layer now plays a sound when it runs out of cable.</li>
</ul>
<h3 class="author">Sparky_Hotdog updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Security now recieves maintainance access during yellow, blue, red and delta alerts.</li>
</ul>
<h2 class="date">28 December 2020</h2>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Mining ore processors and Mining Vendors now find IDs wirelessly, allowing mining stationbounds to redeem points as well. Mining drones cannot utilize this system.</li>
<li class="rscadd">Hitting reply on a message to the NTIRC client will now reply to that channel directly, instead of requiring it to be the active one when doing so.</li>
<li class="rscadd">Skrell can now store a single small item in their headtails via an ability in the top left corner of their screen. It can be emptied via the strip menu, same as pockets.</li>
<li class="rscadd">Buffed the help intent shuffle. Pulled objects will no longer be dropped.</li>
<li class="rscadd">When doing the shuffle and pulling a dense object, shuffling through someone will move both you and the object past your target.</li>
<li class="rscadd">When doing the shuffle and you&#x27;re pulling a non-dense object, you will shuffle as normal, but your object will move to beneath the target&#x27;s feet, allowing movement.</li>
<li class="rscadd">Shuffling past someone while grabbing someone will move the grabbed person / peoples to your tile after the shuffle completes, maintaining your grip.</li>
<li class="tweak">When both you and your shuffle target are pulling dense objects, the help intent shuffle will no longer occur.</li>
</ul>
<h3 class="author">MoondancerPony updated:</h3>
<ul class="changes bgimages16">
<li class="refactor">Chemmaster UI icons are now sent via spritesheets.</li>
</ul>
<h3 class="author">Skull132 updated:</h3>
<ul class="changes bgimages16">
<li class="bugfix">Fixes fringe colour being saved in an invalid format.</li>
</ul>
<h3 class="author">Wowzewow (Wezzy) updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Adds secondary hair colors for hair, and a gradient - sort of like highlights.</li>
</ul>
<h2 class="date">27 December 2020</h2>
<h3 class="author">Alberyk, Kyres1 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added some items related to the end of the King of World Arc and the creation of the SCC; zeng-hu body analyzer, hephaestus exosuit dock, and idris service backpack.</li>
</ul>
<h2 class="date">26 December 2020</h2>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Added LIGHTSTEP to the syndi no-slip shoes. This prevents you from activating mouse traps and landmines while wearing them, as well as letting you dodge past soap, banana peels, and oil spills.</li>
<li class="tweak">Emergency energy shields have had their health reduced to 75, down from 200.</li>
<li class="rscadd">Attacking emergency energy shields now play an animation. The less HP they have, the more transparent they become.</li>
<li class="rscadd">You can now use a multitool on engineering tape to mark it as an emergency shield target. An emergency shield generator will deploy shields over it.</li>
<li class="rscadd">Added Coagzolug, a blood coagulation chemical created by mixing tricordrazine and cough syrup. It will slow bleeding, even arterial, while in the bloodstream.</li>
<li class="rscadd">Added Coagzolug autoinjectors to mining brute packs and the EMT stabilization kit locker.</li>
</ul>
<h3 class="author">Karolis2011 updated:</h3>
<ul class="changes bgimages16">
<li class="tweak">Vue numeric input no longer has repeated &#x27;-&#x27; and &#x27;+&#x27; symbols for larger adjustment buttons.</li>
</ul>
<h2 class="date">25 December 2020</h2>
<h3 class="author">Arrow768 updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Unique character names are now enforced per player.</li>
<li class="refactor">Reworks the custom item system to be database-based.</li>
<li class="rscadd">The reason why a custom item could not be spawned is now displayed in the chat.</li>
</ul>
<h3 class="author">Ferner updated:</h3>
<ul class="changes bgimages16">
<li class="maptweak">Removed a carp spawnpoint by the surface access stairwell.</li>
</ul>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
<li class="rscadd">Increased the amount of funds departments start with to 10k, up from 5k, except for the Cargo account.</li>
<li class="tweak">The vendor account now starts with 0 credits.</li>
<li class="rscadd">You can now pay for cargo orders with a charge card. To do so, do not have an ID card in the computer, have a charge card in your active hand when you press the pay button.</li>
</ul>
<h2 class="date">24 December 2020</h2>
<h3 class="author">Alberyk updated:</h3>
<ul class="changes bgimages16">
<li class="rscdel">Removed antag drafting. People that voted for the round won&#x27;t be selected for antag if they don&#x27;t have their options enabled.</li>
<li class="tweak">Reduced the meat hook&#x27;s damage.</li>
</ul>
<h3 class="author">Geeves updated:</h3>
<ul class="changes bgimages16">
+105
View File
@@ -17663,5 +17663,110 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Alberyk:
- rscdel: Removed antag drafting. People that voted for the round won&#x27;t be
selected for antag if they don&#x27;t have their options enabled.
- tweak: Reduced the meat hook&#x27;s damage.
Geeves:
- rscadd: Added an extension to skrell eyes for Axiori under the body markings menu.
2020-12-25:
Arrow768:
- rscadd: Unique character names are now enforced per player.
- refactor: Reworks the custom item system to be database-based.
- rscadd: The reason why a custom item could not be spawned is now displayed in
the chat.
Ferner:
- maptweak: Removed a carp spawnpoint by the surface access stairwell.
Geeves:
- rscadd: Increased the amount of funds departments start with to 10k, up from 5k,
except for the Cargo account.
- tweak: The vendor account now starts with 0 credits.
- rscadd: You can now pay for cargo orders with a charge card. To do so, do not
have an ID card in the computer, have a charge card in your active hand when
you press the pay button.
2020-12-26:
Geeves:
- rscadd: Added LIGHTSTEP to the syndi no-slip shoes. This prevents you from activating
mouse traps and landmines while wearing them, as well as letting you dodge past
soap, banana peels, and oil spills.
- tweak: Emergency energy shields have had their health reduced to 75, down from
200.
- rscadd: Attacking emergency energy shields now play an animation. The less HP
they have, the more transparent they become.
- rscadd: You can now use a multitool on engineering tape to mark it as an emergency
shield target. An emergency shield generator will deploy shields over it.
- rscadd: Added Coagzolug, a blood coagulation chemical created by mixing tricordrazine
and cough syrup. It will slow bleeding, even arterial, while in the bloodstream.
- rscadd: Added Coagzolug autoinjectors to mining brute packs and the EMT stabilization
kit locker.
Karolis2011:
- tweak: Vue numeric input no longer has repeated &#x27;-&#x27; and &#x27;+&#x27;
symbols for larger adjustment buttons.
2020-12-27:
Alberyk, Kyres1:
- rscadd: Added some items related to the end of the King of World Arc and the creation
of the SCC; zeng-hu body analyzer, hephaestus exosuit dock, and idris service
backpack.
2020-12-28:
Geeves:
- rscadd: Mining ore processors and Mining Vendors now find IDs wirelessly, allowing
mining stationbounds to redeem points as well. Mining drones cannot utilize
this system.
- rscadd: Hitting reply on a message to the NTIRC client will now reply to that
channel directly, instead of requiring it to be the active one when doing so.
- rscadd: Skrell can now store a single small item in their headtails via an ability
in the top left corner of their screen. It can be emptied via the strip menu,
same as pockets.
- rscadd: Buffed the help intent shuffle. Pulled objects will no longer be dropped.
- rscadd: When doing the shuffle and pulling a dense object, shuffling through someone
will move both you and the object past your target.
- rscadd: When doing the shuffle and you&#x27;re pulling a non-dense object, you
will shuffle as normal, but your object will move to beneath the target&#x27;s
feet, allowing movement.
- rscadd: Shuffling past someone while grabbing someone will move the grabbed person
/ peoples to your tile after the shuffle completes, maintaining your grip.
- tweak: When both you and your shuffle target are pulling dense objects, the help
intent shuffle will no longer occur.
MoondancerPony:
- refactor: Chemmaster UI icons are now sent via spritesheets.
Skull132:
- bugfix: Fixes fringe colour being saved in an invalid format.
Wowzewow (Wezzy):
- rscadd: Adds secondary hair colors for hair, and a gradient - sort of like highlights.
2020-12-31:
Geeves:
- rscadd: Posibrains and MMI now get Tau Ceti Basic and EAL on spawn, as well as
a TTS accent.
- rscadd: Cable layer code has been updated to be a little bit more sane. It will
no longer tear up floor tiles to turn it into plating.
- rscadd: Cable layers can now use different colours of cable. Use a multitool on
it to change the colour.
- rscadd: The cable layer now plays a sound when it runs out of cable.
Sparky_Hotdog:
- tweak: Security now recieves maintainance access during yellow, blue, red and
delta alerts.
2021-01-01:
Ferner:
- maptweak: Removed Christmas.
- maptweak: The outer chapel windows can now be tinted.
Ferner, sekritsanter:
- rscadd: Added a Idris windbreaker jacket to the faction loadout selection.
Geeves:
- rscadd: Added a paralysis indicator to the HUD.
- tweak: Being paralyzed will no longer make you asleep, instead, you will be awake
with a crit overlay, and you will only be able to whisper.
- tweak: Pain doesn&#x27;t slow you down as much anymore. It&#x27;s still pretty
substantial, though.
- tweak: You now lose pain damage much faster.
- rscadd: A message now plays if you drop your items because of how much pain damage
you have.
Sparky_hotdog:
- bugfix: Fixes the medical gumball jar not loading its underlay on roundstart.
- bugfix: Fixes Fisanduhian Coffee missing a sprite.
2021-01-02:
Geeves:
- rscadd: Added the ability for exosuits to respond to verbal commands.
- rscadd: The guide for the verbal commands will be on the Guide to Robotics wiki
page.
- tweak: Standard disruptors now have enough charge capacity for 8 shots in general,
lethal shots no longer drain more.
- tweak: Lethal disruptor shots now do 20 burn damage, down from 30.
- tweak: Lethal disruptor shots no longer pass through windows and grilles.
- tweak: Stun disruptor shots now do 25 agony damage, down from 45.
+3
View File
@@ -0,0 +1,3 @@
author: Skull132
changes: []
delte-after: true
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

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