fixes a few bugs, rewrites station time system (#7402)

see tin

fixes tgs4 scripts for linux too and updates them
This commit is contained in:
silicons
2025-11-21 12:20:07 -05:00
committed by GitHub
parent e71ea59172
commit 3492998c87
34 changed files with 539 additions and 532 deletions

View File

@@ -648,6 +648,7 @@
#include "code\controllers\subsystem\tgui.dm"
#include "code\controllers\subsystem\throwing.dm"
#include "code\controllers\subsystem\ticker.dm"
#include "code\controllers\subsystem\time_keep.dm"
#include "code\controllers\subsystem\time_track.dm"
#include "code\controllers\subsystem\timer.dm"
#include "code\controllers\subsystem\titlescreen.dm"
@@ -1954,6 +1955,7 @@
#include "code\game\objects\items\storage\belt\security.dm"
#include "code\game\objects\items\storage\medical\firstaid.dm"
#include "code\game\objects\items\storage\medical\hypokit.dm"
#include "code\game\objects\items\storage\medical\pill_bottle.dm"
#include "code\game\objects\items\storage\misc\survival.dm"
#include "code\game\objects\items\storage\misc_legacy\bible.dm"
#include "code\game\objects\items\storage\misc_legacy\fancy.dm"

View File

@@ -29,11 +29,6 @@
#define PERCENT(val) (round((val)*100, 0.1))
#define CLAMP01(x) (clamp(x, 0, 1))
//time of day but automatically adjusts to the server going into the next day within the same round.
//for when you need a reliable time number that doesn't depend on byond time.
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
#define SIGN(x) ( (x)!=0 ? (x) / abs(x) : 0 )
/// ceil()

View File

@@ -265,9 +265,6 @@ var/list/economy_station_departments = list(
#define TSC_XION "Xion"
#define TSC_ZH "Zeng-Hu"
///The number of deciseconds in a day
#define MIDNIGHT_ROLLOVER 864000
/// Maximum effective value of client.view (According to DM references)
#define MAX_CLIENT_VIEW 34

View File

@@ -48,3 +48,21 @@
#define CHATSPAM_THROTTLE_DEFAULT (!(world.time % 5))
/// ditto
#define CHATSPAM_THROTTLE(every) (!(world.time % every))
//* REALTIMEOFDAY, because we don't have chrono::steady_clock *//
//* Automatically adjusts to the server rolling over midnight *//
//* so this is monotonically increasing wall-time. *//
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
#define MIDNIGHT_ROLLOVER 864000
#define MIDNIGHT_ROLLOVER_CHECK (global.midnight_rollover_last_timeofday != world.timeofday ? update_midnight_rollover() : global.midnight_rollovers)
#define MIDNIGHT_ROLLOVER_CHECK_STANDALONE if(global.midnight_rollover_last_timeofday != world.timeofday) update_midnight_rollover()
GLOBAL_REAL_VAR(midnight_rollovers) = 0
GLOBAL_REAL_VAR(midnight_rollover_last_timeofday) = world.timeofday
/proc/update_midnight_rollover()
if (world.timeofday < global.midnight_rollover_last_timeofday) //TIME IS GOING BACKWARDS!
++global.midnight_rollovers
midnight_rollover_last_timeofday = world.timeofday
return global.midnight_rollovers

View File

@@ -21,30 +21,17 @@ GLOBAL_VAR_INIT(startup_day, text2num(time2text(world.time, "DD")))
return wtime + (time_offset + wusage) * world.tick_lag
GLOBAL_VAR_INIT(roundstart_hour, pick(2,7,12,17))
/var/station_date = ""
/var/next_station_date_change = 1 DAY
// todo: better subsystem based way of tracking this, this is fucky.
#define duration2stationtime(time) time2text(station_time_in_ds + time, "hh:mm")
#define worldtime2stationtime(time) time2text((GLOB.roundstart_hour HOURS) - SSticker.round_start_time + time, "hh:mm")
#define worldtime2stationtime(time) SStime_keep.render_galactic_time_short(time)
#define round_duration_in_ds (SSticker.round_start_time ? world.time - SSticker.round_start_time : 0)
#define station_time_in_ds (GLOB.roundstart_hour HOURS + round_duration_in_ds)
#define station_time_in_ds (world.time + SStime_keep.get_galactic_time_offset())
// TODO: remove
/proc/stationtime2text()
return time2text(station_time_in_ds, "hh:mm", 0)
return SStime_keep.render_galactic_time()
// TODO: remove
/proc/stationdate2text()
var/update_time = FALSE
if(station_time_in_ds > next_station_date_change)
next_station_date_change += 1 DAY
update_time = TRUE
if(!station_date || update_time)
var/extra_days = round(station_time_in_ds / (1 DAY)) DAYS
var/timeofday = world.timeofday + extra_days
station_date = num2text((text2num(time2text(timeofday, "YYYY"))+544)) + "-" + time2text(timeofday, "MM-DD")
return station_date
return SStime_keep.render_galactic_date()
/// ISO 8601
/proc/time_stamp()
@@ -52,30 +39,11 @@ GLOBAL_VAR_INIT(roundstart_hour, pick(2,7,12,17))
var/time_portion = time2text(world.timeofday, "hh:mm:ss")
return "[date_portion]T[time_portion]"
/proc/get_timezone_offset()
var/midnight_gmt_here = text2num(time2text(0,"hh")) * 36000
if(midnight_gmt_here > 12 HOURS)
return 24 HOURS - midnight_gmt_here
else
return midnight_gmt_here
/proc/gameTimestamp(format = "hh:mm:ss", wtime=null)
if(!wtime)
wtime = world.time
return time2text(wtime, format, 0)
/**
* This is used for displaying the "station time" equivelent of a world.time value
* Calling it with no args will give you the current time, but you can specify a world.time-based value as an argument.
* - You can use this, for example, to do "This will expire at [station_time_at(world.time + 500)]" to display a "station time" expiration date
* which is much more useful for a player).
*/
/proc/station_time(time=world.time)
return ((((time - SSticker.round_start_time)) + GLOB.gametime_offset) % 864000)
/proc/station_time_timestamp(format = "hh:mm:ss", time=world.time)
return time2text(station_time(time), format, 0)
/**
* Returns 1 if it is the selected month and day.
*/
@@ -95,6 +63,7 @@ GLOBAL_VAR_INIT(roundstart_hour, pick(2,7,12,17))
/var/next_duration_update = 0
/var/last_round_duration = 0
// TODO: this is buggy, should use RTOD / walltime
/proc/roundduration2text()
if(!SSticker.round_start_time)
return "00:00"
@@ -115,14 +84,6 @@ GLOBAL_VAR_INIT(roundstart_hour, pick(2,7,12,17))
next_duration_update = world.time + 1 MINUTES
return last_round_duration
/var/midnight_rollovers = 0
/var/rollovercheck_last_timeofday = 0
/proc/update_midnight_rollover()
if (world.timeofday < rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS!
return midnight_rollovers++
return midnight_rollovers
/proc/weekdayofthemonth()
/// Get the current day.
var/DD = text2num(time2text(world.timeofday, "DD"))

View File

@@ -1,5 +1,7 @@
/proc/load_configuration()
/proc/create_legacy_configuration()
config_legacy = new /datum/configuration_legacy()
/proc/load_legacy_configuration()
config_legacy.load("config/legacy/config.txt")
config_legacy.load("config/legacy/game_options.txt","game_options")
@@ -113,13 +115,13 @@
var/expected_round_length = 3 * 60 * 60 * 10 // 3 hours
// If the first delay has a custom start time
// No custom time, no custom time, between 80 to 100 minutes respectively.
var/list/event_first_run = list(EVENT_LEVEL_MUNDANE = null, EVENT_LEVEL_MODERATE = null, EVENT_LEVEL_MAJOR = list("lower" = 48000, "upper" = 60000))
var/list/event_first_run = list(null, null, list("lower" = 48000, "upper" = 60000))
// The lowest delay until next event
// 10, 30, 50 minutes respectively
var/list/event_delay_lower = list(EVENT_LEVEL_MUNDANE = 6000, EVENT_LEVEL_MODERATE = 18000, EVENT_LEVEL_MAJOR = 30000)
var/list/event_delay_lower = list(6000, 18000, 30000)
// The upper delay until next event
// 15, 45, 70 minutes respectively
var/list/event_delay_upper = list(EVENT_LEVEL_MUNDANE = 9000, EVENT_LEVEL_MODERATE = 27000, EVENT_LEVEL_MAJOR = 42000)
var/list/event_delay_upper = list(9000, 27000, 42000)
var/aliens_allowed = 0
var/ninjas_allowed = 0

View File

@@ -115,14 +115,12 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
// which results in all procs called by the MC inheriting that usr.
usr = null
//# 1. load configs
if(!config_legacy)
load_configuration()
//# 1. create configs
create_legacy_configuration()
if(!config)
config = new
if(!Configuration)
Configuration = new
Configuration.Initialize()
//# 2. set up random seed
if(!random_seed)
@@ -374,17 +372,17 @@ GLOBAL_REAL(Master, /datum/controller/master) = new
switch(initialize_result)
if(SS_INIT_FAILURE)
message_prefix = "Failed to initialize [subsystem.name] subsystem after"
message_prefix = "Failed to initialize [subsystem.name] ([subsystem.type]) subsystem after"
tell_everyone = TRUE
chat_warning = TRUE
// Since this is an explicit failure, shut its ticking off. We also will not set its initialized variable.
subsystem.subsystem_flags |= SS_NO_FIRE
if(SS_INIT_NONE)
message_prefix = "Initialized [subsystem.name] subsystem with errors within"
message_prefix = "Initialized [subsystem.name] ([subsystem.type]) subsystem with errors within"
tell_everyone = TRUE
chat_warning = TRUE
subsystem.initialized = TRUE
warning("[subsystem.name] subsystem does not implement Initialize() or it returns ..(). If the former is true, the SS_NO_INIT flag should be set for this subsystem.")
warning("[subsystem.name] ([subsystem.type]) subsystem does not implement Initialize() or it returns ..(). If the former is true, the SS_NO_INIT flag should be set for this subsystem.")
if(SS_INIT_SUCCESS)
message_prefix = "Initialized [subsystem.name] subsystem within"
tell_everyone = TRUE

View File

@@ -26,9 +26,9 @@ SUBSYSTEM_DEF(events)
SSticker.OnRoundstart(CALLBACK(src, PROC_REF(HolidayRoundstart)))
allEvents = typesof(/datum/event) - /datum/event
event_containers = list(
EVENT_LEVEL_MUNDANE = new/datum/event_container/mundane,
EVENT_LEVEL_MODERATE = new/datum/event_container/moderate,
EVENT_LEVEL_MAJOR = new/datum/event_container/major
new/datum/event_container/mundane,
new/datum/event_container/moderate,
new/datum/event_container/major
)
// unfortunately, character setup server startup hooks fire before /Initialize so :/
// SScharactersetup but not shit when :)

View File

@@ -4,7 +4,7 @@
SUBSYSTEM_DEF(overmap_physics)
name = "Overmap Physics"
priority = FIRE_PRIORITY_OVERMAP_PHYSICS
subsystem_flags = NONE
subsystem_flags = SS_NO_INIT
wait = 0.25
/// processing

View File

@@ -307,6 +307,8 @@ SUBSYSTEM_DEF(ticker)
log_world("Game start took [(world.timeofday - init_start)/10]s")
round_start_time = world.time
SStime_keep.cached_round_start_time = world.time
SStime_keep.cached_round_start_rtod = REALTIMEOFDAY
INVOKE_ASYNC(SSdbcore, TYPE_PROC_REF(/datum/controller/subsystem/dbcore, SetRoundStart))
// TODO Dear God Fix This. Fix all of this. Not just this line, this entire proc. This entire file!

View File

@@ -0,0 +1,99 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2025 Citadel Station Developers *//
/**
* # SStime_keep
*
* Centralized time-keeping subsystem for world & in-game time.
*
* * Linux broke our clock, instead of figuring out why
* I'm going to fix this by doing what I do best:
* needlessly refactoring code.
* * Galactic date is the IRL date plus a given number of years.
* * Galactic time is a random hour, usually, plus time from server boot.
* * Galactic time is affected by time dilation, unlike timeofday/realtimeofday.
*/
SUBSYSTEM_DEF(time_keep)
name = "Time Keeping"
subsystem_flags = SS_NO_FIRE | SS_NO_INIT
var/galactic_year_offset = 544
var/static/galactic_time_offset = null
var/list/possible_roundstart_offsets = list(
2 HOURS,
7 HOURS,
12 HOURS,
17 HOURS,
)
var/tmp/cached_galactic_date
var/tmp/cached_galactic_date_rollovers
/// approximate REALTIMEOFDAY we booted at
/// * Set by PreInit, which is very close, but not precisely, at server boot.
var/static/cached_server_boot_rtod
/// world.time we started the round at
/// * Null until round starts.
var/static/cached_round_start_time
/// REALTIMEOFDAY we started the round at
/// * Null until round starts.
var/static/cached_round_start_rtod
/datum/controller/subsystem/time_keep/PreInit(recovering)
if(isnull(galactic_time_offset))
galactic_time_offset = pick(possible_roundstart_offsets)
cached_server_boot_rtod = REALTIMEOFDAY
return ..()
/**
* @return as YYYY-MM-DD
*/
/datum/controller/subsystem/time_keep/proc/render_galactic_date(manual_offset)
// Note: midnight rollovers have to be subtracted because we manually track midnight rollovers
// in date rendering code.
MIDNIGHT_ROLLOVER_CHECK_STANDALONE
if(manual_offset)
var/use_time = galactic_time_offset + manual_offset - (global.midnight_rollovers DAYS)
return "[num2text(time2text(use_time, "YYYY")) + galactic_year_offset]-[time2text(use_time, "MM-DD", 0)]"
else
var/use_time = galactic_time_offset + world.time - (global.midnight_rollovers DAYS)
var/rollovers = floor(use_time / (1 DAY))
if(rollovers != cached_galactic_date_rollovers)
cached_galactic_date = "[text2num(time2text(use_time, "YYYY")) + galactic_year_offset]-[time2text(use_time, "MM-DD", 0)]"
return cached_galactic_date
/**
* Returns time from start of current round. Default offset is current time.
* @return as hh:mm:ss
*/
/datum/controller/subsystem/time_keep/proc/render_galactic_time(manual_offset)
if(manual_offset)
// TODO: slow path that doesn't cache
return time2text(galactic_time_offset + manual_offset, "hh:mm:ss", 0)
else
// TODO: cache fast path
return time2text(galactic_time_offset + world.time, "hh:mm:ss", 0)
/**
* Returns time from start of current round. Default offset is current time.
* @return as hh:mm
*/
/datum/controller/subsystem/time_keep/proc/render_galactic_time_short(manual_offset)
if(manual_offset)
// TODO: slow path that doesn't cache
return time2text(galactic_time_offset + manual_offset, "hh:mm", 0)
else
// TODO: cache fast path
return time2text(galactic_time_offset + world.time, "hh:mm", 0)
/**
* * **warning**: this proc return should never be used to render date. BYOND is weird.
* @return deciseconds into the current day we started the server at.
* Value will only make sense when time2text'd to `hh`, `mm`, `ss` format.
* Date formats will fail miserably due to us using `world.time` instead of `world.realtime` for floating
* point accuracy reasons. Make sure you remember to set timezone to `0` in `time2text` if using this
* for that.
*/
/datum/controller/subsystem/time_keep/proc/get_galactic_time_offset()
return galactic_time_offset

View File

@@ -1,3 +1,6 @@
/**
* Time tracking subsystem responsible for tracking server lag / time dilation.
*/
SUBSYSTEM_DEF(time_track)
name = "Time Tracking"
wait = 1 SECONDS

View File

@@ -521,30 +521,30 @@ SUBSYSTEM_DEF(timer)
#if defined(TIMER_DEBUG)
// Generate debug-friendly list for timer, more complex but also more expensive
timer_info = list(
1 = id,
2 = timeToRun,
3 = wait,
4 = timer_flags,
5 = callBack, /* Safe to hold this directly because it's never del'd */
6 = "[callBack.object]",
7 = REF(callBack.object),
8 = getcallingtype(),
9 = callBack.delegate,
10 = callBack.arguments ? callBack.arguments.Copy() : null,
11 = "[source]"
id,
timeToRun,
wait,
timer_flags,
callBack, /* Safe to hold this directly because it's never del'd */
"[callBack.object]",
REF(callBack.object),
getcallingtype(),
callBack.delegate,
callBack.arguments ? callBack.arguments.Copy() : null,
"[source]"
)
#else
// Generate a debuggable list for the timer, simpler but wayyyy cheaper, string generation (and ref/copy memes) is a bitch and this saves a LOT of time
timer_info = list(
1 = id,
2 = timeToRun,
3 = wait,
4 = timer_flags,
5 = callBack, /* Safe to hold this directly because it's never del'd */
6 = "[callBack.object]",
7 = getcallingtype(),
8 = callBack.delegate,
9 = "[source]"
id,
timeToRun,
wait,
timer_flags,
callBack, /* Safe to hold this directly because it's never del'd */
"[callBack.object]",
getcallingtype(),
callBack.delegate,
"[source]"
)
#endif

View File

@@ -228,11 +228,3 @@
*/
/datum/prototype/design/proc/lathe_print(atom/where, amount, list/material_parts, list/ingredient_parts, list/reagent_parts, obj/machinery/lathe/fabricator, cost_multiplier = 1)
return print(where, amount, material_parts, ingredient_parts, reagent_parts, cost_multiplier)
//? legacy below
/**
* for legacy lathes
*/
/datum/prototype/design/proc/legacy_print(atom/where, fabricator)
return print(where, 1)

View File

@@ -87,10 +87,28 @@
* decodes damage type to what it should actually do
*
* * this is for hybrid / semantic damage types like bio-acid and searing damage to work
* * for the love of god make sure you are not infinite looping here; never use a compound damage type in this.
* * this gets a direct reference to args; you can just modify it and pass it back.
*
* TODO: can we datumize damage types already?
*
* @return TRUE to handle the damage type.
*/
/atom/proc/inflict_damage_type_special(list/shieldcall_args)
switch(shieldcall_args[SHIELDCALL_ARG_DAMAGE_TYPE])
if(DAMAGE_TYPE_BIOACID)
// hand it back
shieldcall_args[SHIELDCALL_ARG_DAMAGE_TYPE] = DAMAGE_TYPE_BURN
return FALSE
if(DAMAGE_TYPE_SEARING)
// split to two and call
var/list/new_args = shieldcall_args.Copy()
new_args[SHIELDCALL_ARG_DAMAGE] /= 2
new_args[SHIELDCALL_ARG_DAMAGE_TYPE] = DAMAGE_TYPE_BRUTE
inflict_damage_instance(arglist(new_args))
new_args[SHIELDCALL_ARG_DAMAGE_TYPE] = DAMAGE_TYPE_BURN
inflict_damage_instance(arglist(new_args))
return TRUE
return FALSE
//* Damage Processing API *//

View File

@@ -141,7 +141,8 @@
set_weight_class(VALUE_OR_DEFAULT(active_weight_class, initial(w_class)))
set_weight_volume(VALUE_OR_DEFAULT(active_weight_volume, initial(weight_volume)))
attack_verb = active_attack_verb
if(active_attack_verb || inactive_attack_verb)
attack_verb = active_attack_verb
if(!silent && activation_sound)
playsound(src, activation_sound, toggle_sound_volume, TRUE)
@@ -165,7 +166,8 @@
set_weight_class(VALUE_OR_DEFAULT(inactive_weight_class, initial(w_class)))
set_weight_volume(VALUE_OR_DEFAULT(inactive_weight_volume, initial(weight_volume)))
attack_verb = inactive_attack_verb
if(active_attack_verb || inactive_attack_verb)
attack_verb = inactive_attack_verb
if(!silent && (activation_sound || deactivation_sound))
playsound(src, deactivation_sound || activation_sound, toggle_sound_volume, TRUE)

View File

@@ -448,14 +448,17 @@
drop_sound = 'sound/items/drop/matchbox.ogg'
pickup_sound = 'sound/items/pickup/matchbox.ogg'
/obj/item/storage/box/matches/attackby(obj/item/flame/match/W as obj, mob/user as mob)
if(istype(W) && !W.lit && !W.burnt)
W.lit = 1
W.damage_type = "burn"
W.icon_state = "match_lit"
START_PROCESSING(SSobj, W)
W.update_icon()
return
/obj/item/storage/box/matches/using_item_on(obj/item/using, datum/event_args/actor/clickchain/clickchain, clickchain_flags)
if(istype(using, /obj/item/flame/match))
var/obj/item/flame/match/W = using
if(istype(W) && !W.lit && !W.burnt)
W.lit = 1
W.damage_type = "burn"
W.icon_state = "match_lit"
START_PROCESSING(SSobj, W)
W.update_icon()
return CLICKCHAIN_DID_SOMETHING | CLICKCHAIN_DO_NOT_PROPAGATE
return ..()
/obj/item/storage/box/autoinjectors
name = "box of injectors"

View File

@@ -153,274 +153,12 @@
max_combined_volume = WEIGHT_VOLUME_SMALL * 7
starts_with = list(/obj/item/reagent_containers/hypospray/autoinjector/biginjector/bonemed = 8)
/*
* Pill Bottles
*/
/obj/item/storage/pill_bottle
name = "pill bottle"
desc = "It's an airtight container for storing medication."
icon_state = "pill_canister"
icon = 'icons/obj/medical/chemical.dmi'
drop_sound = 'sound/items/drop/pillbottle.ogg'
pickup_sound = 'sound/items/pickup/pillbottle.ogg'
item_state_slots = list(SLOT_ID_RIGHT_HAND = "contsolid", SLOT_ID_LEFT_HAND = "contsolid")
w_class = WEIGHT_CLASS_SMALL
insertion_whitelist = list(/obj/item/reagent_containers/pill,/obj/item/dice,/obj/item/paper)
allow_quick_empty = TRUE
allow_mass_gather = TRUE
sfx_insert = null
sfx_remove = null
sfx_open = null
max_combined_volume = WEIGHT_VOLUME_TINY * 14
max_single_weight_class = WEIGHT_CLASS_TINY
materials_base = list(MAT_PLASTIC = 80)
item_flags = ITEM_CAREFUL_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD | ITEM_EASY_LATHE_DECONSTRUCT
suit_storage_class = SUIT_STORAGE_CLASS_SOFTWEAR
var/label_text = ""
var/labeled = 0
var/base_name = " "
var/base_desc = " "
var/base_icon = "pill_canister"
var/bottle_color = "orange"
/obj/item/storage/pill_bottle/Initialize(mapload)
. = ..()
base_name = name
base_desc = desc
update_icon()
/obj/item/storage/pill_bottle/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/pen) || istype(W, /obj/item/flashlight/pen))
var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
if(length(tmp_label) > 50)
to_chat(user, "<span class='notice'>The label can be at most 50 characters long.</span>")
else if(length(tmp_label) > 10)
to_chat(user, "<span class='notice'>You set the label.</span>")
label_text = tmp_label
update_name_label()
else
to_chat(user, "<span class='notice'>You set the label to \"[tmp_label]\".</span>")
label_text = tmp_label
update_name_label()
labeled = 1
update_icon()
else
..()
/obj/item/storage/pill_bottle/proc/update_name_label()
if(!label_text)
name = base_name
desc = base_desc
return
else if(length(label_text) > 10)
var/short_label_text = copytext(label_text, 1, 11)
name = "[base_name] ([short_label_text]...)"
else
name = "[base_name] ([label_text])"
desc = "[base_desc] It is labeled \"[label_text]\"."
/obj/item/storage/pill_bottle/proc/choose_color()
set name = "Recolor bottle"
set category = VERB_CATEGORY_OBJECT
set desc = "Click to choose a color for the pill bottle."
var/mob/M = usr
var/list/options = list()
options["red"] = "red"
options["orange"] = "orange"
options["yellow"] = "yellow"
options["green"] = "green"
options["blue"] = "blue"
options["purple"] = "purple"
options["pink"] = "pink"
options["black"] = "black"
options["white"] = "white"
var/choice = input(M,"Choose a color!","Recolor Bottle") in options
if(src && choice && !M.stat && in_range(M,src))
bottle_color = "[choice]"
to_chat(usr,"<span class='notice'>The bottle is now [choice]. How [pick("pretty","professional","informative","creative","appropriate","bold")]!</span>")
update_icon()
return 1
/obj/item/storage/pill_bottle/update_icon()
..()
if(labeled == 1)
add_overlay("pill_canister_label")
if(base_icon == "pill_canister")
if(bottle_color == "orange")
icon_state = "[base_icon]"
else
icon_state = "[base_icon]_[bottle_color]"
/obj/item/storage/pill_bottle/Initialize(mapload)
. = ..()
if(base_icon == "pill_canister")
add_obj_verb(src, /obj/item/storage/pill_bottle/proc/choose_color)
update_icon()
/obj/item/storage/pill_bottle/antitox
name = "bottle of Dylovene pills"
desc = "Contains pills used to counter toxins."
labeled = 1
bottle_color = "green"
starts_with = list(/obj/item/reagent_containers/pill/antitox = 7)
/obj/item/storage/pill_bottle/bicaridine
name = "bottle of Bicaridine pills"
desc = "Contains pills used to stabilize the severely injured."
labeled = 1
bottle_color = "red"
starts_with = list(/obj/item/reagent_containers/pill/bicaridine = 7)
/obj/item/storage/pill_bottle/dexalin_plus
name = "bottle of Dexalin Plus pills"
desc = "Contains pills used to treat extreme cases of oxygen deprivation."
labeled = 1
bottle_color = "blue"
starts_with = list(/obj/item/reagent_containers/pill/dexalin_plus = 7)
/obj/item/storage/pill_bottle/dermaline
name = "bottle of Dermaline pills"
desc = "Contains pills used to treat burn wounds."
labeled = 1
starts_with = list(/obj/item/reagent_containers/pill/dermaline = 7)
/obj/item/storage/pill_bottle/dylovene
name = "bottle of Dylovene pills"
desc = "Contains pills used to treat toxic substances in the blood."
labeled = 1
bottle_color = "green"
starts_with = list(/obj/item/reagent_containers/pill/dylovene = 7)
/obj/item/storage/pill_bottle/inaprovaline
name = "bottle of Inaprovaline pills"
desc = "Contains pills used to stabilize patients."
labeled = 1
bottle_color = "blue"
starts_with = list(/obj/item/reagent_containers/pill/inaprovaline = 7)
/obj/item/storage/pill_bottle/kelotane
name = "bottle of kelotane pills"
desc = "Contains pills used to treat burns."
labeled = 1
starts_with = list(/obj/item/reagent_containers/pill/kelotane = 7)
/obj/item/storage/pill_bottle/spaceacillin
name = "bottle of Spaceacillin pills"
desc = "A theta-lactam antibiotic. Effective against many diseases likely to be encountered in space."
labeled = 1
bottle_color = "white"
starts_with = list(/obj/item/reagent_containers/pill/spaceacillin = 7)
/obj/item/storage/pill_bottle/tramadol
name = "bottle of Tramadol pills"
desc = "Contains pills used to relieve pain."
labeled = 1
bottle_color = "purple"
starts_with = list(/obj/item/reagent_containers/pill/tramadol = 7)
/obj/item/storage/pill_bottle/citalopram
name = "bottle of Citalopram pills"
desc = "Contains pills used to stabilize a patient's mood."
labeled = 1
starts_with = list(/obj/item/reagent_containers/pill/citalopram = 7)
/obj/item/storage/pill_bottle/carbon
name = "bottle of Carbon pills"
desc = "Contains pills used to neutralise chemicals in the stomach."
labeled = 1
bottle_color = "black"
starts_with = list(/obj/item/reagent_containers/pill/carbon = 7)
/obj/item/storage/pill_bottle/iron
name = "bottle of Iron pills"
desc = "Contains pills used to aid in blood regeneration."
labeled = 1
bottle_color = "black"
starts_with = list(/obj/item/reagent_containers/pill/iron = 7)
/obj/item/storage/firstaid/clotting
icon_state = "clottingkit"
/obj/item/storage/firstaid/bonemed
icon_state = "pinky"
/obj/item/storage/pill_bottle/adminordrazine
name = "pill bottle (Adminordrazine)"
desc = "It's magic. We don't have to explain it."
starts_with = list(/obj/item/reagent_containers/pill/adminordrazine = 21)
/obj/item/storage/pill_bottle/nutriment
name = "pill bottle (Food)"
desc = "Contains pills used to feed people."
starts_with = list(/obj/item/reagent_containers/pill/nutriment = 7, /obj/item/reagent_containers/pill/protein = 7)
/obj/item/storage/pill_bottle/rezadone
name = "pill bottle (Rezadone)"
desc = "A powder with almost magical properties, this substance can effectively treat genetic damage in humanoids, though excessive consumption has side effects."
starts_with = list(/obj/item/reagent_containers/pill/rezadone = 7)
//wrapper_color = COLOR_GREEN_GRAY
/obj/item/storage/pill_bottle/peridaxon
name = "pill bottle (Peridaxon)"
desc = "Used to encourage recovery of internal organs and nervous systems. Medicate cautiously."
starts_with = list(/obj/item/reagent_containers/pill/peridaxon = 7)
//wrapper_color = COLOR_PURPLE
/obj/item/storage/pill_bottle/carthatoline
name = "pill bottle (Carthatoline)"
desc = "Carthatoline is strong evacuant used to treat severe poisoning."
starts_with = list(/obj/item/reagent_containers/pill/carthatoline = 7)
//wrapper_color = COLOR_GREEN_GRAY
/obj/item/storage/pill_bottle/alkysine
name = "pill bottle (Alkysine)"
desc = "Alkysine is a drug used to lessen the damage to neurological tissue after a catastrophic injury. Can heal brain tissue."
starts_with = list(/obj/item/reagent_containers/pill/alkysine = 7)
//wrapper_color = COLOR_YELLOW
/obj/item/storage/pill_bottle/imidazoline
name = "pill bottle (Imidazoline)"
desc = "Heals eye damage."
starts_with = list(/obj/item/reagent_containers/pill/imidazoline = 7)
//wrapper_color = COLOR_PURPLE_GRAY
/obj/item/storage/pill_bottle/osteodaxon
name = "pill bottle (Osteodaxon)"
desc = "An experimental drug used to heal bone fractures."
starts_with = list(/obj/item/reagent_containers/pill/osteodaxon = 7)
//wrapper_color = COLOR_WHITE
/obj/item/storage/pill_bottle/myelamine
name = "pill bottle (Myelamine)"
desc = "Used to rapidly clot internal hemorrhages by increasing the effectiveness of platelets."
starts_with = list(/obj/item/reagent_containers/pill/myelamine = 7)
//wrapper_color = COLOR_PALE_PURPLE_GRAY
/obj/item/storage/pill_bottle/hyronalin
name = "pill bottle (Hyronalin)"
desc = "Hyronalin is a medicinal drug used to counter the effect of radiation poisoning."
starts_with = list(/obj/item/reagent_containers/pill/hyronalin = 7)
//wrapper_color = COLOR_TEAL
/obj/item/storage/pill_bottle/arithrazine
name = "pill bottle (Arithrazine)"
desc = "Arithrazine is an unstable medication used for the most extreme cases of radiation poisoning."
starts_with = list(/obj/item/reagent_containers/pill/arithrazine = 7)
//wrapper_color = COLOR_TEAL
/obj/item/storage/pill_bottle/corophizine
name = "pill bottle (Corophizine)"
desc = "A wide-spectrum antibiotic drug. Powerful and uncomfortable in equal doses."
starts_with = list(/obj/item/reagent_containers/pill/corophizine = 7)
//wrapper_color = COLOR_PALE_GREEN_GRAY
/obj/item/storage/pill_bottle/healing_nanites
name = "pill bottle (Healing nanites)"
desc = "Miniature medical robots that swiftly restore bodily damage."
starts_with = list(/obj/item/reagent_containers/pill/healing_nanites = 7)
/obj/item/storage/firstaid/insiderepair
name = "combat organ kit"
desc = "Contains advanced organ medical treatments."

View File

@@ -0,0 +1,261 @@
/obj/item/storage/pill_bottle
name = "pill bottle"
desc = "It's an airtight container for storing medication."
icon_state = "pill_canister"
icon = 'icons/obj/medical/chemical.dmi'
drop_sound = 'sound/items/drop/pillbottle.ogg'
pickup_sound = 'sound/items/pickup/pillbottle.ogg'
item_state_slots = list(SLOT_ID_RIGHT_HAND = "contsolid", SLOT_ID_LEFT_HAND = "contsolid")
w_class = WEIGHT_CLASS_SMALL
insertion_whitelist = list(/obj/item/reagent_containers/pill,/obj/item/dice,/obj/item/paper)
allow_quick_empty = TRUE
allow_mass_gather = TRUE
sfx_insert = null
sfx_remove = null
sfx_open = null
max_combined_volume = WEIGHT_VOLUME_TINY * 14
max_single_weight_class = WEIGHT_CLASS_TINY
materials_base = list(MAT_PLASTIC = 80)
item_flags = ITEM_CAREFUL_BLUDGEON | ITEM_ENCUMBERS_WHILE_HELD | ITEM_EASY_LATHE_DECONSTRUCT
suit_storage_class = SUIT_STORAGE_CLASS_SOFTWEAR
var/label_text = ""
var/labeled = 0
var/base_name = " "
var/base_desc = " "
var/base_icon = "pill_canister"
var/bottle_color = "orange"
/obj/item/storage/pill_bottle/Initialize(mapload)
. = ..()
base_name = name
base_desc = desc
update_icon()
/obj/item/storage/pill_bottle/using_item_on(obj/item/using, datum/event_args/actor/clickchain/clickchain, clickchain_flags)
var/obj/item/W = using
// TODO: generalize pens. or flashlights. one of the fucking two c'mon. probably flashlight on pen as it's simpler.
if(istype(W, /obj/item/pen) || istype(W, /obj/item/flashlight/pen))
var/mob/user = clickchain.initiator
var/tmp_label = sanitizeSafe(input(user, "Enter a label for [name]", "Label", label_text), MAX_NAME_LEN)
if(length(tmp_label) > 50)
to_chat(user, "<span class='notice'>The label can be at most 50 characters long.</span>")
else if(length(tmp_label) > 10)
to_chat(user, "<span class='notice'>You set the label.</span>")
label_text = tmp_label
update_name_label()
else
to_chat(user, "<span class='notice'>You set the label to \"[tmp_label]\".</span>")
label_text = tmp_label
update_name_label()
labeled = 1
update_icon()
return CLICKCHAIN_DO_NOT_PROPAGATE | CLICKCHAIN_DID_SOMETHING
return ..()
/obj/item/storage/pill_bottle/proc/update_name_label()
if(!label_text)
name = base_name
desc = base_desc
return
else if(length(label_text) > 10)
var/short_label_text = copytext(label_text, 1, 11)
name = "[base_name] ([short_label_text]...)"
else
name = "[base_name] ([label_text])"
desc = "[base_desc] It is labeled \"[label_text]\"."
/obj/item/storage/pill_bottle/proc/choose_color()
set name = "Recolor bottle"
set category = VERB_CATEGORY_OBJECT
set desc = "Click to choose a color for the pill bottle."
var/mob/M = usr
var/list/options = list()
options["red"] = "red"
options["orange"] = "orange"
options["yellow"] = "yellow"
options["green"] = "green"
options["blue"] = "blue"
options["purple"] = "purple"
options["pink"] = "pink"
options["black"] = "black"
options["white"] = "white"
var/choice = input(M,"Choose a color!","Recolor Bottle") in options
if(src && choice && !M.stat && in_range(M,src))
bottle_color = "[choice]"
to_chat(usr,"<span class='notice'>The bottle is now [choice]. How [pick("pretty","professional","informative","creative","appropriate","bold")]!</span>")
update_icon()
return 1
/obj/item/storage/pill_bottle/update_icon()
..()
if(labeled == 1)
add_overlay("pill_canister_label")
if(base_icon == "pill_canister")
if(bottle_color == "orange")
icon_state = "[base_icon]"
else
icon_state = "[base_icon]_[bottle_color]"
/obj/item/storage/pill_bottle/Initialize(mapload)
. = ..()
if(base_icon == "pill_canister")
add_obj_verb(src, /obj/item/storage/pill_bottle/proc/choose_color)
update_icon()
/obj/item/storage/pill_bottle/antitox
name = "bottle of Dylovene pills"
desc = "Contains pills used to counter toxins."
labeled = 1
bottle_color = "green"
starts_with = list(/obj/item/reagent_containers/pill/antitox = 7)
/obj/item/storage/pill_bottle/bicaridine
name = "bottle of Bicaridine pills"
desc = "Contains pills used to stabilize the severely injured."
labeled = 1
bottle_color = "red"
starts_with = list(/obj/item/reagent_containers/pill/bicaridine = 7)
/obj/item/storage/pill_bottle/dexalin_plus
name = "bottle of Dexalin Plus pills"
desc = "Contains pills used to treat extreme cases of oxygen deprivation."
labeled = 1
bottle_color = "blue"
starts_with = list(/obj/item/reagent_containers/pill/dexalin_plus = 7)
/obj/item/storage/pill_bottle/dermaline
name = "bottle of Dermaline pills"
desc = "Contains pills used to treat burn wounds."
labeled = 1
starts_with = list(/obj/item/reagent_containers/pill/dermaline = 7)
/obj/item/storage/pill_bottle/dylovene
name = "bottle of Dylovene pills"
desc = "Contains pills used to treat toxic substances in the blood."
labeled = 1
bottle_color = "green"
starts_with = list(/obj/item/reagent_containers/pill/dylovene = 7)
/obj/item/storage/pill_bottle/inaprovaline
name = "bottle of Inaprovaline pills"
desc = "Contains pills used to stabilize patients."
labeled = 1
bottle_color = "blue"
starts_with = list(/obj/item/reagent_containers/pill/inaprovaline = 7)
/obj/item/storage/pill_bottle/kelotane
name = "bottle of kelotane pills"
desc = "Contains pills used to treat burns."
labeled = 1
starts_with = list(/obj/item/reagent_containers/pill/kelotane = 7)
/obj/item/storage/pill_bottle/spaceacillin
name = "bottle of Spaceacillin pills"
desc = "A theta-lactam antibiotic. Effective against many diseases likely to be encountered in space."
labeled = 1
bottle_color = "white"
starts_with = list(/obj/item/reagent_containers/pill/spaceacillin = 7)
/obj/item/storage/pill_bottle/tramadol
name = "bottle of Tramadol pills"
desc = "Contains pills used to relieve pain."
labeled = 1
bottle_color = "purple"
starts_with = list(/obj/item/reagent_containers/pill/tramadol = 7)
/obj/item/storage/pill_bottle/citalopram
name = "bottle of Citalopram pills"
desc = "Contains pills used to stabilize a patient's mood."
labeled = 1
starts_with = list(/obj/item/reagent_containers/pill/citalopram = 7)
/obj/item/storage/pill_bottle/carbon
name = "bottle of Carbon pills"
desc = "Contains pills used to neutralise chemicals in the stomach."
labeled = 1
bottle_color = "black"
starts_with = list(/obj/item/reagent_containers/pill/carbon = 7)
/obj/item/storage/pill_bottle/iron
name = "bottle of Iron pills"
desc = "Contains pills used to aid in blood regeneration."
labeled = 1
bottle_color = "black"
starts_with = list(/obj/item/reagent_containers/pill/iron = 7)
/obj/item/storage/pill_bottle/adminordrazine
name = "pill bottle (Adminordrazine)"
desc = "It's magic. We don't have to explain it."
starts_with = list(/obj/item/reagent_containers/pill/adminordrazine = 21)
/obj/item/storage/pill_bottle/nutriment
name = "pill bottle (Food)"
desc = "Contains pills used to feed people."
starts_with = list(/obj/item/reagent_containers/pill/nutriment = 7, /obj/item/reagent_containers/pill/protein = 7)
/obj/item/storage/pill_bottle/rezadone
name = "pill bottle (Rezadone)"
desc = "A powder with almost magical properties, this substance can effectively treat genetic damage in humanoids, though excessive consumption has side effects."
starts_with = list(/obj/item/reagent_containers/pill/rezadone = 7)
//wrapper_color = COLOR_GREEN_GRAY
/obj/item/storage/pill_bottle/peridaxon
name = "pill bottle (Peridaxon)"
desc = "Used to encourage recovery of internal organs and nervous systems. Medicate cautiously."
starts_with = list(/obj/item/reagent_containers/pill/peridaxon = 7)
//wrapper_color = COLOR_PURPLE
/obj/item/storage/pill_bottle/carthatoline
name = "pill bottle (Carthatoline)"
desc = "Carthatoline is strong evacuant used to treat severe poisoning."
starts_with = list(/obj/item/reagent_containers/pill/carthatoline = 7)
//wrapper_color = COLOR_GREEN_GRAY
/obj/item/storage/pill_bottle/alkysine
name = "pill bottle (Alkysine)"
desc = "Alkysine is a drug used to lessen the damage to neurological tissue after a catastrophic injury. Can heal brain tissue."
starts_with = list(/obj/item/reagent_containers/pill/alkysine = 7)
//wrapper_color = COLOR_YELLOW
/obj/item/storage/pill_bottle/imidazoline
name = "pill bottle (Imidazoline)"
desc = "Heals eye damage."
starts_with = list(/obj/item/reagent_containers/pill/imidazoline = 7)
//wrapper_color = COLOR_PURPLE_GRAY
/obj/item/storage/pill_bottle/osteodaxon
name = "pill bottle (Osteodaxon)"
desc = "An experimental drug used to heal bone fractures."
starts_with = list(/obj/item/reagent_containers/pill/osteodaxon = 7)
//wrapper_color = COLOR_WHITE
/obj/item/storage/pill_bottle/myelamine
name = "pill bottle (Myelamine)"
desc = "Used to rapidly clot internal hemorrhages by increasing the effectiveness of platelets."
starts_with = list(/obj/item/reagent_containers/pill/myelamine = 7)
//wrapper_color = COLOR_PALE_PURPLE_GRAY
/obj/item/storage/pill_bottle/hyronalin
name = "pill bottle (Hyronalin)"
desc = "Hyronalin is a medicinal drug used to counter the effect of radiation poisoning."
starts_with = list(/obj/item/reagent_containers/pill/hyronalin = 7)
//wrapper_color = COLOR_TEAL
/obj/item/storage/pill_bottle/arithrazine
name = "pill bottle (Arithrazine)"
desc = "Arithrazine is an unstable medication used for the most extreme cases of radiation poisoning."
starts_with = list(/obj/item/reagent_containers/pill/arithrazine = 7)
//wrapper_color = COLOR_TEAL
/obj/item/storage/pill_bottle/corophizine
name = "pill bottle (Corophizine)"
desc = "A wide-spectrum antibiotic drug. Powerful and uncomfortable in equal doses."
starts_with = list(/obj/item/reagent_containers/pill/corophizine = 7)
//wrapper_color = COLOR_PALE_GREEN_GRAY
/obj/item/storage/pill_bottle/healing_nanites
name = "pill bottle (Healing nanites)"
desc = "Miniature medical robots that swiftly restore bodily damage."
starts_with = list(/obj/item/reagent_containers/pill/healing_nanites = 7)

View File

@@ -74,8 +74,11 @@ GLOBAL_LIST(topic_status_cache)
InitTgs()
// load configuration
load_legacy_configuration()
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
config.update_world_viewsize() //! Since world.view is immutable, we load it here.
Configuration.Initialize()
//SetupLogs depends on the RoundID, so lets check
//DB schema and set RoundID if we can

View File

@@ -30,7 +30,7 @@
next_turf:
for(var/turf/T in world)
for(var/dir in GLOB.cardinal)
var/list/connect_types = list(1 = 0, 2 = 0, 3 = 0)
var/list/connect_types = list(0, 0, 0)
for(var/obj/machinery/atmospherics/pipe in T)
if(dir & pipe.initialize_directions)
for(var/connect_type in pipe.connect_types)

View File

@@ -9,4 +9,4 @@
log_and_message_admins("[key_name(usr)] reloaded server configuration.")
config.admin_reload()
Configuration.admin_reload()
load_configuration() //for legacy
load_legacy_configuration() //for legacy

View File

@@ -8,7 +8,7 @@
#define ASSIGNMENT_SCIENTIST "Scientist"
#define ASSIGNMENT_SECURITY "Security"
var/global/list/severity_to_string = list(EVENT_LEVEL_MUNDANE = "Mundane", EVENT_LEVEL_MODERATE = "Moderate", EVENT_LEVEL_MAJOR = "Major")
var/global/list/severity_to_string = list("Mundane", "Moderate", "Major")
/datum/event_container
var/severity = -1

View File

@@ -9,9 +9,9 @@
var/recordtype
/datum/gm_action/manifest_malfunction/set_up()
severity = pickweight(list(EVENT_LEVEL_MUNDANE = 6,
EVENT_LEVEL_MODERATE = 2,
EVENT_LEVEL_MAJOR = 1
severity = pickweight(list(6,
2,
1
))
recordtype = pickweight(list("medical" = 10,"security" = (severity * 15)))

View File

@@ -6,11 +6,11 @@
severity = 1
/datum/gm_action/wormholes/set_up() // 1 out of 5 will be full-duration wormholes, meaning up to a minute long.
severity = pickweight(list(
3 = 5,
2 = 7,
1 = 13
))
severity = text2num(pickweight(list(
"3" = 5,
"2" = 7,
"1" = 13
)))
/datum/gm_action/wormholes/start()
..()

View File

@@ -4,5 +4,5 @@
/mob/living/carbon/get_usable_emote_require()
. = ..()
var/obj/item/organ/internal/maybe_voicebox = organs_by_name[O_VOICE]
if(maybe_voicebox?.robotic >= ORGAN_ROBOT)
if(maybe_voicebox?.robotic >= ORGAN_ASSISTED)
. |= EMOTE_REQUIRE_SYNTHETIC_SPEAKER

View File

@@ -1,4 +1,3 @@
/**
* legacy science designs
*/
@@ -6,22 +5,15 @@
abstract_type = /datum/prototype/design/science
lathe_type = LATHE_TYPE_PROTOLATHE
design_unlock = DESIGN_UNLOCK_TECHLEVEL
var/legacy_stack_amount = 1
//Make sure items don't get free power
/datum/prototype/design/science/print(atom/where, amount, list/material_parts, list/ingredient_parts, list/reagent_parts, cost_multiplier = 1)
if(isnull(amount) || amount == 1)
if(is_stack)
amount = legacy_stack_amount
else
amount = 1
var/obj/item/I = ..()
var/obj/item/cell/C = I.get_cell()
if(C)
C.charge = 0
I.update_icon()
C.update_icon()
if(istype(I, /obj/item/gun))
var/obj/item/gun/G = I
G.pin = null
return I

View File

@@ -46,9 +46,9 @@
id = "nanopaste"
category = DESIGN_CATEGORY_SYNTH
req_tech = list(TECH_MATERIAL = 4, TECH_ENGINEERING = 3)
materials_base = list(MAT_STEEL = 1500, MAT_GLASS = 750)
materials_base = list(MAT_STEEL = 150, MAT_GLASS = 75)
build_path = /obj/item/stack/nanopaste
legacy_stack_amount = 10
work = 0.5 SECONDS
/datum/prototype/design/science/biotech/plant_analyzer
desc = "A device capable of quickly scanning all relevant data about a plant."

View File

@@ -3,12 +3,6 @@
category = DESIGN_CATEGORY_POWER
lathe_type = LATHE_TYPE_PROTOLATHE | LATHE_TYPE_MECHFAB
/datum/prototype/design/science/powercell/print(atom/where)
var/obj/item/cell/C = ..()
C.charge = 0 //shouldn't produce power out of thin air.
C.update_icon()
return C
/datum/prototype/design/science/powercell/basic
id = "basic_cell"
req_tech = list(TECH_POWER = 1)

View File

@@ -10,6 +10,7 @@
* and view for robots.
*/
// TODO: ughhhhhh check the logic on this and define what this even semantically means
GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
/datum/ui_state/default/can_use_topic(src_object, mob/user)
@@ -41,11 +42,13 @@ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
if(. != UI_INTERACTIVE)
return
// Prevents the AI from using Topic on admin levels (by for example viewing through the court/thunderdome cameras)
// unless it's on the same level as the object it's interacting with.
var/turf/T = get_turf(src_object)
if(!T || !(z == T.z || (T.z in (LEGACY_MAP_DATUM).player_levels)))
return UI_CLOSE
// Make sure it's in the same map
var/turf/src_turf = get_turf(src_object)
var/turf/our_turf = get_turf(src)
var/datum/map_level/src_level = src_turf && SSmapping.ordered_levels[src_turf.z]
var/datum/map_level/our_level = our_turf && SSmapping.ordered_levels[our_turf.z]
if(!src_level || (src_level.parent_map != our_level.parent_map))
return FALSE
// If an object is in view then we can interact with it
if(src_object in view(client.view, src))

View File

@@ -0,0 +1,48 @@
#!/bin/bash
#find out what we have (+e is important for this)
set +e
has_git="$(command -v git)"
has_curl="$(command -v curl)"
has_sudo="$(command -v sudo)"
has_unzip="$(command -v unzip)"
has_cargo="$(command -v ~/.cargo/bin/cargo)"
has_ytdlp="$(command -v ~/.local/bin/yt-dlp)"
has_uv="$(command -v ~/.local/bin/uv)"
set -e
set -x
# apt packages, libssl needed by rust-g but not included in TGS barebones install
if ! ( [ -x "$has_git" ] && [ -x "$has_curl" ] && [ -x "$has_unzip" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "!!! HEY YOU THERE, READING THE TGS LOGS READ THIS!!!"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "We are about to try installing native dependencies, we will use 'sudo' if possible for this, but it may fail because the tgstation-server user doesn't have passwordless sudo."
echo "WE DO NOT RECOMMEND GRANTING PASSWORDLESS SUDO!!! Instead, install all the dependencies yourself with the following command:"
echo ".................................................................................................................................................."
echo "sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl libclang-dev g++-multilib python3 python3-pip unzip"
echo ".................................................................................................................................................."
echo "Attempting to install apt dependencies..."
if ! [ -x "$has_sudo" ]; then
dpkg --add-architecture i386
apt-get update
apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl libclang-dev g++-multilib python3 python3-pip unzip
else
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl libclang-dev g++-multilib python3 python3-pip unzip
fi
fi
# install cargo if needed
if ! [ -x "$has_cargo" ]; then
echo "Installing rust..."
curl https://sh.rustup.rs -sSf | sh -s -- -y
. ~/.profile
fi
# install yt-dlp
if ! [ -x "$has_ytdlp" ]; then
echo "Installing ytdlp..."
~/.local/bin/uv tool install yt-dlp
fi

View File

@@ -1,9 +1,6 @@
#!/bin/bash
# REPO MAINTAINERS: KEEP CHANGES TO THIS IN SYNC WITH /tools/LinuxOneShot/SetupProgram/PreCompile.sh
# No ~mso
set -e
set -x
./InstallDeps.sh
#load dep exports
#need to switch to game dir for Dockerfile weirdness
@@ -12,41 +9,7 @@ cd "$1"
. dependencies.sh
cd "$original_dir"
#find out what we have (+e is important for this)
set +e
has_git="$(command -v git)"
has_cargo="$(command -v ~/.cargo/bin/cargo)"
has_sudo="$(command -v sudo)"
has_grep="$(command -v grep)"
has_youtubedl="$(command -v youtube-dl)"
has_pip3="$(command -v pip3)"
set -e
# install cargo if needed
if ! [ -x "$has_cargo" ]; then
echo "Installing rust..."
curl https://sh.rustup.rs -sSf | sh -s -- -y
. ~/.profile
fi
# apt packages, libssl needed by rust-g but not included in TGS barebones install
if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
echo "Installing apt dependencies..."
if ! [ -x "$has_sudo" ]; then
dpkg --add-architecture i386
apt-get update
apt-get install -y git libssl-dev:i386
rm -rf /var/lib/apt/lists/*
else
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install -y git libssl-dev:i386
sudo rm -rf /var/lib/apt/lists/*
fi
fi
dpkg --add-architecture i386
apt-get update
apt-get install -y lib32z1 pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386
# update rust-g
if [ ! -d "rust-g" ]; then
echo "Cloning rust-g..."
@@ -62,25 +25,10 @@ fi
echo "Deploying rust-g..."
git checkout "$RUST_G_VERSION"
env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --release --target=i686-unknown-linux-gnu --all-features
mv target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g.so"
env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --ignore-rust-version --release --target=i686-unknown-linux-gnu --features=all
cp -f target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g.so"
cd ..
# install or update youtube-dl when not present, or if it is present with pip3,
# which we assume was used to install it
if ! [ -x "$has_youtubedl" ]; then
echo "Installing youtube-dl with pip3..."
if ! [ -x "$has_sudo" ]; then
apt-get install -y python3 python3-pip
else
sudo apt-get install -y python3 python3-pip
fi
pip3 install youtube-dl
elif [ -x "$has_pip3" ]; then
echo "Ensuring youtube-dl is up-to-date with pip3..."
pip3 install youtube-dl -U
fi
# compile tgui
echo "Compiling tgui..."
cd "$1"

View File

@@ -1,37 +0,0 @@
#!/bin/sh
has_python="$(command -v python3)"
has_git="$(command -v git)"
has_sudo="$(command -v sudo)"
has_pip="$(command -v pip3)"
set -e
if ! { [ -x "$has_python" ] && [ -x "$has_pip" ] && [ -x "$has_git" ]; }; then
echo "Installing apt dependencies..."
if ! [ -x "$has_sudo" ]; then
apt update
apt install -y python3 python3-pip git
rm -rf /var/lib/apt/lists/*
else
sudo apt update
sudo apt install -y python3 python3-pip git
sudo rm -rf /var/lib/apt/lists/*
fi
fi
echo "Installing pip dependencies..."
pip3 install PyYaml beautifulsoup4
cd $1
echo "Running changelog script..."
python3 tools/ss13_genchangelog.py html/changelogs
echo "Committing changes..."
git add html
#we now don't care about failures
set +e
git commit -m "Automatic changelog compile, [ci skip]"
exit 0

View File

@@ -1,41 +1,6 @@
#!/bin/bash
# Special file to ensure all dependencies still exist between server lanuches.
# Special file to ensure all dependencies still exist between server launches.
# Mainly for use by people who abuse docker by modifying the container's system.
set -e
set -x
#find out what we have (+e is important for this)
set +e
has_git="$(command -v git)"
has_cargo="$(command -v ~/.cargo/bin/cargo)"
has_sudo="$(command -v sudo)"
has_grep="$(command -v grep)"
has_youtubedl="$(command -v youtube-dl)"
has_pip3="$(command -v pip3)"
set -e
# install cargo if needed
if ! [ -x "$has_cargo" ]; then
echo "Installing rust..."
curl https://sh.rustup.rs -sSf | sh -s -- -y
. ~/.profile
fi
# apt packages, libssl needed by rust-g but not included in TGS barebones install
if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then
dpkg --add-architecture i386
apt-get update
apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386
fi
# install youtube-dl when not present
if ! [ -x "$has_youtubedl" ]; then
echo "Installing youtube-dl with pip3..."
if ! [ -x "$has_sudo" ]; then
apt-get install -y python3 python3-pip
else
sudo apt-get install -y python3 python3-pip
fi
pip3 install youtube-dl
fi
./InstallDeps.sh