# Conflicts:
#	code/modules/ninja/suit/ninjaDrainAct.dm
This commit is contained in:
zerothebigboy
2021-05-02 22:47:39 -04:00
448 changed files with 310031 additions and 306315 deletions
+63
View File
@@ -0,0 +1,63 @@
/datum/component/activity
var/activity_level = 0
var/not_moved_counter = 0
var/list/historical_activity_levels = list()
/datum/component/activity/Initialize()
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
var/mob/living/L = parent
RegisterSignal(L, COMSIG_LIVING_SET_AS_ATTACKER, .proc/on_set_as_attacker)
RegisterSignal(L, COMSIG_LIVING_ATTACKER_SET, .proc/on_attacker_set)
RegisterSignal(L, COMSIG_MOB_DEATH, .proc/on_death)
RegisterSignal(L, COMSIG_EXIT_AREA, .proc/on_exit_area)
RegisterSignal(L, COMSIG_LIVING_LIFE, .proc/on_life)
RegisterSignal(L, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_MOVABLE_TELEPORTED, COMSIG_LIVING_GUN_PROCESS_FIRE, COMSIG_MOB_APPLY_DAMAGE), .proc/minor_activity)
/datum/component/activity/proc/log_activity()
historical_activity_levels[world.time] = activity_level
/datum/component/activity/proc/minor_activity(datum/source)
activity_level += 1
/datum/component/activity/proc/on_attacker_set(datum/source, mob/attacker)
activity_level += 10
if(attacker?.mind)
activity_level += 10
log_activity()
/datum/component/activity/proc/on_set_as_attacker(datum/source, mob/target)
activity_level += 10
if(target?.mind)
activity_level += 20
log_activity()
/datum/component/activity/proc/on_death(datum/source)
activity_level += 100 // dying means you're doing SOMETHING
log_activity()
/datum/component/activity/proc/on_exit_area(datum/source)
activity_level += 1
not_moved_counter = 0
/datum/component/activity/proc/on_life(datum/source, seconds, times_fired)
var/mob/living/L = source
if(L.stat >= UNCONSCIOUS) // can't expect the unconscious to move
return
not_moved_counter += seconds
var/should_log = FALSE
switch(not_moved_counter)
if(60 to 120)
activity_level -= 1
if(120 to 600)
activity_level -= 5
if(600 to 1200)
activity_level -= 10
should_log = TRUE
if(1200 to INFINITY)
activity_level -= 20
should_log = TRUE
activity_level = max(activity_level, 0)
if(should_log)
log_activity()
+1 -1
View File
@@ -73,7 +73,7 @@
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
var/meat_quality = 50 + (bonus_modifier/10) //increases through quality of butchering tool, and through if it was butchered in the kitchen or not
if(istype(get_area(butcher), /area/crew_quarters/kitchen))
if(istype(get_area(butcher), /area/service/kitchen))
meat_quality = meat_quality + 10
var/turf/T = meat.drop_location()
var/final_effectiveness = effectiveness - meat.butcher_difficulty
@@ -16,7 +16,7 @@
/datum/crafting_recipe/strobeshield
name = "Strobe Shield"
result = /obj/item/assembly/flash/shield
result = /obj/item/shield/riot/flash
reqs = list(/obj/item/wallframe/flasher = 1,
/obj/item/assembly/flash/handheld = 1,
/obj/item/shield/riot = 1)
+2 -2
View File
@@ -56,10 +56,10 @@
detonate()
/datum/component/explodable/proc/on_equip(datum/source, mob/equipper, slot)
RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMGE, .proc/explodable_attack_zone, TRUE)
RegisterSignal(equipper, COMSIG_MOB_APPLY_DAMAGE, .proc/explodable_attack_zone, TRUE)
/datum/component/explodable/proc/on_drop(datum/source, mob/user)
UnregisterSignal(user, COMSIG_MOB_APPLY_DAMGE)
UnregisterSignal(user, COMSIG_MOB_APPLY_DAMAGE)
/// Checks if we're hitting the zone this component is covering
/datum/component/explodable/proc/is_hitting_zone(def_zone)
+1 -1
View File
@@ -52,7 +52,7 @@
return
strength -= strength / hl3_release_date
if(strength <= RAD_BACKGROUND_RADIATION)
return PROCESS_KILL
qdel(src)
/datum/component/radioactive/proc/glow_loop(atom/movable/master)
+12 -31
View File
@@ -47,18 +47,8 @@
var/display_numerical_stacking = FALSE //stack things of the same type and show as a single object with a number.
/// "legacy"/default view mode's storage "boxes"
var/obj/screen/storage/boxes/ui_boxes
/// New volumetric storage display mode's left side
var/obj/screen/storage/left/ui_left
/// New volumetric storage display mode's center 'blocks'
var/obj/screen/storage/continuous/ui_continuous
/// The close button, used in all modes. Frames right side in volumetric mode.
var/obj/screen/storage/close/ui_close
/// Associative list of list(item = screen object) for volumetric storage item screen blocks
var/list/ui_item_blocks
var/current_maxscreensize
/// Ui objects by person. mob = list(objects)
var/list/ui_by_mob = list()
var/allow_big_nesting = FALSE //allow storage objects of the same or greater size.
@@ -125,18 +115,16 @@
/datum/component/storage/Destroy()
close_all()
QDEL_NULL(ui_boxes)
QDEL_NULL(ui_close)
QDEL_NULL(ui_continuous)
QDEL_NULL(ui_left)
// DO NOT USE QDEL_LIST_ASSOC.
if(ui_item_blocks)
for(var/i in ui_item_blocks)
qdel(ui_item_blocks[i]) //qdel the screen object not the item
ui_item_blocks.Cut()
wipe_ui_objects()
LAZYCLEARLIST(is_using)
return ..()
/datum/component/storage/proc/wipe_ui_objects()
for(var/i in ui_by_mob)
var/list/objects = ui_by_mob[i]
QDEL_LIST(objects)
ui_by_mob.Cut()
/datum/component/storage/PreTransfer()
update_actions()
@@ -351,13 +339,6 @@
return master._removal_reset(thing)
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
if(LAZYACCESS(ui_item_blocks, thing))
var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing]
for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion.
var/mob/M = i
M.client?.screen -= C.on_screen_objects()
ui_item_blocks -= thing
qdel(C)
_removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK!
refresh_mob_views()
@@ -467,14 +448,14 @@
return
A.add_fingerprint(M)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE, ghost = FALSE)
/datum/component/storage/proc/user_show_to_mob(mob/M, force = FALSE)
var/atom/A = parent
if(!istype(M))
return FALSE
A.add_fingerprint(M)
if(!force && (check_locked(null, M) || !M.CanReach(parent, view_only = TRUE)))
return FALSE
ui_show(M, !ghost)
ui_show(M)
/datum/component/storage/proc/mousedrop_receive(datum/source, atom/movable/O, mob/M)
if(isitem(O))
@@ -596,7 +577,7 @@
return can_be_inserted(I, silent, M)
/datum/component/storage/proc/show_to_ghost(datum/source, mob/dead/observer/M)
return user_show_to_mob(M, TRUE, TRUE)
return user_show_to_mob(M, TRUE)
/datum/component/storage/proc/signal_show_attempt(datum/source, mob/showto, force = FALSE)
return user_show_to_mob(showto, force)
+32 -53
View File
@@ -7,7 +7,7 @@
if(QDELETED(I))
continue
if(!.[I.type])
.[I.type] = new /datum/numbered_display(I, 1)
.[I.type] = new /datum/numbered_display(I, 1, src)
else
var/datum/numbered_display/ND = .[I.type]
ND.number++
@@ -20,6 +20,8 @@
. = list()
var/list/accessible_contents = accessible_items()
var/adjusted_contents = length(accessible_contents)
var/obj/screen/storage/close/ui_close
var/obj/screen/storage/boxes/ui_boxes
//Numbered contents display
var/list/datum/numbered_display/numbered_contents
@@ -60,12 +62,13 @@
for(var/obj/O in accessible_items())
if(QDELETED(O))
continue
O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
O.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
var/obj/screen/storage/item_holder/D = new(null, src, O)
D.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip"
D.screen_loc = "[cx]:[screen_pixel_x],[cy]:[screen_pixel_y]"
O.maptext = ""
O.layer = ABOVE_HUD_LAYER
O.plane = ABOVE_HUD_PLANE
. += O
. += D
cx++
if(cx - screen_start_x >= columns)
cx = screen_start_x
@@ -78,6 +81,9 @@
*/
/datum/component/storage/proc/orient2hud_volumetric(mob/user, maxcolumns)
. = list()
var/obj/screen/storage/left/ui_left
var/obj/screen/storage/continuous/ui_continuous
var/obj/screen/storage/close/ui_close
// Generate ui_item_blocks for missing ones and render+orient.
var/list/atom/contents = accessible_items()
@@ -128,14 +134,10 @@
var/first = TRUE
var/row = 1
LAZYINITLIST(ui_item_blocks)
for(var/i in percentage_by_item)
I = i
var/percent = percentage_by_item[I]
if(!ui_item_blocks[I])
ui_item_blocks[I] = new /obj/screen/storage/volumetric_box/center(null, src, I)
var/obj/screen/storage/volumetric_box/center/B = ui_item_blocks[I]
var/obj/screen/storage/volumetric_box/center/B = new /obj/screen/storage/volumetric_box/center(null, src, I)
var/pixels_to_use = overrun? MINIMUM_PIXELS_PER_ITEM : max(using_horizontal_pixels * percent, MINIMUM_PIXELS_PER_ITEM)
var/addrow = FALSE
if(CEILING(pixels_to_use, 1) >= FLOOR(horizontal_pixels - current_pixel - VOLUMETRIC_STORAGE_EDGE_PADDING, 1))
@@ -143,25 +145,17 @@
addrow = TRUE
// now that we have pixels_to_use, place our thing and add it to the returned list.
B.screen_loc = I.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]"
B.screen_loc = "[screen_start_x]:[round(current_pixel + (pixels_to_use * 0.5) + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING), 1)],[screen_start_y+row-1]:[screen_pixel_y]"
// add the used pixels to pixel after we place the object
current_pixel += pixels_to_use + (first? 0 : VOLUMETRIC_STORAGE_ITEM_PADDING)
first = FALSE //apply padding to everything after this
// set various things
B.set_pixel_size(pixels_to_use)
B.layer = VOLUMETRIC_STORAGE_BOX_LAYER
B.plane = VOLUMETRIC_STORAGE_BOX_PLANE
B.name = I.name
I.mouse_opacity = MOUSE_OPACITY_ICON
I.maptext = ""
I.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
I.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
// finally add our things.
. += B.on_screen_objects()
. += I
// go up a row if needed
if(addrow)
@@ -185,18 +179,19 @@
/**
* Shows our UI to a mob.
*/
/datum/component/storage/proc/ui_show(mob/M, set_screen_size = TRUE)
/datum/component/storage/proc/ui_show(mob/M)
if(!M.client)
return FALSE
if(ui_by_mob[M] || LAZYFIND(is_using, M))
// something went horribly wrong
// hide first
ui_hide(M)
var/list/cview = getviewsize(M.client.view)
// in tiles
var/maxallowedscreensize = cview[1]-8
if(set_screen_size)
current_maxscreensize = maxallowedscreensize
else if(current_maxscreensize)
maxallowedscreensize = current_maxscreensize
// we got screen size, register signal
RegisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT, .proc/on_logout, override = TRUE)
RegisterSignal(M, COMSIG_PARENT_QDELETING, .proc/on_logout, override = TRUE)
if(M.active_storage != src)
if(M.active_storage)
M.active_storage.ui_hide(M)
@@ -204,10 +199,14 @@
LAZYOR(is_using, M)
if(!M.client?.prefs?.no_tetris_storage && volumetric_ui())
//new volumetric ui bay-style
M.client.screen |= orient2hud_volumetric(M, maxallowedscreensize)
var/list/objects = orient2hud_volumetric(M, maxallowedscreensize)
M.client.screen |= objects
ui_by_mob[M] = objects
else
//old ui
M.client.screen |= orient2hud_legacy(M, maxallowedscreensize)
var/list/objects = orient2hud_legacy(M, maxallowedscreensize)
M.client.screen |= objects
ui_by_mob[M] = objects
return TRUE
/**
@@ -236,8 +235,10 @@
/datum/component/storage/proc/ui_hide(mob/M)
if(!M.client)
return TRUE
UnregisterSignal(M, COMSIG_MOB_CLIENT_LOGOUT)
M.client.screen -= list(ui_boxes, ui_close, ui_left, ui_continuous) + get_ui_item_objects_hide(M)
UnregisterSignal(M, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_CLIENT_LOGOUT))
M.client.screen -= ui_by_mob[M]
var/list/objects = ui_by_mob[M]
QDEL_LIST(objects)
if(M.active_storage == src)
M.active_storage = null
LAZYREMOVE(is_using, M)
@@ -250,48 +251,26 @@
var/atom/real_location = real_location()
return (storage_flags & STORAGE_LIMIT_VOLUME) && (length(real_location.contents) <= MAXIMUM_VOLUMETRIC_ITEMS) && !display_numerical_stacking
/**
* Gets the ui item objects to ui_hide.
*/
/datum/component/storage/proc/get_ui_item_objects_hide(mob/M)
if(!volumetric_ui() || M.client?.prefs?.no_tetris_storage)
var/atom/real_location = real_location()
return real_location.contents
else
. = list()
for(var/i in ui_item_blocks)
// get both the box and the item
. += ui_item_blocks[i]
. += i
/**
* Gets our ui_boxes, making it if it doesn't exist.
*/
/datum/component/storage/proc/get_ui_boxes()
if(!ui_boxes)
ui_boxes = new(null, src)
return ui_boxes
return new /obj/screen/storage/boxes(null, src)
/**
* Gets our ui_left, making it if it doesn't exist.
*/
/datum/component/storage/proc/get_ui_left()
if(!ui_left)
ui_left = new(null, src)
return ui_left
return new /obj/screen/storage/left(null, src)
/**
* Gets our ui_close, making it if it doesn't exist.
*/
/datum/component/storage/proc/get_ui_close()
if(!ui_close)
ui_close = new(null, src)
return ui_close
return new /obj/screen/storage/close(null, src)
/**
* Gets our ui_continuous, making it if it doesn't exist.
*/
/datum/component/storage/proc/get_ui_continuous()
if(!ui_continuous)
ui_continuous = new(null, src)
return ui_continuous
return new /obj/screen/storage/continuous(null, src)
@@ -384,7 +384,7 @@
var/temp_rate = 1
threshold_desc = list(
"Transmission 6" = "Additionally increases temperature adjustment rate and heals those who love toxins",
"Resistance 7" = "Increases healing speed.",
"Stage Speed 7" = "Increases healing speed.",
)
/datum/symptom/heal/plasma/Start(datum/disease/advance/A)
if(!..())
+3 -2
View File
@@ -329,12 +329,13 @@
uni_identity = generate_uni_identity()
unique_enzymes = generate_unique_enzymes()
/datum/dna/proc/initialize_dna(newblood_type)
/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE)
if(newblood_type)
blood_type = newblood_type
unique_enzymes = generate_unique_enzymes()
uni_identity = generate_uni_identity()
generate_dna_blocks()
if(!skip_index) //I hate this
generate_dna_blocks()
features = random_features(species?.id, holder?.gender)
+15 -11
View File
@@ -1,22 +1,24 @@
/**
* A holder for simple behaviour that can be attached to many different types
*
* Only one element of each type is instanced during game init.
* Otherwise acts basically like a lightweight component.
*/
* A holder for simple behaviour that can be attached to many different types
*
* Only one element of each type is instanced during game init.
* Otherwise acts basically like a lightweight component.
*/
/datum/element
/// Option flags for element behaviour
var/element_flags = NONE
/**
* The index of the first attach argument to consider for duplicate elements
* Is only used when flags contains ELEMENT_BESPOKE
*
* Is only used when flags contains [ELEMENT_BESPOKE]
*
* This is infinity so you must explicitly set this
*/
var/id_arg_index = INFINITY
/// Activates the functionality defined by the element on the given target datum
/datum/element/proc/Attach(datum/target)
SHOULD_CALL_PARENT(1)
SHOULD_CALL_PARENT(TRUE)
if(type == /datum/element)
return ELEMENT_INCOMPATIBLE
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
@@ -25,8 +27,10 @@
/// Deactivates the functionality defines by the element on the given datum
/datum/element/proc/Detach(datum/source, force)
SIGNAL_HANDLER
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
SHOULD_CALL_PARENT(1)
SHOULD_CALL_PARENT(TRUE)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
/datum/element/Destroy(force)
@@ -45,9 +49,9 @@
CRASH("Incompatible [arguments[1]] assigned to a [type]! args: [json_encode(args)]")
/**
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using ELEMENT_BESPOKE
*/
* Finds the singleton for the element type given and detaches it from src
* You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE]
*/
/datum/proc/_RemoveElement(list/arguments)
var/datum/element/ele = SSdcs.GetElement(arguments)
ele.Detach(src)
+1 -1
View File
@@ -141,7 +141,7 @@
/obj/item/clothing/head/mob_holder/dropped(mob/user)
. = ..()
if(held_mob && !ismob(loc))//don't release on soft-drops
if(held_mob && !ismob(loc) && !istype(loc,/obj/item/storage))//don't release on soft-drops
release()
/obj/item/clothing/head/mob_holder/proc/release()
+75
View File
@@ -0,0 +1,75 @@
/datum/element/turf_z_transparency
var/show_bottom_level = FALSE
///This proc sets up the signals to handle updating viscontents when turfs above/below update. Handle plane and layer here too so that they don't cover other obs/turfs in Dream Maker
/datum/element/turf_z_transparency/Attach(datum/target, show_bottom_level = TRUE)
. = ..()
if(!isturf(target))
return ELEMENT_INCOMPATIBLE
var/turf/our_turf = target
src.show_bottom_level = show_bottom_level
our_turf.plane = OPENSPACE_PLANE
our_turf.layer = OPENSPACE_LAYER
RegisterSignal(target, COMSIG_TURF_MULTIZ_DEL, .proc/on_multiz_turf_del)
RegisterSignal(target, COMSIG_TURF_MULTIZ_NEW, .proc/on_multiz_turf_new)
ADD_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, TURF_TRAIT)
update_multiz(our_turf, TRUE, TRUE)
/datum/element/turf_z_transparency/Detach(datum/source, force)
. = ..()
var/turf/our_turf = source
our_turf.vis_contents.len = 0
REMOVE_TRAIT(our_turf, TURF_Z_TRANSPARENT_TRAIT, TURF_TRAIT)
///Updates the viscontents or underlays below this tile.
/datum/element/turf_z_transparency/proc/update_multiz(turf/our_turf, prune_on_fail = FALSE, init = FALSE)
var/turf/below_turf = our_turf.below()
if(!below_turf)
our_turf.vis_contents.len = 0
if(!show_bottom_level(our_turf) && prune_on_fail) //If we cant show whats below, and we prune on fail, change the turf to plating as a fallback
our_turf.ChangeTurf(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
return FALSE
if(init)
our_turf.vis_contents += below_turf
if(isclosedturf(our_turf)) //Show girders below closed turfs
var/mutable_appearance/girder_underlay = mutable_appearance('icons/obj/structures.dmi', "girder", layer = TURF_LAYER-0.01)
girder_underlay.appearance_flags = RESET_ALPHA | RESET_COLOR
our_turf.underlays += girder_underlay
var/mutable_appearance/plating_underlay = mutable_appearance('icons/turf/floors.dmi', "plating", layer = TURF_LAYER-0.02)
plating_underlay = RESET_ALPHA | RESET_COLOR
our_turf.underlays += plating_underlay
return TRUE
/datum/element/turf_z_transparency/proc/on_multiz_turf_del(turf/our_turf, turf/T, dir)
SIGNAL_HANDLER
if(dir != DOWN)
return
update_multiz(our_turf)
/datum/element/turf_z_transparency/proc/on_multiz_turf_new(turf/our_turf, turf/T, dir)
SIGNAL_HANDLER
if(dir != DOWN)
return
update_multiz(our_turf)
///Called when there is no real turf below this turf
/datum/element/turf_z_transparency/proc/show_bottom_level(turf/our_turf)
if(!show_bottom_level)
return FALSE
var/turf/path = SSmapping.level_trait(our_turf.z, ZTRAIT_BASETURF) || /turf/open/space
if(!ispath(path))
path = text2path(path)
if(!ispath(path))
warning("Z-level [our_turf.z] has invalid baseturf '[SSmapping.level_trait(our_turf.z, ZTRAIT_BASETURF)]'")
path = /turf/open/space
var/mutable_appearance/underlay_appearance = mutable_appearance(initial(path.icon), initial(path.icon_state), layer = TURF_LAYER-0.02, plane = PLANE_SPACE)
underlay_appearance.appearance_flags = RESET_ALPHA | RESET_COLOR
our_turf.underlays += underlay_appearance
return TRUE
+2 -2
View File
@@ -34,13 +34,13 @@
. = ..()
UnregisterSignal(source, COMSIG_MOB_ATTACK_HAND)
/datum/element/wuv/proc/on_attack_hand(datum/source, mob/user)
/datum/element/wuv/proc/on_attack_hand(datum/source, mob/user, act_intent)
var/mob/living/L = source
if(L.stat == DEAD)
return
//we want to delay the effect to be displayed after the mob is petted, not before.
switch(user.a_intent)
switch(act_intent)
if(INTENT_HARM)
addtimer(CALLBACK(src, .proc/kick_the_dog, source, user), 1)
if(INTENT_HELP)
+2
View File
@@ -317,6 +317,8 @@ GLOBAL_LIST_EMPTY(explosions)
var/took = (REALTIMEOFDAY - started_at) / 10
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPLOSION,epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range)
//You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
if(GLOB.Debug2)
log_world("## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [took] seconds.")
+27 -9
View File
@@ -5,8 +5,8 @@
// effectout: effect to show right after teleportation
// asoundin: soundfile to play before teleportation
// asoundout: soundfile to play after teleportation
// no_effects: disable the default effectin/effectout of sparks
// forceMove: if false, teleport will use Move() proc (dense objects will prevent teleportation)
// no_effects: disable the default effectin/effectout of sparks
// forced: whether or not to ignore no_teleport
/proc/do_teleport(atom/movable/teleatom, atom/destination, precision=null, forceMove = TRUE, datum/effect_system/effectin=null, datum/effect_system/effectout=null, asoundin=null, asoundout=null, no_effects=FALSE, channel=TELEPORT_CHANNEL_BLUESPACE, forced = FALSE)
// teleporting most effects just deletes them
@@ -15,7 +15,8 @@
)) - typecacheof(list(
/obj/effect/dummy/chameleon,
/obj/effect/wisp,
/obj/effect/mob_spawn
/obj/effect/mob_spawn,
/obj/effect/immovablerod,
))
if(delete_atoms[teleatom.type])
qdel(teleatom)
@@ -66,7 +67,7 @@
var/area/A = get_area(curturf)
var/area/B = get_area(destturf)
if(!forced && (HAS_TRAIT(teleatom, TRAIT_NO_TELEPORT) || A.noteleport || B.noteleport))
if(!forced && (HAS_TRAIT(teleatom, TRAIT_NO_TELEPORT) || (A.area_flags & NOTELEPORT) || (B.area_flags & NOTELEPORT)))
return FALSE
if(SEND_SIGNAL(destturf, COMSIG_ATOM_INTERCEPT_TELEPORT, channel, curturf, destturf))
@@ -99,13 +100,13 @@
/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
if (location && !isobserver(teleatom))
if (sound)
playsound(location, sound, 60, 1)
playsound(location, sound, 60, TRUE)
if (effect)
effect.attach(location)
effect.start()
// Safe location finder
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE)
/proc/find_safe_turf(zlevel, list/zlevels, extended_safety_checks = FALSE, dense_atoms = TRUE)
if(!zlevels)
if (zlevel)
zlevels = list(zlevel)
@@ -122,12 +123,17 @@
if(!isfloorturf(random_location))
continue
var/turf/open/floor/F = random_location
var/area/destination_area = F.loc
if(cycle < 300 && destination_area.area_flags & NOTELEPORT)//if the area is mostly NOTELEPORT (centcom) we gotta give up on this fantasy at some point.
continue
if(!F.air)
continue
var/datum/gas_mixture/A = F.air
var/list/A_gases = A.get_gases()
var/trace_gases
for(var/id in A.get_gases())
for(var/id in A_gases)
if(id in GLOB.hardcoded_gases)
continue
trace_gases = TRUE
@@ -136,7 +142,7 @@
// Can most things breathe?
if(trace_gases)
continue
if(A.get_moles(/datum/gas/oxygen) < 16)
if(A.get_moles(/datum/gas/oxygen) >= 16)
continue
if(A.get_moles(/datum/gas/plasma))
continue
@@ -156,6 +162,16 @@
if(!L.is_safe())
continue
// Check that we're not warping onto a table or window
if(!dense_atoms)
var/density_found = FALSE
for(var/atom/movable/found_movable in F)
if(found_movable.density)
density_found = TRUE
break
if(density_found)
continue
// DING! You have passed the gauntlet, and are "probably" safe.
return F
@@ -167,9 +183,11 @@
if(T.is_transition_turf())
continue // Avoid picking these.
var/area/A = T.loc
if(!A.noteleport)
if(!(A.area_flags & NOTELEPORT))
posturfs.Add(T)
return posturfs
/proc/get_teleport_turf(turf/center, precision = 0)
return safepick(get_teleport_turfs(center, precision))
var/list/turfs = get_teleport_turfs(center, precision)
if (length(turfs))
return pick(turfs)
+144
View File
@@ -0,0 +1,144 @@
/datum/map_generator/cave_generator
var/name = "Cave Generator"
///Weighted list of the types that spawns if the turf is open
var/open_turf_types = list(/turf/open/floor/plating/asteroid/airless = 1)
///Weighted list of the types that spawns if the turf is closed
var/closed_turf_types = list(/turf/closed/mineral/random = 1)
///Weighted list of mobs that can spawn in the area.
var/list/mob_spawn_list
// Weighted list of Megafauna that can spawn in the caves
var/list/megafauna_spawn_list
///Weighted list of flora that can spawn in the area.
var/list/flora_spawn_list
///Weighted list of extra features that can spawn in the area, such as geysers.
var/list/feature_spawn_list
///Base chance of spawning a mob
var/mob_spawn_chance = 6
///Base chance of spawning flora
var/flora_spawn_chance = 2
///Base chance of spawning features
var/feature_spawn_chance = 0.1
///Unique ID for this spawner
var/string_gen
///Chance of cells starting closed
var/initial_closed_chance = 45
///Amount of smoothing iterations
var/smoothing_iterations = 20
///How much neighbours does a dead cell need to become alive
var/birth_limit = 4
///How little neighbours does a alive cell need to die
var/death_limit = 3
/datum/map_generator/cave_generator/New()
. = ..()
if(!mob_spawn_list)
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goldgrub = 1, /mob/living/simple_animal/hostile/asteroid/goliath = 5, /mob/living/simple_animal/hostile/asteroid/basilisk = 4, /mob/living/simple_animal/hostile/asteroid/hivelord = 3)
if(!megafauna_spawn_list)
megafauna_spawn_list = GLOB.megafauna_spawn_list
if(!flora_spawn_list)
flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2)
if(!feature_spawn_list)
feature_spawn_list = list(/obj/structure/geyser/random = 1)
/datum/map_generator/cave_generator/generate_terrain(list/turfs)
. = ..()
var/start_time = REALTIMEOFDAY
string_gen = rustg_cnoise_generate("[initial_closed_chance]", "[smoothing_iterations]", "[birth_limit]", "[death_limit]", "[world.maxx]", "[world.maxy]") //Generate the raw CA data
for(var/i in turfs) //Go through all the turfs and generate them
var/turf/gen_turf = i
var/area/A = gen_turf.loc
if(!(A.area_flags & CAVES_ALLOWED))
continue
var/closed = text2num(string_gen[world.maxx * (gen_turf.y - 1) + gen_turf.x])
var/stored_flags
if(gen_turf.flags_1 & NO_RUINS_1)
stored_flags |= NO_RUINS_1
var/turf/new_turf = pickweight(closed ? closed_turf_types : open_turf_types)
new_turf = gen_turf.ChangeTurf(new_turf, initial(new_turf.baseturfs), CHANGETURF_DEFER_CHANGE)
new_turf.flags_1 |= stored_flags
if(!closed)//Open turfs have some special behavior related to spawning flora and mobs.
var/turf/open/new_open_turf = new_turf
///Spawning isn't done in procs to save on overhead on the 60k turfs we're going through.
//FLORA SPAWNING HERE
var/atom/spawned_flora
if(flora_spawn_list && prob(flora_spawn_chance))
var/can_spawn = TRUE
if(!(A.area_flags & FLORA_ALLOWED))
can_spawn = FALSE
if(can_spawn)
spawned_flora = pickweight(flora_spawn_list)
spawned_flora = new spawned_flora(new_open_turf)
//FEATURE SPAWNING HERE
var/atom/spawned_feature
if(feature_spawn_list && prob(feature_spawn_chance))
var/can_spawn = TRUE
if(!(A.area_flags & FLORA_ALLOWED)) //checks the same flag because lol dunno
can_spawn = FALSE
var/atom/picked_feature = pickweight(feature_spawn_list)
for(var/obj/structure/F in range(7, new_open_turf))
if(istype(F, picked_feature))
can_spawn = FALSE
if(can_spawn)
spawned_feature = new picked_feature(new_open_turf)
//MOB SPAWNING HERE
if(mob_spawn_list && !spawned_flora && !spawned_feature && prob(mob_spawn_chance))
var/can_spawn = TRUE
if(!(A.area_flags & MOB_SPAWN_ALLOWED))
can_spawn = FALSE
var/atom/picked_mob = pickweight(mob_spawn_list)
if(picked_mob == SPAWN_MEGAFAUNA) //
if((A.area_flags & MEGAFAUNA_SPAWN_ALLOWED) && megafauna_spawn_list?.len) //this is danger. it's boss time.
picked_mob = pickweight(megafauna_spawn_list)
else //this is not danger, don't spawn a boss, spawn something else
picked_mob = pickweight(mob_spawn_list - SPAWN_MEGAFAUNA) //What if we used 100% of the brain...and did something (slightly) less shit than a while loop?
for(var/thing in urange(12, new_open_turf)) //prevents mob clumps
if(!ishostile(thing) && !istype(thing, /obj/structure/spawner))
continue
if((ispath(picked_mob, /mob/living/simple_animal/hostile/megafauna) || ismegafauna(thing)) && get_dist(new_open_turf, thing) <= 7)
can_spawn = FALSE //if there's a megafauna within standard view don't spawn anything at all
break
if(ispath(picked_mob, /mob/living/simple_animal/hostile/asteroid) || istype(thing, /mob/living/simple_animal/hostile/asteroid))
can_spawn = FALSE //if the random is a standard mob, avoid spawning if there's another one within 12 tiles
break
if((ispath(picked_mob, /obj/structure/spawner/lavaland) || istype(thing, /obj/structure/spawner/lavaland)) && get_dist(new_open_turf, thing) <= 2)
can_spawn = FALSE //prevents tendrils spawning in each other's collapse range
break
if(can_spawn)
if(ispath(picked_mob, /mob/living/simple_animal/hostile/megafauna/bubblegum)) //there can be only one bubblegum, so don't waste spawns on it
megafauna_spawn_list.Remove(picked_mob)
new picked_mob(new_open_turf)
CHECK_TICK
var/message = "[name] finished in [(REALTIMEOFDAY - start_time)/10]s!"
to_chat(world, "<span class='boldannounce'>[message]</span>")
log_world(message)
@@ -0,0 +1,28 @@
/datum/map_generator/cave_generator/icemoon
open_turf_types = list(/turf/open/floor/plating/asteroid/snow/icemoon = 19, /turf/open/floor/plating/ice/icemoon = 1)
closed_turf_types = list(/turf/closed/mineral/random/snow = 1)
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/wolf = 50, /obj/structure/spawner/ice_moon = 3, \
/mob/living/simple_animal/hostile/asteroid/polarbear = 30, /obj/structure/spawner/ice_moon/polarbear = 3, \
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10, \
/mob/living/simple_animal/hostile/asteroid/lobstrosity = 15)
flora_spawn_list = list(/obj/structure/flora/tree/pine = 2, /obj/structure/flora/rock/icy = 2, /obj/structure/flora/rock/pile/icy = 2, /obj/structure/flora/grass/both = 6, /obj/structure/flora/ash = 2)
feature_spawn_list = list(/obj/structure/geyser/random = 1)
/datum/map_generator/cave_generator/icemoon/surface
flora_spawn_chance = 4
mob_spawn_list = null
initial_closed_chance = 53
birth_limit = 5
death_limit = 4
smoothing_iterations = 10
/datum/map_generator/cave_generator/icemoon/deep
closed_turf_types = list(/turf/closed/mineral/random/snow/underground = 1)
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/ice_demon = 50, /obj/structure/spawner/ice_moon/demonic_portal = 3, \
/mob/living/simple_animal/hostile/asteroid/ice_whelp = 30, /obj/structure/spawner/ice_moon/demonic_portal/ice_whelp = 3, \
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow = 50, /obj/structure/spawner/ice_moon/demonic_portal/snowlegion = 3, \
SPAWN_MEGAFAUNA = 2)
megafauna_spawn_list = list(/mob/living/simple_animal/hostile/megafauna/colossus = 1)
flora_spawn_list = list(/obj/structure/flora/rock/icy = 6, /obj/structure/flora/rock/pile/icy = 6, /obj/structure/flora/ash = 1)
@@ -0,0 +1,16 @@
/datum/map_generator/cave_generator/lavaland
open_turf_types = list(/turf/open/floor/plating/asteroid/basalt/lava_land_surface = 1)
closed_turf_types = list(/turf/closed/mineral/random/volcanic = 1)
mob_spawn_list = list(/mob/living/simple_animal/hostile/asteroid/goliath/beast/random = 50, /obj/structure/spawner/lavaland/goliath = 3, \
/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/random = 40, /obj/structure/spawner/lavaland = 2, \
/mob/living/simple_animal/hostile/asteroid/hivelord/legion/random = 30, /obj/structure/spawner/lavaland/legion = 3, \
SPAWN_MEGAFAUNA = 4, /mob/living/simple_animal/hostile/asteroid/goldgrub = 10)
flora_spawn_list = list(/obj/structure/flora/ash/leaf_shroom = 2 , /obj/structure/flora/ash/cap_shroom = 2 , /obj/structure/flora/ash/stem_shroom = 2 , /obj/structure/flora/ash/cacti = 1, /obj/structure/flora/ash/tall_shroom = 2)
feature_spawn_list = list(/obj/structure/geyser/random = 1)
initial_closed_chance = 45
smoothing_iterations = 50
birth_limit = 4
death_limit = 3
+91
View File
@@ -0,0 +1,91 @@
//the random offset applied to square coordinates, causes intermingling at biome borders
#define BIOME_RANDOM_SQUARE_DRIFT 2
/datum/map_generator/jungle_generator
///2D list of all biomes based on heat and humidity combos.
var/list/possible_biomes = list(
BIOME_LOW_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/plains,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/mudlands,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/mudlands,
BIOME_HIGH_HUMIDITY = /datum/biome/water
),
BIOME_LOWMEDIUM_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/plains,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/jungle,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle,
BIOME_HIGH_HUMIDITY = /datum/biome/mudlands
),
BIOME_HIGHMEDIUM_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/plains,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/plains,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle/deep,
BIOME_HIGH_HUMIDITY = /datum/biome/jungle
),
BIOME_HIGH_HEAT = list(
BIOME_LOW_HUMIDITY = /datum/biome/wasteland,
BIOME_LOWMEDIUM_HUMIDITY = /datum/biome/plains,
BIOME_HIGHMEDIUM_HUMIDITY = /datum/biome/jungle,
BIOME_HIGH_HUMIDITY = /datum/biome/jungle/deep
)
)
///Used to select "zoom" level into the perlin noise, higher numbers result in slower transitions
var/perlin_zoom = 65
///Seeds the rust-g perlin noise with a random number.
/datum/map_generator/jungle_generator/generate_terrain(list/turfs)
. = ..()
var/height_seed = rand(0, 50000)
var/humidity_seed = rand(0, 50000)
var/heat_seed = rand(0, 50000)
for(var/t in turfs) //Go through all the turfs and generate them
var/turf/gen_turf = t
var/drift_x = (gen_turf.x + rand(-BIOME_RANDOM_SQUARE_DRIFT, BIOME_RANDOM_SQUARE_DRIFT)) / perlin_zoom
var/drift_y = (gen_turf.y + rand(-BIOME_RANDOM_SQUARE_DRIFT, BIOME_RANDOM_SQUARE_DRIFT)) / perlin_zoom
var/height = text2num(rustg_noise_get_at_coordinates("[height_seed]", "[drift_x]", "[drift_y]"))
var/datum/biome/selected_biome
if(height <= 0.85) //If height is less than 0.85, we generate biomes based on the heat and humidity of the area.
var/humidity = text2num(rustg_noise_get_at_coordinates("[humidity_seed]", "[drift_x]", "[drift_y]"))
var/heat = text2num(rustg_noise_get_at_coordinates("[heat_seed]", "[drift_x]", "[drift_y]"))
var/heat_level //Type of heat zone we're in LOW-MEDIUM-HIGH
var/humidity_level //Type of humidity zone we're in LOW-MEDIUM-HIGH
switch(heat)
if(0 to 0.25)
heat_level = BIOME_LOW_HEAT
if(0.25 to 0.5)
heat_level = BIOME_LOWMEDIUM_HEAT
if(0.5 to 0.75)
heat_level = BIOME_HIGHMEDIUM_HEAT
if(0.75 to 1)
heat_level = BIOME_HIGH_HEAT
switch(humidity)
if(0 to 0.25)
humidity_level = BIOME_LOW_HUMIDITY
if(0.25 to 0.5)
humidity_level = BIOME_LOWMEDIUM_HUMIDITY
if(0.5 to 0.75)
humidity_level = BIOME_HIGHMEDIUM_HUMIDITY
if(0.75 to 1)
humidity_level = BIOME_HIGH_HUMIDITY
selected_biome = possible_biomes[heat_level][humidity_level]
else //Over 0.85; It's a mountain
selected_biome = /datum/biome/mountain
selected_biome = SSmapping.biomes[selected_biome] //Get the instance of this biome from SSmapping
selected_biome.generate_turf(gen_turf)
CHECK_TICK
/turf/open/genturf
name = "ungenerated turf"
desc = "If you see this, and you're not a ghost, yell at coders"
icon = 'icons/turf/debug.dmi'
icon_state = "genturf"
/area/mine/planetgeneration
name = "planet generation area"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
map_generator = /datum/map_generator/jungle_generator
+6
View File
@@ -0,0 +1,6 @@
///This type is responsible for any map generation behavior that is done in areas, override this to allow for area-specific map generation. This generation is ran by areas in initialize.
/datum/map_generator
///This proc will be ran by areas on Initialize, and provides the areas turfs as argument to allow for generation.
/datum/map_generator/proc/generate_terrain(list/turfs)
return
+53
View File
@@ -0,0 +1,53 @@
///This datum handles the transitioning from a turf to a specific biome, and handles spawning decorative structures and mobs.
/datum/biome
///Type of turf this biome creates
var/turf_type
///Chance of having a structure from the flora types list spawn
var/flora_density = 0
///Chance of having a mob from the fauna types list spawn
var/fauna_density = 0
///list of type paths of objects that can be spawned when the turf spawns flora
var/list/flora_types = list(/obj/structure/flora/grass/jungle)
///list of type paths of mobs that can be spawned when the turf spawns fauna
var/list/fauna_types = list()
///This proc handles the creation of a turf of a specific biome type
/datum/biome/proc/generate_turf(turf/gen_turf)
gen_turf.ChangeTurf(turf_type, null, CHANGETURF_DEFER_CHANGE)
if(length(fauna_types) && prob(fauna_density))
var/mob/fauna = pick(fauna_types)
new fauna(gen_turf)
if(length(flora_types) && prob(flora_density))
var/obj/structure/flora = pick(flora_types)
new flora(gen_turf)
/datum/biome/mudlands
// turf_type = /turf/open/floor/plating/dirt/jungle/dark
turf_type = /turf/open/floor/plating/dirt/jungle
flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/rock/jungle, /obj/structure/flora/rock/pile/largejungle)
flora_density = 3
/datum/biome/plains
// turf_type = /turf/open/floor/plating/grass/jungle
turf_type = /turf/open/floor/grass
flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/tree/jungle, /obj/structure/flora/rock/jungle, /obj/structure/flora/junglebush, /obj/structure/flora/junglebush/b, /obj/structure/flora/junglebush/c, /obj/structure/flora/junglebush/large, /obj/structure/flora/rock/pile/largejungle)
flora_density = 15
/datum/biome/jungle
// turf_type = /turf/open/floor/plating/grass/jungle
turf_type = /turf/open/floor/grass
flora_types = list(/obj/structure/flora/grass/jungle,/obj/structure/flora/grass/jungle/b, /obj/structure/flora/tree/jungle, /obj/structure/flora/rock/jungle, /obj/structure/flora/junglebush, /obj/structure/flora/junglebush/b, /obj/structure/flora/junglebush/c, /obj/structure/flora/junglebush/large, /obj/structure/flora/rock/pile/largejungle)
flora_density = 40
/datum/biome/jungle/deep
flora_density = 65
/datum/biome/wasteland
// turf_type = /turf/open/floor/plating/dirt/jungle/wasteland
turf_type = /turf/open/floor/plating/dirt/jungle
/datum/biome/water
turf_type = /turf/open/water/jungle
/datum/biome/mountain
turf_type = /turf/closed/mineral/random //jungle
+3 -2
View File
@@ -223,9 +223,10 @@
///Subtype of CQC. Only used for the chef.
/datum/martial_art/cqc/under_siege
name = "Close Quarters Cooking"
var/list/valid_areas = list(/area/service/kitchen)
///Prevents use if the cook is not in the kitchen.
/datum/martial_art/cqc/under_siege/can_use(mob/living/carbon/human/H) //this is used to make chef CQC only work in kitchen
if(!istype(get_area(H), /area/crew_quarters/kitchen))
/datum/martial_art/cqc/under_siege/can_use(mob/living/owner) //this is used to make chef CQC only work in kitchen
if(!is_type_in_list(get_area(owner), valid_areas))
return FALSE
return ..()
+2 -1
View File
@@ -52,7 +52,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
name = "diamond"
desc = "Highly pressurized carbon"
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
strength_modifier = 1.1
strength_modifier = 1.2
alpha = 132
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/diamond
@@ -85,6 +85,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
name = "plasma"
desc = "Isn't plasma a state of matter? Oh whatever."
color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
strength_modifier = 0.7
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
sheet_type = /obj/item/stack/sheet/mineral/plasma
value_per_unit = 0.1
+7 -8
View File
@@ -129,7 +129,7 @@
/datum/mutation/human/proc/get_spans()
return list()
/mob/living/carbon/proc/update_mutations_overlay()
/mob/living/proc/update_mutations_overlay()
return
/mob/living/carbon/human/update_mutations_overlay()
@@ -142,13 +142,12 @@
if(overlays_standing[CM.layer_used])
mut_overlay = overlays_standing[CM.layer_used]
var/mutable_appearance/V = CM.get_visual_indicator()
if(!mut_overlay.Find(V)) //either we lack the visual indicator or we have the wrong one
remove_overlay(CM.layer_used)
for(var/mutable_appearance/MA in CM.visual_indicators[CM.type])
mut_overlay.Remove(MA)
mut_overlay |= V
overlays_standing[CM.layer_used] = mut_overlay
apply_overlay(CM.layer_used)
remove_overlay(CM.layer_used) //trying to find its existence defeats the point because if cut_overlays is called it doesn't bother reloading it.
for(var/mutable_appearance/MA in CM.visual_indicators[CM.type])
mut_overlay.Remove(MA)
mut_overlay |= V
overlays_standing[CM.layer_used] = mut_overlay
apply_overlay(CM.layer_used)
/datum/mutation/human/proc/modify() //called when a genome is applied so we can properly update some stats without having to remove and reapply the mutation from someone
if(modified || !power || !owner)
+2 -2
View File
@@ -283,7 +283,7 @@
desc = "Allows a creature to voluntary discard a random appendage."
quality = POSITIVE
text_gain_indication = "<span class='notice'>Your joints feel loose.</span>"
instability = 30
instability = 20
power = /obj/effect/proc_holder/spell/self/self_amputation
energy_coeff = 1
@@ -316,7 +316,7 @@
return
var/obj/item/bodypart/BP = pick(parts)
BP.dismember()
BP.dismember(harmless=TRUE)
//spider webs
/datum/mutation/human/webbing
+1 -1
View File
@@ -261,7 +261,7 @@
desc = "The user's chemical balance is more robust."
quality = POSITIVE
text_gain_indication = "<span class='notice'>You feel stimmed.</span>"
difficulty = 16
difficulty = 18
/datum/mutation/human/paranoia
name = "Paranoia"
+4
View File
@@ -30,3 +30,7 @@
/datum/generecipe/hulk
required = "/datum/mutation/human/strong; /datum/mutation/human/radioactive"
result = HULK
/datum/generecipe/thermal
required = "/datum/mutation/human/nearsight; /datum/mutation/human/stimmed"
result = THERMAL
+1 -1
View File
@@ -1,6 +1,6 @@
/datum/mutation/human/radioactive
name = "Radioactivity"
desc = "A volatile mutation that causes the host to sent out deadly beta radiation. This affects both the hosts and their surroundings."
desc = "A volatile mutation that causes the host to send out deadly beta radiation. This affects both the hosts and their surroundings."
quality = NEGATIVE
text_gain_indication = "<span class='warning'>You can feel it in your bones!</span>"
time_coeff = 5
+3 -2
View File
@@ -42,7 +42,8 @@
difficulty = 18
text_gain_indication = "<span class='notice'>You can see the heat rising off of your skin...</span>"
time_coeff = 2
instability = 25
instability = 40
locked = TRUE
var/visionflag = TRAIT_THERMAL_VISION
/datum/mutation/human/thermal/on_acquiring(mob/living/carbon/human/owner)
@@ -63,7 +64,7 @@
name = "X Ray Vision"
desc = "A strange genome that allows the user to see between the spaces of walls." //actual x-ray would mean you'd constantly be blasting rads, wich might be fun for later //hmb
text_gain_indication = "<span class='notice'>The walls suddenly disappear!</span>"
instability = 35
instability = 50
locked = TRUE
visionflag = TRAIT_XRAY_VISION
+2 -2
View File
@@ -1,7 +1,7 @@
//Cold Resistance gives your entire body an orange halo, and makes you immune to the effects of vacuum and cold.
/datum/mutation/human/space_adaptation
name = "Space Adaptation"
desc = "A strange mutation that renders the host immune to the vacuum if space. Will still need an oxygen supply."
desc = "A strange mutation that renders the host immune to the vacuum of space. Will still need an oxygen supply."
quality = POSITIVE
difficulty = 16
text_gain_indication = "<span class='notice'>Your body feels warm!</span>"
@@ -11,7 +11,7 @@
/datum/mutation/human/space_adaptation/New(class_ = MUT_OTHER, timer, datum/mutation/human/copymut)
..()
if(!(type in visual_indicators))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "fire", -MUTATIONS_LAYER))
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "space_adapt", -MUTATIONS_LAYER))
/datum/mutation/human/space_adaptation/get_visual_indicator()
return visual_indicators[type][1]
+2 -2
View File
@@ -3,8 +3,8 @@
var/obj/item/sample_object
var/number
/datum/numbered_display/New(obj/item/sample, _number = 1)
/datum/numbered_display/New(obj/item/sample, _number = 1, datum/component/storage/parent)
if(!istype(sample))
qdel(src)
sample_object = sample
sample_object = new /obj/screen/storage/item_holder(null, parent, sample)
number = _number
+294 -57
View File
@@ -1,71 +1,185 @@
/**
* # Outfit datums
*
* This is a clean system of applying outfits to mobs, if you need to equip someone in a uniform
* this is the way to do it cleanly and properly.
*
* You can also specify an outfit datum on a job to have it auto equipped to the mob on join
*
* /mob/living/carbon/human/proc/equipOutfit(outfit) is the mob level proc to equip an outfit
* and you pass it the relevant datum outfit
*
* outfits can also be saved as json blobs downloadable by a client and then can be uploaded
* by that user to recreate the outfit, this is used by admins to allow for custom event outfits
* that can be restored at a later date
*/
/datum/outfit
///Name of the outfit (shows up in the equip admin verb)
var/name = "Naked"
var/uniform = null
var/suit = null
var/toggle_helmet = TRUE
var/back = null
var/belt = null
var/gloves = null
var/shoes = null
var/head = null
var/mask = null
var/neck = null
var/ears = null
var/glasses = null
/// Type path of item to go in the idcard slot
var/id = null
var/l_pocket = null
var/r_pocket = null
/// Type path of item to go in uniform slot
var/uniform = null
/// Type path of item to go in suit slot
var/suit = null
/**
* Type path of item to go in suit storage slot
*
* (make sure it's valid for that suit)
*/
var/suit_store = null
var/r_hand = null
/// Type path of item to go in back slot
var/back = null
/**
* list of items that should go in the backpack of the user
*
* Format of this list should be: list(path=count,otherpath=count)
*/
var/list/backpack_contents = null
/// Type path of item to go in belt slot
var/belt = null
/// Type path of item to go in ears slot
var/ears = null
/// Type path of item to go in the glasses slot
var/glasses = null
/// Type path of item to go in gloves slot
var/gloves = null
/// Type path of item to go in head slot
var/head = null
/// Type path of item to go in mask slot
var/mask = null
/// Type path of item to go in neck slot
var/neck = null
/// Type path of item to go in shoes slot
var/shoes = null
/// Type path of item for left pocket slot
var/l_pocket = null
/// Type path of item for right pocket slot
var/r_pocket = null
///Type path of item to go in the right hand
var/l_hand = null
var/internals_slot = null //ID of slot containing a gas tank
var/list/backpack_contents = null // In the list(path=count,otherpath=count) format
var/box // Internals box. Will be inserted at the start of backpack_contents
var/list/implants = null
//Type path of item to go in left hand
var/r_hand = null
/// Any clothing accessory item
var/accessory = null
var/can_be_admin_equipped = TRUE // Set to FALSE if your outfit requires runtime parameters
var/list/chameleon_extras //extra types for chameleon outfit changes, mostly guns
/// Internals box. Will be inserted at the start of backpack_contents
var/box
/**
* extra types for chameleon outfit changes, mostly guns
*
* Format of this list is (typepath, typepath, typepath)
*
* These are all added and returns in the list for get_chamelon_diguise_info proc
*/
var/list/chameleon_extras
/**
* Any implants the mob should start implanted with
*
* Format of this list is (typepath, typepath, typepath)
*/
var/list/implants = null
///ID of the slot containing a gas tank
var/internals_slot = null
/// Should the toggle helmet proc be called on the helmet during equip
var/toggle_helmet = TRUE
/// Any undershirt. While on humans it is a string, here we use paths to stay consistent with the rest of the equips.
var/datum/sprite_accessory/undershirt = null
/**
* Called at the start of the equip proc
*
* Override to change the value of the slots depending on client prefs, species and
* other such sources of change
*
* Extra Arguments
* * visualsOnly true if this is only for display (in the character setup screen)
*
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
*/
/datum/outfit/proc/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
//to be overridden for customization depending on client prefs,species etc
return
/**
* Called after the equip proc has finished
*
* All items are on the mob at this point, use this proc to toggle internals
* fiddle with id bindings and accesses etc
*
* Extra Arguments
* * visualsOnly true if this is only for display (in the character setup screen)
*
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
*/
/datum/outfit/proc/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
//to be overridden for toggling internals, id binding, access etc
return
/**
* Equips all defined types and paths to the mob passed in
*
* Extra Arguments
* * visualsOnly true if this is only for display (in the character setup screen)
*
* If visualsOnly is true, you can omit any work that doesn't visually appear on the character sprite
*/
/datum/outfit/proc/equip(mob/living/carbon/human/H, visualsOnly = FALSE, client/preference_source)
pre_equip(H, visualsOnly, preference_source)
//Start with uniform,suit,backpack for additional slots
if(uniform)
H.equip_to_slot_or_del(new uniform(H),SLOT_W_UNIFORM)
H.equip_to_slot_or_del(new uniform(H), SLOT_W_UNIFORM, TRUE)
if(suit)
H.equip_to_slot_or_del(new suit(H),SLOT_WEAR_SUIT)
H.equip_to_slot_or_del(new suit(H), SLOT_WEAR_SUIT, TRUE)
if(back)
H.equip_to_slot_or_del(new back(H),SLOT_BACK)
H.equip_to_slot_or_del(new back(H), SLOT_BACK, TRUE)
if(belt)
H.equip_to_slot_or_del(new belt(H),SLOT_BELT)
H.equip_to_slot_or_del(new belt(H), SLOT_BELT, TRUE)
if(gloves)
H.equip_to_slot_or_del(new gloves(H),SLOT_GLOVES)
H.equip_to_slot_or_del(new gloves(H), SLOT_GLOVES, TRUE)
if(shoes)
H.equip_to_slot_or_del(new shoes(H),SLOT_SHOES)
H.equip_to_slot_or_del(new shoes(H), SLOT_SHOES, TRUE)
if(head)
H.equip_to_slot_or_del(new head(H),SLOT_HEAD)
H.equip_to_slot_or_del(new head(H), SLOT_HEAD, TRUE)
if(mask)
H.equip_to_slot_or_del(new mask(H),SLOT_WEAR_MASK)
H.equip_to_slot_or_del(new mask(H), SLOT_WEAR_MASK, TRUE)
if(neck)
H.equip_to_slot_or_del(new neck(H),SLOT_NECK)
H.equip_to_slot_or_del(new neck(H), SLOT_NECK, TRUE)
if(ears)
H.equip_to_slot_or_del(new ears(H),SLOT_EARS)
H.equip_to_slot_or_del(new ears(H), SLOT_EARS, TRUE)
if(glasses)
H.equip_to_slot_or_del(new glasses(H),SLOT_GLASSES)
H.equip_to_slot_or_del(new glasses(H), SLOT_GLASSES, TRUE)
if(id)
H.equip_to_slot_or_del(new id(H),SLOT_WEAR_ID)
H.equip_to_slot_or_del(new id(H), SLOT_WEAR_ID, TRUE)
if(suit_store)
H.equip_to_slot_or_del(new suit_store(H),SLOT_S_STORE)
H.equip_to_slot_or_del(new suit_store(H), SLOT_S_STORE, TRUE)
if(undershirt)
H.undershirt = initial(undershirt.name)
if(accessory)
var/obj/item/clothing/under/U = H.w_uniform
@@ -81,9 +195,9 @@
if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon.
if(l_pocket)
H.equip_to_slot_or_del(new l_pocket(H),SLOT_L_STORE)
H.equip_to_slot_or_del(new l_pocket(H), SLOT_L_STORE, TRUE)
if(r_pocket)
H.equip_to_slot_or_del(new r_pocket(H),SLOT_R_STORE)
H.equip_to_slot_or_del(new r_pocket(H), SLOT_R_STORE, TRUE)
if(box)
if(!backpack_contents)
@@ -97,7 +211,7 @@
if(!isnum(number))//Default to 1
number = 1
for(var/i in 1 to number)
H.equip_to_slot_or_del(new path(H),SLOT_IN_BACKPACK)
H.equip_to_slot_or_del(new path(H), SLOT_IN_BACKPACK, TRUE)
if(!H.head && toggle_helmet && istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit))
var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit
@@ -112,55 +226,178 @@
H.update_action_buttons_icon()
if(implants)
for(var/implant_type in implants)
var/obj/item/implant/I = new implant_type
var/obj/item/implant/I = new implant_type(H)
I.implant(H, null, TRUE)
H.update_body()
return TRUE
/**
* Apply a fingerprint from the passed in human to all items in the outfit
*
* Used for forensics setup when the mob is first equipped at roundstart
* essentially calls add_fingerprint to every defined item on the human
*
*/
/datum/outfit/proc/apply_fingerprints(mob/living/carbon/human/H)
if(!istype(H))
return
if(H.back)
H.back.add_fingerprint(H,1) //The 1 sets a flag to ignore gloves
H.back.add_fingerprint(H, ignoregloves = TRUE)
for(var/obj/item/I in H.back.contents)
I.add_fingerprint(H,1)
I.add_fingerprint(H, ignoregloves = TRUE)
if(H.wear_id)
H.wear_id.add_fingerprint(H,1)
H.wear_id.add_fingerprint(H, ignoregloves = TRUE)
if(H.w_uniform)
H.w_uniform.add_fingerprint(H,1)
H.w_uniform.add_fingerprint(H, ignoregloves = TRUE)
if(H.wear_suit)
H.wear_suit.add_fingerprint(H,1)
H.wear_suit.add_fingerprint(H, ignoregloves = TRUE)
if(H.wear_mask)
H.wear_mask.add_fingerprint(H,1)
H.wear_mask.add_fingerprint(H, ignoregloves = TRUE)
if(H.wear_neck)
H.wear_neck.add_fingerprint(H,1)
H.wear_neck.add_fingerprint(H, ignoregloves = TRUE)
if(H.head)
H.head.add_fingerprint(H,1)
H.head.add_fingerprint(H, ignoregloves = TRUE)
if(H.shoes)
H.shoes.add_fingerprint(H,1)
H.shoes.add_fingerprint(H, ignoregloves = TRUE)
if(H.gloves)
H.gloves.add_fingerprint(H,1)
H.gloves.add_fingerprint(H, ignoregloves = TRUE)
if(H.ears)
H.ears.add_fingerprint(H,1)
H.ears.add_fingerprint(H, ignoregloves = TRUE)
if(H.glasses)
H.glasses.add_fingerprint(H,1)
H.glasses.add_fingerprint(H, ignoregloves = TRUE)
if(H.belt)
H.belt.add_fingerprint(H,1)
H.belt.add_fingerprint(H, ignoregloves = TRUE)
for(var/obj/item/I in H.belt.contents)
I.add_fingerprint(H,1)
I.add_fingerprint(H, ignoregloves = TRUE)
if(H.s_store)
H.s_store.add_fingerprint(H,1)
H.s_store.add_fingerprint(H, ignoregloves = TRUE)
if(H.l_store)
H.l_store.add_fingerprint(H,1)
H.l_store.add_fingerprint(H, ignoregloves = TRUE)
if(H.r_store)
H.r_store.add_fingerprint(H,1)
H.r_store.add_fingerprint(H, ignoregloves = TRUE)
for(var/obj/item/I in H.held_items)
I.add_fingerprint(H,1)
return 1
I.add_fingerprint(H, ignoregloves = TRUE)
return TRUE
/// Return a list of all the types that are required to disguise as this outfit type
/datum/outfit/proc/get_chameleon_disguise_info()
var/list/types = list(uniform, suit, back, belt, gloves, shoes, head, mask, neck, ears, glasses, id, l_pocket, r_pocket, suit_store, r_hand, l_hand)
types += chameleon_extras
listclearnulls(types)
return types
/// Return a json list of this outfit
/datum/outfit/proc/get_json_data()
. = list()
.["outfit_type"] = type
.["name"] = name
.["uniform"] = uniform
.["suit"] = suit
.["toggle_helmet"] = toggle_helmet
.["back"] = back
.["belt"] = belt
.["gloves"] = gloves
.["shoes"] = shoes
.["head"] = head
.["mask"] = mask
.["neck"] = neck
.["ears"] = ears
.["glasses"] = glasses
.["id"] = id
.["l_pocket"] = l_pocket
.["r_pocket"] = r_pocket
.["suit_store"] = suit_store
.["r_hand"] = r_hand
.["l_hand"] = l_hand
.["internals_slot"] = internals_slot
.["backpack_contents"] = backpack_contents
.["box"] = box
.["implants"] = implants
.["accessory"] = accessory
/// Copy most vars from another outfit to this one
/datum/outfit/proc/copy_from(datum/outfit/target)
name = target.name
uniform = target.uniform
suit = target.suit
toggle_helmet = target.toggle_helmet
back = target.back
belt = target.belt
gloves = target.gloves
shoes = target.shoes
head = target.head
mask = target.mask
neck = target.neck
ears = target.ears
glasses = target.glasses
id = target.id
l_pocket = target.l_pocket
r_pocket = target.r_pocket
suit_store = target.suit_store
r_hand = target.r_hand
l_hand = target.l_hand
internals_slot = target.internals_slot
backpack_contents = target.backpack_contents
box = target.box
implants = target.implants
accessory = target.accessory
/// Prompt the passed in mob client to download this outfit as a json blob
/datum/outfit/proc/save_to_file(mob/admin)
var/stored_data = get_json_data()
var/json = json_encode(stored_data)
//Kinda annoying but as far as i can tell you need to make actual file.
var/f = file("data/TempOutfitUpload")
fdel(f)
WRITE_FILE(f,json)
admin << ftp(f,"[name].json")
/// Create an outfit datum from a list of json data
/datum/outfit/proc/load_from(list/outfit_data)
//This could probably use more strict validation
name = outfit_data["name"]
uniform = text2path(outfit_data["uniform"])
suit = text2path(outfit_data["suit"])
toggle_helmet = outfit_data["toggle_helmet"]
back = text2path(outfit_data["back"])
belt = text2path(outfit_data["belt"])
gloves = text2path(outfit_data["gloves"])
shoes = text2path(outfit_data["shoes"])
head = text2path(outfit_data["head"])
mask = text2path(outfit_data["mask"])
neck = text2path(outfit_data["neck"])
ears = text2path(outfit_data["ears"])
glasses = text2path(outfit_data["glasses"])
id = text2path(outfit_data["id"])
l_pocket = text2path(outfit_data["l_pocket"])
r_pocket = text2path(outfit_data["r_pocket"])
suit_store = text2path(outfit_data["suit_store"])
r_hand = text2path(outfit_data["r_hand"])
l_hand = text2path(outfit_data["l_hand"])
internals_slot = outfit_data["internals_slot"]
var/list/backpack = outfit_data["backpack_contents"]
backpack_contents = list()
for(var/item in backpack)
var/itype = text2path(item)
if(itype)
backpack_contents[itype] = backpack[item]
box = text2path(outfit_data["box"])
var/list/impl = outfit_data["implants"]
implants = list()
for(var/I in impl)
var/imptype = text2path(I)
if(imptype)
implants += imptype
accessory = text2path(outfit_data["accessory"])
return TRUE
/datum/outfit/vv_get_dropdown()
. = ..()
VV_DROPDOWN_OPTION("", "---")
VV_DROPDOWN_OPTION(VV_HK_TO_OUTFIT_EDITOR, "Outfit Editor")
/datum/outfit/vv_do_topic(list/href_list)
. = ..()
if(href_list[VV_HK_TO_OUTFIT_EDITOR])
usr.client.open_outfit_editor(src)
+2 -2
View File
@@ -108,7 +108,7 @@
/datum/status_effect/off_balance/on_remove()
var/active_item = owner.get_active_held_item()
if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
if(active_item)
owner.visible_message("<span class='warning'>[owner.name] regains their grip on \the [active_item]!</span>", "<span class='warning'>You regain your grip on \the [active_item]</span>", null, COMBAT_MESSAGE_RANGE)
return ..()
@@ -160,7 +160,7 @@
/obj/screen/alert/status_effect/mesmerized
name = "Mesmerized"
desc = "You cant tear your sight from who is in front of you... their gaze is simply too enthralling.."
desc = "You can't tear your sight from who is in front of you... their gaze is simply too enthralling.."
icon = 'icons/mob/actions/bloodsucker.dmi'
icon_state = "power_mez"
@@ -18,7 +18,7 @@
area_type = /area
protected_areas = list(/area/maintenance, /area/ai_monitored/turret_protected/ai_upload, /area/ai_monitored/turret_protected/ai_upload_foyer,
/area/ai_monitored/turret_protected/ai, /area/storage/emergency/starboard, /area/storage/emergency/port, /area/shuttle, /area/security/prison, /area/ruin, /area/space/nearstation, /area/icemoon)
/area/ai_monitored/turret_protected/ai, /area/commons/storage/emergency/starboard, /area/commons/storage/emergency/port, /area/shuttle, /area/security/prison/safe, /area/security/prison/toilet)
target_trait = ZTRAIT_STATION
immunity_type = "rad"