Merge branch 'master' into placeholder
@@ -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`;
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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."))
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
@@ -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:)")
|
||||
|
||||
@@ -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]."))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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
|
||||
# }
|
||||
##
|
||||
@@ -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't slow you down as much anymore. It'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're pulling a non-dense object, you will shuffle as normal, but your object will move to beneath the target'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 '-' and '+' 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't be selected for antag if they don't have their options enabled.</li>
|
||||
<li class="tweak">Reduced the meat hook's damage.</li>
|
||||
</ul>
|
||||
<h3 class="author">Geeves updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
|
||||
@@ -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't be
|
||||
selected for antag if they don't have their options enabled.
|
||||
- tweak: Reduced the meat hook'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 '-' and '+'
|
||||
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're pulling a non-dense object, you
|
||||
will shuffle as normal, but your object will move to beneath the target'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't slow you down as much anymore. It'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.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
author: Skull132
|
||||
changes: []
|
||||
delte-after: true
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 888 B |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 2.4 KiB |