Merge branch 'master' into spooder
This commit is contained in:
@@ -451,7 +451,7 @@
|
||||
// otherwise, just reset the client mob's machine var.
|
||||
//
|
||||
/client/verb/windowclose(atomref as text)
|
||||
set hidden = 1 // hide this verb from the user's panel
|
||||
set hidden = TRUE // hide this verb from the user's panel
|
||||
set name = ".windowclose" // no autocomplete on cmd line
|
||||
|
||||
if(atomref!="null") // if passed a real atomref
|
||||
|
||||
+47
-21
@@ -1,12 +1,25 @@
|
||||
/// How long the chat message's spawn-in animation will occur for
|
||||
#define CHAT_MESSAGE_SPAWN_TIME 0.2 SECONDS
|
||||
/// How long the chat message will exist prior to any exponential decay
|
||||
#define CHAT_MESSAGE_LIFESPAN 5 SECONDS
|
||||
/// How long the chat message's end of life fading animation will occur for
|
||||
#define CHAT_MESSAGE_EOL_FADE 0.7 SECONDS
|
||||
#define CHAT_MESSAGE_EXP_DECAY 0.7 // Messages decay at pow(factor, idx in stack)
|
||||
#define CHAT_MESSAGE_HEIGHT_DECAY 0.9 // Increase message decay based on the height of the message
|
||||
#define CHAT_MESSAGE_APPROX_LHEIGHT 11 // Approximate height in pixels of an 'average' line, used for height decay
|
||||
#define CHAT_MESSAGE_WIDTH 96 // pixels
|
||||
#define CHAT_MESSAGE_MAX_LENGTH 110 // characters
|
||||
#define WXH_TO_HEIGHT(x) text2num(copytext((x), findtextEx((x), "x") + 1)) // thanks lummox
|
||||
/// Factor of how much the message index (number of messages) will account to exponential decay
|
||||
#define CHAT_MESSAGE_EXP_DECAY 0.7
|
||||
/// Factor of how much height will account to exponential decay
|
||||
#define CHAT_MESSAGE_HEIGHT_DECAY 0.9
|
||||
/// Approximate height in pixels of an 'average' line, used for height decay
|
||||
#define CHAT_MESSAGE_APPROX_LHEIGHT 11
|
||||
/// Max width of chat message in pixels
|
||||
#define CHAT_MESSAGE_WIDTH 96
|
||||
/// Max length of chat message in characters
|
||||
#define CHAT_MESSAGE_MAX_LENGTH 110
|
||||
/// Maximum precision of float before rounding errors occur (in this context)
|
||||
#define CHAT_LAYER_Z_STEP 0.0001
|
||||
/// The number of z-layer 'slices' usable by the chat message layering
|
||||
#define CHAT_LAYER_MAX_Z (CHAT_LAYER_MAX - CHAT_LAYER) / CHAT_LAYER_Z_STEP
|
||||
/// Macro from Lummox used to get height from a MeasureText proc
|
||||
#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1))
|
||||
|
||||
/**
|
||||
* # Chat Message Overlay
|
||||
@@ -20,10 +33,18 @@
|
||||
var/atom/message_loc
|
||||
/// The client who heard this message
|
||||
var/client/owned_by
|
||||
/// Contains the scheduled destruction time
|
||||
/// Contains the scheduled destruction time, used for scheduling EOL
|
||||
var/scheduled_destruction
|
||||
/// Contains the time that the EOL for the message will be complete, used for qdel scheduling
|
||||
var/eol_complete
|
||||
/// Contains the approximate amount of lines for height decay
|
||||
var/approx_lines
|
||||
/// Contains the reference to the next chatmessage in the bucket, used by runechat subsystem
|
||||
var/datum/chatmessage/next
|
||||
/// Contains the reference to the previous chatmessage in the bucket, used by runechat subsystem
|
||||
var/datum/chatmessage/prev
|
||||
/// The current index used for adjusting the layer of each sequential chat message such that recent messages will overlay older ones
|
||||
var/static/current_z_idx = 0
|
||||
|
||||
/**
|
||||
* Constructs a chat message overlay
|
||||
@@ -53,6 +74,7 @@
|
||||
owned_by = null
|
||||
message_loc = null
|
||||
message = null
|
||||
leave_subsystem()
|
||||
return ..()
|
||||
|
||||
/**
|
||||
@@ -109,17 +131,12 @@
|
||||
// We dim italicized text to make it more distinguishable from regular text
|
||||
var/tgt_color = extra_classes.Find("italics") ? target.chat_color_darkened : target.chat_color
|
||||
|
||||
// Approximate text height
|
||||
// Note we have to replace HTML encoded metacharacters otherwise MeasureText will return a zero height
|
||||
// BYOND Bug #2563917
|
||||
// Construct text
|
||||
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
|
||||
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[owner.say_emphasis(text)]</span>"
|
||||
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
|
||||
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(complete_text, null, CHAT_MESSAGE_WIDTH))
|
||||
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
|
||||
|
||||
// Translate any existing messages upwards, apply exponential decay factors to timers
|
||||
message_loc = target
|
||||
message_loc = get_atom_on_turf(target)
|
||||
if (owned_by.seen_messages)
|
||||
var/idx = 1
|
||||
var/combined_height = approx_lines
|
||||
@@ -127,14 +144,20 @@
|
||||
var/datum/chatmessage/m = msg
|
||||
animate(m.message, pixel_y = m.message.pixel_y + mheight, time = CHAT_MESSAGE_SPAWN_TIME)
|
||||
combined_height += m.approx_lines
|
||||
|
||||
// When choosing to update the remaining time we have to be careful not to update the
|
||||
// scheduled time once the EOL completion time has been set.
|
||||
var/sched_remaining = m.scheduled_destruction - world.time
|
||||
if (sched_remaining > CHAT_MESSAGE_SPAWN_TIME)
|
||||
if (!m.eol_complete)
|
||||
var/remaining_time = (sched_remaining) * (CHAT_MESSAGE_EXP_DECAY ** idx++) * (CHAT_MESSAGE_HEIGHT_DECAY ** combined_height)
|
||||
m.scheduled_destruction = world.time + remaining_time
|
||||
addtimer(CALLBACK(m, .proc/end_of_life), remaining_time, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
m.enter_subsystem(world.time + remaining_time) // push updated time to runechat SS
|
||||
|
||||
// Reset z index if relevant
|
||||
if (current_z_idx >= CHAT_LAYER_MAX_Z)
|
||||
current_z_idx = 0
|
||||
|
||||
// Build message image
|
||||
message = image(loc = message_loc, layer = CHAT_LAYER)
|
||||
message = image(loc = message_loc, layer = CHAT_LAYER + CHAT_LAYER_Z_STEP * current_z_idx++)
|
||||
message.plane = CHAT_PLANE
|
||||
message.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA | KEEP_APART
|
||||
message.alpha = 0
|
||||
@@ -149,16 +172,19 @@
|
||||
owned_by.images |= message
|
||||
animate(message, alpha = 255, time = CHAT_MESSAGE_SPAWN_TIME)
|
||||
|
||||
// Prepare for destruction
|
||||
// Register with the runechat SS to handle EOL and destruction
|
||||
scheduled_destruction = world.time + (lifespan - CHAT_MESSAGE_EOL_FADE)
|
||||
addtimer(CALLBACK(src, .proc/end_of_life), lifespan - CHAT_MESSAGE_EOL_FADE, TIMER_UNIQUE|TIMER_OVERRIDE)
|
||||
enter_subsystem()
|
||||
|
||||
/**
|
||||
* Applies final animations to overlay CHAT_MESSAGE_EOL_FADE deciseconds prior to message deletion
|
||||
* Arguments:
|
||||
* * fadetime - The amount of time to animate the message's fadeout for
|
||||
*/
|
||||
/datum/chatmessage/proc/end_of_life(fadetime = CHAT_MESSAGE_EOL_FADE)
|
||||
eol_complete = scheduled_destruction + fadetime
|
||||
animate(message, alpha = 0, time = fadetime, flags = ANIMATION_PARALLEL)
|
||||
QDEL_IN(src, fadetime)
|
||||
enter_subsystem(eol_complete) // re-enter the runechat SS with the EOL completion time to QDEL self
|
||||
|
||||
/**
|
||||
* Creates a message overlay at a defined location for a given speaker
|
||||
|
||||
+51
-34
@@ -1,5 +1,3 @@
|
||||
GLOBAL_LIST_EMPTY(cinematics)
|
||||
|
||||
// Use to play cinematics.
|
||||
// Watcher can be world,mob, or a list of mobs
|
||||
// Blocks until sequence is done.
|
||||
@@ -18,6 +16,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
playing.is_global = TRUE
|
||||
watcher = GLOB.mob_list
|
||||
playing.play(watcher)
|
||||
qdel(playing)
|
||||
|
||||
/obj/screen/cinematic
|
||||
icon = 'icons/effects/station_explosion.dmi'
|
||||
@@ -25,12 +24,13 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
plane = SPLASHSCREEN_PLANE
|
||||
layer = SPLASHSCREEN_LAYER
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
screen_loc = "1,1"
|
||||
screen_loc = "BOTTOM,LEFT+50%"
|
||||
appearance_flags = APPEARANCE_UI | TILE_BOUND
|
||||
|
||||
/datum/cinematic
|
||||
var/id = CINEMATIC_DEFAULT
|
||||
var/list/watching = list() //List of clients watching this
|
||||
var/list/locked = list() //Who had mob_transforming set during the cinematic
|
||||
var/list/locked = list() //Who had mob_transforming set during the cinematic
|
||||
var/is_global = FALSE //Global cinematics will override mob-specific ones
|
||||
var/obj/screen/cinematic/screen
|
||||
var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc)
|
||||
@@ -38,28 +38,35 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
var/stop_ooc = TRUE //Turns off ooc when played globally.
|
||||
|
||||
/datum/cinematic/New()
|
||||
GLOB.cinematics += src
|
||||
screen = new(src)
|
||||
|
||||
/datum/cinematic/Destroy()
|
||||
GLOB.cinematics -= src
|
||||
for(var/CC in watching)
|
||||
if(!CC)
|
||||
continue
|
||||
var/client/C = CC
|
||||
//C.mob.clear_fullscreen("cinematic")
|
||||
C.screen -= screen
|
||||
watching = null
|
||||
QDEL_NULL(screen)
|
||||
for(var/mob/M in locked)
|
||||
M.mob_transforming = FALSE
|
||||
QDEL_NULL(special_callback)
|
||||
for(var/MM in locked)
|
||||
if(!MM)
|
||||
continue
|
||||
var/mob/M = MM
|
||||
M.mob_transforming = FALSE
|
||||
locked = null
|
||||
return ..()
|
||||
|
||||
/datum/cinematic/proc/play(watchers)
|
||||
//Check if you can actually play it (stop mob cinematics for global ones) and create screen objects
|
||||
for(var/A in GLOB.cinematics)
|
||||
var/datum/cinematic/C = A
|
||||
if(C == src)
|
||||
continue
|
||||
if(C.is_global || !is_global)
|
||||
return //Can't play two global or local cinematics at the same time
|
||||
//Check if cinematic can actually play (stop mob cinematics for global ones)
|
||||
if(SEND_GLOBAL_SIGNAL(COMSIG_GLOB_PLAY_CINEMATIC, src) & COMPONENT_GLOB_BLOCK_CINEMATIC)
|
||||
return
|
||||
|
||||
//Close all open windows if global
|
||||
if(is_global)
|
||||
SStgui.close_all_uis()
|
||||
//We are now playing this cinematic
|
||||
|
||||
//Handle what happens when a different cinematic tries to play over us
|
||||
RegisterSignal(SSdcs, COMSIG_GLOB_PLAY_CINEMATIC, .proc/replacement_cinematic)
|
||||
|
||||
//Pause OOC
|
||||
var/ooc_toggled = FALSE
|
||||
@@ -67,24 +74,17 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
ooc_toggled = TRUE
|
||||
toggle_ooc(FALSE)
|
||||
|
||||
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(M in watchers)
|
||||
M.mob_transforming = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
locked += M
|
||||
//Close watcher ui's
|
||||
SStgui.close_user_uis(M)
|
||||
if(M.client)
|
||||
watching += M.client
|
||||
M.client.screen += screen
|
||||
else
|
||||
if(is_global)
|
||||
M.mob_transforming = TRUE
|
||||
locked += M
|
||||
//Place /obj/screen/cinematic into everyone's screens, prevent them from moving
|
||||
for(var/MM in watchers)
|
||||
var/mob/M = MM
|
||||
show_to(M, M.client)
|
||||
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGIN, .proc/show_to)
|
||||
//Close watcher ui's
|
||||
SStgui.close_user_uis(M)
|
||||
|
||||
//Actually play it
|
||||
content()
|
||||
|
||||
|
||||
//Cleanup
|
||||
sleep(cleanup_time)
|
||||
|
||||
@@ -92,7 +92,17 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
if(ooc_toggled)
|
||||
toggle_ooc(TRUE)
|
||||
|
||||
qdel(src)
|
||||
/datum/cinematic/proc/show_to(mob/M, client/C)
|
||||
//SIGNAL_HANDLER //must not wait.
|
||||
|
||||
if(!M.mob_transforming)
|
||||
locked += M
|
||||
M.mob_transforming = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
if(!C)
|
||||
return
|
||||
watching += C
|
||||
//M.overlay_fullscreen("cinematic",/obj/screen/fullscreen/cinematic_backdrop)
|
||||
C.screen += screen
|
||||
|
||||
//Sound helper
|
||||
/datum/cinematic/proc/cinematic_sound(s)
|
||||
@@ -111,6 +121,13 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
/datum/cinematic/proc/content()
|
||||
sleep(50)
|
||||
|
||||
/datum/cinematic/proc/replacement_cinematic(datum/source, datum/cinematic/other)
|
||||
//SIGNAL_HANDLER
|
||||
|
||||
if(!is_global && other.is_global) //Allow it to play if we're local and it's global
|
||||
return NONE
|
||||
return COMPONENT_GLOB_BLOCK_CINEMATIC
|
||||
|
||||
/datum/cinematic/nuke_win
|
||||
id = CINEMATIC_NUKE_WIN
|
||||
|
||||
|
||||
@@ -189,26 +189,32 @@
|
||||
if(-INFINITY to SANITY_CRAZY)
|
||||
setInsanityEffect(MAJOR_INSANITY_PEN)
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/insane)
|
||||
master.add_actionspeed_modifier(/datum/actionspeed_modifier/low_sanity)
|
||||
sanity_level = 6
|
||||
if(SANITY_CRAZY to SANITY_UNSTABLE)
|
||||
setInsanityEffect(MINOR_INSANITY_PEN)
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/crazy)
|
||||
master.add_actionspeed_modifier(/datum/actionspeed_modifier/low_sanity)
|
||||
sanity_level = 5
|
||||
if(SANITY_UNSTABLE to SANITY_DISTURBED)
|
||||
setInsanityEffect(SLIGHT_INSANITY_PEN)
|
||||
master.add_movespeed_modifier(/datum/movespeed_modifier/sanity/disturbed)
|
||||
master.add_actionspeed_modifier(/datum/actionspeed_modifier/low_sanity)
|
||||
sanity_level = 4
|
||||
if(SANITY_DISTURBED to SANITY_NEUTRAL)
|
||||
setInsanityEffect(0)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
master.remove_actionspeed_modifier(ACTIONSPEED_ID_SANITY)
|
||||
sanity_level = 3
|
||||
if(SANITY_NEUTRAL+1 to SANITY_GREAT+1) //shitty hack but +1 to prevent it from responding to super small differences
|
||||
setInsanityEffect(0)
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
master.add_actionspeed_modifier(/datum/actionspeed_modifier/high_sanity)
|
||||
sanity_level = 2
|
||||
if(SANITY_GREAT+1 to INFINITY)
|
||||
setInsanityEffect(ECSTATIC_SANITY_PEN) //It's not a penalty but w/e
|
||||
master.remove_movespeed_modifier(MOVESPEED_ID_SANITY)
|
||||
master.add_actionspeed_modifier(/datum/actionspeed_modifier/high_sanity)
|
||||
sanity_level = 1
|
||||
|
||||
if(sanity_level != old_sanity_level)
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
buckled_mob.pixel_x = 0
|
||||
buckled_mob.pixel_y = 0
|
||||
if(buckled_mob.client)
|
||||
buckled_mob.client.change_view(CONFIG_GET(string/default_view))
|
||||
buckled_mob.client.view_size.resetToDefault()
|
||||
|
||||
//MOVEMENT
|
||||
/datum/component/riding/proc/turf_check(turf/next, turf/current)
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
// This is to stop squeak spam from inhand usage
|
||||
var/last_use = 0
|
||||
var/use_delay = 20
|
||||
|
||||
|
||||
// squeak cooldowns
|
||||
var/last_squeak = 0
|
||||
var/squeak_delay = 5
|
||||
|
||||
|
||||
/// chance we'll be stopped from squeaking by cooldown when something crossing us squeaks
|
||||
var/cross_squeak_delay_chance = 33 // about 3 things can squeak at a time
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), .proc/play_squeak)
|
||||
if(ismovable(parent))
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak)
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED), .proc/play_squeak_crossed)
|
||||
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED, COMSIG_MOVABLE_CROSS), .proc/play_squeak_crossed)
|
||||
RegisterSignal(parent, COMSIG_CROSS_SQUEAKED, .proc/delay_squeak)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react)
|
||||
if(isitem(parent))
|
||||
|
||||
+45
-17
@@ -15,22 +15,32 @@
|
||||
* If this is non zero then the object has been garbage collected and is awaiting either
|
||||
* a hard del by the GC subsystme, or to be autocollected (if it has no references)
|
||||
*/
|
||||
var/gc_destroyed //Time when this object was destroyed.
|
||||
var/gc_destroyed
|
||||
|
||||
/// Active timers with this datum as the target
|
||||
var/list/active_timers
|
||||
/// Status traits attached to this datum
|
||||
var/list/status_traits
|
||||
/// Components attached to this datum
|
||||
/// Lazy associated list in the structure of `type:component/list of components`
|
||||
|
||||
/**
|
||||
* Components attached to this datum
|
||||
*
|
||||
* Lazy associated list in the structure of `type:component/list of components`
|
||||
*/
|
||||
var/list/datum_components
|
||||
/// Any datum registered to receive signals from this datum is in this list
|
||||
/// Lazy associated list in the structure of `signal:registree/list of registrees`
|
||||
var/list/comp_lookup //it used to be for looking up components which had registered a signal but now anything can register
|
||||
/**
|
||||
* Any datum registered to receive signals from this datum is in this list
|
||||
*
|
||||
* Lazy associated list in the structure of `signal:registree/list of registrees`
|
||||
*/
|
||||
var/list/comp_lookup
|
||||
/// Lazy associated list in the structure of `signals:proctype` that are run when the datum receives that signal
|
||||
var/list/list/datum/callback/signal_procs
|
||||
/// Is this datum capable of sending signals?
|
||||
/// Set to true when a signal has been registered
|
||||
/**
|
||||
* Is this datum capable of sending signals?
|
||||
*
|
||||
* Set to true when a signal has been registered
|
||||
*/
|
||||
var/signal_enabled = FALSE
|
||||
|
||||
/// Datum level flags
|
||||
@@ -39,7 +49,12 @@
|
||||
/// A weak reference to another datum
|
||||
var/datum/weakref/weak_reference
|
||||
|
||||
///Lazy associative list of currently active cooldowns.
|
||||
/*
|
||||
* Lazy associative list of currently active cooldowns.
|
||||
*
|
||||
* cooldowns [ COOLDOWN_INDEX ] = add_timer()
|
||||
* add_timer() returns the truthy value of -1 when not stoppable, and else a truthy numeric index
|
||||
*/
|
||||
var/list/cooldowns
|
||||
|
||||
#ifdef TESTING
|
||||
@@ -51,23 +66,34 @@
|
||||
var/list/cached_vars
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Called when a href for this datum is clicked
|
||||
*
|
||||
* Sends a [COMSIG_TOPIC] signal
|
||||
*/
|
||||
/datum/Topic(href, href_list[])
|
||||
..()
|
||||
SEND_SIGNAL(src, COMSIG_TOPIC, usr, href_list)
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of clean-up code.
|
||||
*
|
||||
* This should be overridden to remove all references pointing to the object being destroyed, if
|
||||
* you do override it, make sure to call the parent and return it's return value by default
|
||||
*
|
||||
* Return an appropriate QDEL_HINT to modify handling of your deletion;
|
||||
* in most cases this is QDEL_HINT_QUEUE.
|
||||
* Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion;
|
||||
* in most cases this is [QDEL_HINT_QUEUE].
|
||||
*
|
||||
* The base case is responsible for doing the following
|
||||
* * Erasing timers pointing to this datum
|
||||
* * Erasing compenents on this datum
|
||||
* * Notifying datums listening to signals from this datum that we are going away
|
||||
*
|
||||
* Returns QDEL_HINT_QUEUE
|
||||
* Returns [QDEL_HINT_QUEUE]
|
||||
*/
|
||||
/datum/proc/Destroy(force=FALSE, ...)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
tag = null
|
||||
datum_flags &= ~DF_USE_TAG //In case something tries to REF us
|
||||
weak_reference = null //ensure prompt GCing of weakref.
|
||||
@@ -112,7 +138,7 @@
|
||||
UnregisterSignal(target, signal_procs[target])
|
||||
//END: ECS SHIT
|
||||
|
||||
SSsounds.free_datum_channels(src)
|
||||
SSsounds.free_datum_channels(src) //?? (not on tg)
|
||||
|
||||
return QDEL_HINT_QUEUE
|
||||
|
||||
@@ -143,15 +169,15 @@
|
||||
to_chat(target, txt_changed_vars())
|
||||
#endif
|
||||
|
||||
//Return a LIST for serialize_datum to encode! Not the actual json!
|
||||
///Return a LIST for serialize_datum to encode! Not the actual json!
|
||||
/datum/proc/serialize_list(list/options)
|
||||
CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!")
|
||||
|
||||
//Accepts a LIST from deserialize_datum. Should return src or another datum.
|
||||
///Accepts a LIST from deserialize_datum. Should return src or another datum.
|
||||
/datum/proc/deserialize_list(json, list/options)
|
||||
CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!")
|
||||
|
||||
//Serializes into JSON. Does not encode type.
|
||||
///Serializes into JSON. Does not encode type.
|
||||
/datum/proc/serialize_json(list/options)
|
||||
. = serialize_list(options)
|
||||
if(!islist(.))
|
||||
@@ -159,13 +185,14 @@
|
||||
else
|
||||
. = json_encode(.)
|
||||
|
||||
//Deserializes from JSON. Does not parse type.
|
||||
///Deserializes from JSON. Does not parse type.
|
||||
/datum/proc/deserialize_json(list/input, list/options)
|
||||
var/list/jsonlist = json_decode(input)
|
||||
. = deserialize_list(jsonlist)
|
||||
if(!istype(., /datum))
|
||||
. = null
|
||||
|
||||
///Convert a datum into a json blob
|
||||
/proc/json_serialize_datum(datum/D, list/options)
|
||||
if(!istype(D))
|
||||
return
|
||||
@@ -174,6 +201,7 @@
|
||||
jsonlist["DATUM_TYPE"] = D.type
|
||||
return json_encode(jsonlist)
|
||||
|
||||
/// Convert a list of json to datum
|
||||
/proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE)
|
||||
if(!islist(jsonlist))
|
||||
if(!istext(jsonlist))
|
||||
|
||||
@@ -236,12 +236,12 @@
|
||||
switch(stage)
|
||||
if(1)
|
||||
if(ishuman(affected_mob) && affected_mob.dna)
|
||||
if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "lum")
|
||||
if(affected_mob.dna.species.id == "slime" || affected_mob.dna.species.id == "stargazer" || affected_mob.dna.species.id == "slimelumi")
|
||||
stage = 5
|
||||
if(3)
|
||||
if(ishuman(affected_mob))
|
||||
var/mob/living/carbon/human/human = affected_mob
|
||||
if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "lum")
|
||||
if(human.dna.species.id != "slime" && affected_mob.dna.species.id != "stargazer" && affected_mob.dna.species.id != "slimelumi")
|
||||
human.set_species(/datum/species/jelly/slime)
|
||||
|
||||
/datum/disease/transformation/corgi
|
||||
|
||||
@@ -89,6 +89,8 @@ GLOBAL_LIST_EMPTY(explosions)
|
||||
if(adminlog)
|
||||
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [ADMIN_VERBOSEJMP(epicenter)]")
|
||||
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in [loc_name(epicenter)]")
|
||||
|
||||
deadchat_broadcast("<span class='deadsay bold'>An explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) has occured at ([get_area(epicenter)])</span>", turf_target = get_turf(epicenter))
|
||||
|
||||
var/x0 = epicenter.x
|
||||
var/y0 = epicenter.y
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
playsound(get_turf(A), pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, TRUE)
|
||||
P.firer = A
|
||||
P.setAngle(rand(0, 360))//SHING
|
||||
A.adjustStaminaLossBuffered (3) //Citadel change to stop infinite bullet sponging as you run away, but it is buffered!
|
||||
A.adjustStaminaLoss(3)
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
|
||||
@@ -214,6 +214,7 @@
|
||||
|
||||
/datum/point/vector/processed/Destroy()
|
||||
STOP_PROCESSING(SSprojectiles, src)
|
||||
return ..()
|
||||
|
||||
/datum/point/vector/processed/proc/start()
|
||||
last_process = world.time
|
||||
|
||||
@@ -114,14 +114,12 @@
|
||||
description = "..."
|
||||
suffix = "lavaland_surface_sloth.dmm"
|
||||
// Generates nothing but atmos runtimes and salt
|
||||
cost = 0
|
||||
|
||||
/datum/map_template/ruin/lavaland/ratvar
|
||||
name = "Dead God"
|
||||
id = "ratvar"
|
||||
description = "Ratvars final resting place."
|
||||
description = "Ratvar's final resting place."
|
||||
suffix = "lavaland_surface_dead_ratvar.dmm"
|
||||
cost = 0
|
||||
allow_duplicates = FALSE
|
||||
|
||||
/datum/map_template/ruin/lavaland/hierophant
|
||||
@@ -137,7 +135,7 @@
|
||||
id = "blooddrunk"
|
||||
description = "A strange arrangement of stone tiles and an insane, beastly miner contemplating them."
|
||||
suffix = "lavaland_surface_blooddrunk1.dmm"
|
||||
cost = 0
|
||||
always_place = TRUE
|
||||
allow_duplicates = FALSE //will only spawn one variant of the ruin
|
||||
|
||||
/datum/map_template/ruin/lavaland/blood_drunk_miner/guidance
|
||||
|
||||
@@ -409,6 +409,13 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/map_template/shuttle/emergency/cruise
|
||||
suffix = "nature"
|
||||
name = "Dynamic Environmental Interaction Shuttle"
|
||||
description = "A large shuttle with a center biodome that is flourishing with life. Frolick with the monkeys! (Extra monkeys are stored on the bridge.)"
|
||||
admin_notes = "Pretty freakin' large, almost as big as Raven or Cere. Excercise caution with it."
|
||||
credit_cost = 8000
|
||||
|
||||
/datum/map_template/shuttle/ferry/base
|
||||
suffix = "base"
|
||||
name = "transport ferry"
|
||||
|
||||
@@ -171,6 +171,7 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
continue
|
||||
max_assoc = levels[lvl-1]
|
||||
levels["[max_assoc] +[max_assoc_start++]"] = value
|
||||
continue
|
||||
levels[key] = value
|
||||
|
||||
/datum/skill/level/sanitize_value(new_value)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/datum/skill/level/dorfy/blacksmithing
|
||||
/datum/skill/level/dwarfy/blacksmithing
|
||||
name = "Blacksmithing"
|
||||
desc = "Making metal into fancy shapes using heat and force. Higher levels increase both your working speed at an anvil as well as the quality of your works."
|
||||
name_color = COLOR_FLOORTILE_GRAY
|
||||
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
|
||||
ui_category = SKILL_UI_CAT_MISC
|
||||
standard_xp_lvl_up = 100 //Effectively 200xp for level 1 because of how this code works. 300 more for 2, Etc,
|
||||
|
||||
@@ -1046,7 +1046,7 @@ datum/status_effect/pacify
|
||||
id = "fake_virus"
|
||||
duration = 1800//3 minutes
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
tick_interval = 1
|
||||
tick_interval = 20
|
||||
alert_type = null
|
||||
var/msg_stage = 0//so you dont get the most intense messages immediately
|
||||
|
||||
|
||||
@@ -278,7 +278,3 @@
|
||||
/datum/status_effect/grouped/before_remove(source)
|
||||
sources -= source
|
||||
return !length(sources)
|
||||
|
||||
//do_after modifier!
|
||||
/datum/status_effect/proc/interact_speed_modifier()
|
||||
return 1
|
||||
|
||||
@@ -141,22 +141,23 @@
|
||||
// bones
|
||||
/datum/status_effect/wound/blunt
|
||||
|
||||
/datum/status_effect/wound/blunt/interact_speed_modifier()
|
||||
var/mob/living/carbon/C = owner
|
||||
/datum/status_effect/wound/blunt/on_apply()
|
||||
. = ..()
|
||||
RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, .proc/on_swap_hands)
|
||||
on_swap_hands()
|
||||
|
||||
if(C.get_active_hand() == linked_limb)
|
||||
to_chat(C, "<span class='warning'>The [lowertext(linked_wound)] in your [linked_limb.name] slows your progress!</span>")
|
||||
return linked_wound.interaction_efficiency_penalty
|
||||
/datum/status_effect/wound/blunt/on_remove()
|
||||
. = ..()
|
||||
UnregisterSignal(owner, COMSIG_MOB_SWAP_HANDS)
|
||||
var/mob/living/carbon/wound_owner = owner
|
||||
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound)
|
||||
|
||||
return 1
|
||||
|
||||
/datum/status_effect/wound/blunt/action_cooldown_mod()
|
||||
var/mob/living/carbon/C = owner
|
||||
|
||||
if(C.get_active_hand() == linked_limb)
|
||||
return linked_wound.interaction_efficiency_penalty
|
||||
|
||||
return 1
|
||||
/datum/status_effect/wound/blunt/proc/on_swap_hands()
|
||||
var/mob/living/carbon/wound_owner = owner
|
||||
if(wound_owner.get_active_hand() == linked_limb)
|
||||
wound_owner.add_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound, (linked_wound.interaction_efficiency_penalty - 1))
|
||||
else
|
||||
wound_owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/blunt_wound)
|
||||
|
||||
/datum/status_effect/wound/blunt/moderate
|
||||
id = "disjoint"
|
||||
|
||||
@@ -44,42 +44,16 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
|
||||
/datum/quirk/family_heirloom/on_spawn()
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
var/obj/item/heirloom_type
|
||||
switch(quirk_holder.mind.assigned_role)
|
||||
if("Clown")
|
||||
heirloom_type = pick(/obj/item/paint/anycolor, /obj/item/bikehorn/golden)
|
||||
if("Mime")
|
||||
heirloom_type = pick(/obj/item/paint/anycolor, /obj/item/toy/dummy)
|
||||
if("Cook")
|
||||
heirloom_type = /obj/item/kitchen/knife/scimitar
|
||||
if("Botanist")
|
||||
heirloom_type = pick(/obj/item/cultivator, /obj/item/reagent_containers/glass/bucket, /obj/item/storage/bag/plants, /obj/item/toy/plush/beeplushie)
|
||||
if("Medical Doctor")
|
||||
heirloom_type = /obj/item/healthanalyzer
|
||||
if("Paramedic")
|
||||
heirloom_type = /obj/item/lighter
|
||||
if("Station Engineer")
|
||||
heirloom_type = /obj/item/wirecutters/brass
|
||||
if("Atmospheric Technician")
|
||||
heirloom_type = /obj/item/extinguisher/mini/family
|
||||
if("Lawyer")
|
||||
heirloom_type = /obj/item/storage/briefcase/lawyer/family
|
||||
if("Janitor")
|
||||
heirloom_type = /obj/item/mop
|
||||
if("Security Officer")
|
||||
heirloom_type = /obj/item/clothing/accessory/medal/silver/valor
|
||||
if("Scientist")
|
||||
heirloom_type = /obj/item/toy/plush/slimeplushie
|
||||
if("Assistant")
|
||||
heirloom_type = /obj/item/clothing/gloves/cut/family
|
||||
if("Chaplain")
|
||||
heirloom_type = /obj/item/camera/spooky/family
|
||||
if("Captain")
|
||||
heirloom_type = /obj/item/clothing/accessory/medal/gold/captain/family
|
||||
var/species_heirloom_entry = GLOB.species_heirlooms[H.dna.species.id]
|
||||
if(species_heirloom_entry)
|
||||
if(prob(species_heirloom_entry[1]))
|
||||
heirloom_type = pick(species_heirloom_entry[2])
|
||||
if(!heirloom_type)
|
||||
heirloom_type = pick(
|
||||
/obj/item/toy/cards/deck,
|
||||
/obj/item/lighter,
|
||||
/obj/item/dice/d20)
|
||||
var/job_heirloom_entry = GLOB.job_heirlooms[quirk_holder.mind.assigned_role]
|
||||
if(!job_heirloom_entry)
|
||||
heirloom_type = pick(GLOB.job_heirlooms["NO_JOB"]) //consider: should this be a define?
|
||||
else
|
||||
heirloom_type = pick(job_heirloom_entry)
|
||||
heirloom = new heirloom_type(get_turf(quirk_holder))
|
||||
GLOB.family_heirlooms += heirloom
|
||||
var/list/slots = list(
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
//This is intended to be a full wrapper. DO NOT directly modify its values
|
||||
///Container for client viewsize
|
||||
/datum/viewData
|
||||
var/width = 0
|
||||
var/height = 0
|
||||
var/default = ""
|
||||
var/is_suppressed = FALSE
|
||||
var/client/chief = null
|
||||
|
||||
/datum/viewData/New(client/owner, view_string)
|
||||
default = view_string
|
||||
chief = owner
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/setDefault(string)
|
||||
default = string
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/safeApplyFormat()
|
||||
if(isZooming())
|
||||
assertFormat()
|
||||
return
|
||||
resetFormat()
|
||||
|
||||
/datum/viewData/proc/assertFormat()//T-Pose
|
||||
// winset(chief, "mapwindow.map", "zoom=0")
|
||||
// Citadel Edit - We're using icon dropdown instead
|
||||
|
||||
/datum/viewData/proc/resetFormat()//Cuck
|
||||
// winset(chief, "mapwindow.map", "zoom=[chief.prefs.pixel_size]")
|
||||
// Citadel Edit - We're using icon dropdown instead
|
||||
|
||||
/datum/viewData/proc/setZoomMode()
|
||||
// winset(chief, "mapwindow.map", "zoom-mode=[chief.prefs.scaling_method]")
|
||||
// Citadel Edit - We're using icon dropdown instead
|
||||
|
||||
/datum/viewData/proc/isZooming()
|
||||
return (width || height)
|
||||
|
||||
/datum/viewData/proc/resetToDefault()
|
||||
width = 0
|
||||
height = 0
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/add(toAdd)
|
||||
width += toAdd
|
||||
height += toAdd
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/addTo(toAdd)
|
||||
var/list/shitcode = getviewsize(toAdd)
|
||||
width += shitcode[1]
|
||||
height += shitcode[2]
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/setTo(toAdd)
|
||||
var/list/shitcode = getviewsize(toAdd) //Backward compatability to account
|
||||
width = shitcode[1] //for a change in how sizes get calculated. we used to include world.view in
|
||||
height = shitcode[2] //this, but it was jank, so I had to move it
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/setBoth(wid, hei)
|
||||
width = wid
|
||||
height = hei
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/setWidth(wid)
|
||||
width = wid
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/setHeight(hei)
|
||||
width = hei
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/addToWidth(toAdd)
|
||||
width += toAdd
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/addToHeight(screen, toAdd)
|
||||
height += toAdd
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/apply()
|
||||
chief.change_view(getView())
|
||||
safeApplyFormat()
|
||||
if(chief.prefs.auto_fit_viewport)
|
||||
chief.fit_viewport()
|
||||
|
||||
/datum/viewData/proc/supress()
|
||||
is_suppressed = TRUE
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/unsupress()
|
||||
is_suppressed = FALSE
|
||||
apply()
|
||||
|
||||
/datum/viewData/proc/getView()
|
||||
var/list/temp = getviewsize(default)
|
||||
if(is_suppressed)
|
||||
return "[temp[1]]x[temp[2]]"
|
||||
return "[width + temp[1]]x[height + temp[2]]"
|
||||
|
||||
/datum/viewData/proc/zoomIn()
|
||||
resetToDefault()
|
||||
animate(chief, pixel_x = 0, pixel_y = 0, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW)
|
||||
|
||||
/datum/viewData/proc/zoomOut(radius = 0, offset = 0, direction = FALSE)
|
||||
if(direction)
|
||||
var/_x = 0
|
||||
var/_y = 0
|
||||
switch(direction)
|
||||
if(NORTH)
|
||||
_y = offset
|
||||
if(EAST)
|
||||
_x = offset
|
||||
if(SOUTH)
|
||||
_y = -offset
|
||||
if(WEST)
|
||||
_x = -offset
|
||||
animate(chief, pixel_x = world.icon_size*_x, pixel_y = world.icon_size*_y, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW)
|
||||
//Ready for this one?
|
||||
setTo(radius)
|
||||
|
||||
/proc/getScreenSize(widescreen)
|
||||
if(widescreen)
|
||||
return CONFIG_GET(string/default_view)
|
||||
return CONFIG_GET(string/default_view_square)
|
||||
@@ -16,8 +16,12 @@
|
||||
/datum/weakref/New(datum/thing)
|
||||
reference = REF(thing)
|
||||
|
||||
/datum/weakref/Destroy()
|
||||
return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore.
|
||||
/datum/weakref/Destroy(force)
|
||||
if(!force)
|
||||
return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore.
|
||||
var/datum/target = resolve()
|
||||
target?.weak_reference = null
|
||||
return ..()
|
||||
|
||||
/datum/weakref/proc/resolve()
|
||||
var/datum/D = locate(reference)
|
||||
|
||||
@@ -95,8 +95,8 @@
|
||||
if(is_ash_immune(L))
|
||||
return
|
||||
if(is_species(L, /datum/species/lizard/ashwalker))
|
||||
if(!IS_STAMCRIT(L))
|
||||
L.adjustStaminaLossBuffered(4)
|
||||
if(L.getStaminaLoss() < (STAMINA_CRIT - 40))
|
||||
L.adjustStaminaLoss(4)
|
||||
return
|
||||
L.adjustFireLoss(4)
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
/// Used to "load" a persistent scar
|
||||
/datum/scar/proc/load(obj/item/bodypart/BP, version, description, specific_location, severity=WOUND_SEVERITY_SEVERE)
|
||||
if(!(BP.body_zone in applicable_zones) || !BP.is_organic_limb())
|
||||
if(!(BP.body_zone in applicable_zones) || !(BP.is_organic_limb() || BP.render_like_organic))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
* * smited- If this is a smite, we don't care about this wound for stat tracking purposes (not yet implemented)
|
||||
*/
|
||||
/datum/wound/proc/apply_wound(obj/item/bodypart/L, silent = FALSE, datum/wound/old_wound = null, smited = FALSE)
|
||||
if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || isalien(L.owner) || !L.is_organic_limb())
|
||||
if(!istype(L) || !L.owner || !(L.body_zone in viable_zones) || isalien(L.owner) || !(L.is_organic_limb() || L.render_like_organic))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
Reference in New Issue
Block a user