This commit is contained in:
Ghommie
2020-05-07 22:14:11 +02:00
180 changed files with 278040 additions and 674 deletions

View File

@@ -161,10 +161,14 @@
#define ATMOS_TANK_O2 "o2=100000;TEMP=293.15"
#define ATMOS_TANK_N2 "n2=100000;TEMP=293.15"
#define ATMOS_TANK_AIRMIX "o2=2644;n2=10580;TEMP=293.15"
//LAVALAND
#define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland
#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300"
//SNOSTATION
#define ICEMOON_DEFAULT_ATMOS "o2=17;n2=63;TEMP=180"
//ATMOSIA GAS MONITOR TAGS
#define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in"
#define ATMOS_GAS_MONITOR_OUTPUT_O2 "o2_out"
@@ -255,10 +259,10 @@
//HELPERS
#define PIPING_LAYER_SHIFT(T, PipingLayer) \
if(T.dir & NORTH || T.dir & SOUTH) { \
if(T.dir & (NORTH|SOUTH)) { \
T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
} \
if(T.dir & WEST || T.dir & EAST) { \
if(T.dir & (WEST|EAST)) { \
T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;\
}

View File

@@ -59,8 +59,6 @@
//let's just pretend fulltile windows being children of border windows is fine
#define FULLTILE_WINDOW_DIR NORTHEAST
//The amount of materials you get from a sheet of mineral like iron/diamond/glass etc
#define MINERAL_MATERIAL_AMOUNT 2000
//The maximum size of a stack object.
#define MAX_STACK_SIZE 50
//maximum amount of cable in a coil

View File

@@ -110,7 +110,8 @@
#define COMSIG_TURF_MULTIZ_NEW "turf_multiz_new" //from base of turf/New(): (turf/source, direction)
// /atom/movable signals
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" //from base of atom/movable/Moved(): (/atom)
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move" ///from base of atom/movable/Moved(): (/atom)
#define COMPONENT_MOVABLE_BLOCK_PRE_MOVE 1
#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
#define COMSIG_MOVABLE_CROSS "movable_cross" //from base of atom/movable/Cross(): (/atom/movable)
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)

View File

@@ -174,7 +174,10 @@ GLOBAL_LIST_INIT(clawfootmob, typecacheof(list(
/mob/living/simple_animal/pet/fox,
/mob/living/simple_animal/chicken,
/mob/living/simple_animal/hostile/bear,
/mob/living/simple_animal/hostile/jungle/mega_arachnid
/mob/living/simple_animal/hostile/jungle/mega_arachnid,
/mob/living/simple_animal/hostile/asteroid/ice_whelp,
/mob/living/simple_animal/hostile/asteroid/wolf,
/mob/living/simple_animal/hostile/asteroid/polarbear
)))
GLOBAL_LIST_INIT(barefootmob, typecacheof(list(

View File

@@ -0,0 +1,3 @@
//map template annihilate_bounds
#define MAP_TEMPLATE_ANNIHILATE_PRELOAD 1 //annihilate bounds before starting loading
#define MAP_TEMPLATE_ANNIHILATE_LOADING 2 //"sweeping" delete during loading

View File

@@ -38,8 +38,15 @@ require only minor tweaks.
#define ZTRAIT_VR "Virtual Reality"
#define ZTRAIT_SPACE_RUINS "Space Ruins"
#define ZTRAIT_LAVA_RUINS "Lava Ruins"
#define ZTRAIT_ICE_RUINS "Ice Ruins"
#define ZTRAIT_ICE_RUINS_UNDERGROUND "Ice Ruins Underground"
#define ZTRAIT_ISOLATED_RUINS "Isolated Ruins" //Placing ruins on z levels with this trait will use turf reservation instead of usual placement.
//boolean - weather types that occur on the level
#define ZTRAIT_SNOWSTORM "Weather_Snowstorm"
#define ZTRAIT_ASHSTORM "Weather_Ashstorm"
#define ZTRAIT_ACIDRAIN "Weather_Acidrain"
// number - bombcap is multiplied by this before being applied to bombs
#define ZTRAIT_BOMBCAP_MULTIPLIER "Bombcap Multiplier"
@@ -68,6 +75,7 @@ require only minor tweaks.
#define ZTRAITS_SPACE list(ZTRAIT_LINKAGE = CROSSLINKED, ZTRAIT_SPACE_RUINS = TRUE)
#define ZTRAITS_LAVALAND list(\
ZTRAIT_MINING = TRUE, \
ZTRAIT_ASHSTORM = TRUE, \
ZTRAIT_LAVA_RUINS = TRUE, \
ZTRAIT_BOMBCAP_MULTIPLIER = 5, \
ZTRAIT_BASETURF = /turf/open/lava/smooth/lava_land_surface)

View File

@@ -0,0 +1,2 @@
/// cm3 of material matter per sheet
#define MINERAL_MATERIAL_AMOUNT 2000

View File

@@ -265,6 +265,7 @@
#define WIZARD_AGE_MIN 30 //youngest a wizard can be
#define APPRENTICE_AGE_MIN 29 //youngest an apprentice can be
#define SHOES_SLOWDOWN 0 //How much shoes slow you down by default. Negative values speed you up
#define SHOES_SPEED_SLIGHT SHOES_SLOWDOWN - 1 // slightest speed boost to movement
#define POCKET_STRIP_DELAY 40 //time taken (in deciseconds) to search somebody's pockets
#define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you
@@ -288,10 +289,8 @@
#define HUMAN_FIRE_STACK_ICON_NUM 3
#define PULL_PRONE_SLOWDOWN 0.6
#define FIREMAN_CARRY_SLOWDOWN 0
#define PIGGYBACK_CARRY_SLOWDOWN 1
//slowdown when in softcrit. Note that crawling slowdown will also apply at the same time!
#define SOFTCRIT_ADD_SLOWDOWN 2
//slowdown when crawling
#define CRAWLING_ADD_SLOWDOWN 4
#define GRAB_PIXEL_SHIFT_PASSIVE 6
#define GRAB_PIXEL_SHIFT_AGGRESSIVE 12
#define GRAB_PIXEL_SHIFT_NECK 16
#define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return;

View File

@@ -0,0 +1,10 @@
/// How much someone is slowed from pulling a prone human
#define PULL_PRONE_SLOWDOWN 0.6
/// How much someone is slowed from fireman carrying a human
#define FIREMAN_CARRY_SLOWDOWN 0
/// How much someone is slowed by piggybacking a human
#define PIGGYBACK_CARRY_SLOWDOWN 1
/// slowdown when in softcrit. Note that crawling slowdown will also apply at the same time!
#define SOFTCRIT_ADD_SLOWDOWN 2
/// slowdown when crawling
#define CRAWLING_ADD_SLOWDOWN 4

View File

@@ -38,11 +38,12 @@
#define BLOCK_GAS_SMOKE_EFFECT (1<<2) //blocks the effect that chemical clouds would have on a mob --glasses, mask and helmets ONLY!
#define ALLOWINTERNALS (1<<3) //mask allows internals
#define NOSLIP (1<<4) //prevents from slipping on wet floors, in space etc
#define THICKMATERIAL (1<<5) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
#define VOICEBOX_TOGGLABLE (1<<6) //The voicebox in this clothing can be toggled.
#define VOICEBOX_DISABLED (1<<7) //The voicebox is currently turned off.
#define IGNORE_HAT_TOSS (1<<8) //Hats with negative effects when worn (i.e the tinfoil hat).
#define SCAN_REAGENTS (1<<9) // Allows helmets and glasses to scan reagents.
#define NOSLIP_ICE (1<<5) //prevents from slipping on frozen floors
#define THICKMATERIAL (1<<6) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body.
#define VOICEBOX_TOGGLABLE (1<<7) //The voicebox in this clothing can be toggled.
#define VOICEBOX_DISABLED (1<<8) //The voicebox is currently turned off.
#define IGNORE_HAT_TOSS (1<<9) //Hats with negative effects when worn (i.e the tinfoil hat).
#define SCAN_REAGENTS (1<<10) // Allows helmets and glasses to scan reagents.
// Flags for the organ_flags var on /obj/item/organ

View File

@@ -65,6 +65,7 @@
#define FREQ_ENGINEERING 1357 // Engineering comms frequency, orange
#define FREQ_SECURITY 1359 // Security comms frequency, red
#define FREQ_HOLOGRID_SOLUTION 1433
#define FREQ_STATUS_DISPLAYS 1435
#define FREQ_ATMOS_ALARMS 1437 // air alarms <-> alert computers
#define FREQ_ATMOS_CONTROL 1439 // air alarms <-> vents and scrubbers

View File

@@ -0,0 +1,5 @@
// the clamps are just sanity checks.
/// Efficiency scaling for stock part level to material usage. All code concerning lathing and production from raw material sheet should be using this.
#define STANDARD_PART_LEVEL_LATHE_COEFFICIENT(level) clamp(1 - (level * 0.1), 0, 1)
/// Efficiency scaling for stock part level to ore factor. All code concerning lathing and production from raw ores to raw material sheets should be using this.
#define STANDARD_PART_LEVEL_ORE_COEFFICIENT(level) clamp(1 + (level * 0.125), 1, 10)

View File

@@ -80,7 +80,7 @@
#define STATUS_EFFECT_CRUSHERMARK /datum/status_effect/crusher_mark //if struck with a proto-kinetic crusher, takes a ton of damage
#define STATUS_EFFECT_SAWBLEED /datum/status_effect/saw_bleed //if the bleed builds up enough, takes a ton of damage
#define STATUS_EFFECT_SAWBLEED /datum/status_effect/stacking/saw_bleed //if the bleed builds up enough, takes a ton of damage
#define STATUS_EFFECT_NECKSLICE /datum/status_effect/neck_slice //Creates the flavor messages for the neck-slice

View File

@@ -58,6 +58,11 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
else if(isarea(areatype))
var/area/areatemp = areatype
areatype = areatemp.type
else if(islist(areatype))
var/list/turfs = list()
for(var/A in areatype)
turfs += get_area_turfs(A)
return turfs
else if(!ispath(areatype))
return null

View File

@@ -163,9 +163,11 @@
"tail_lizard" = pick(GLOB.tails_list_lizard),
"tail_human" = "None",
"wings" = "None",
"wings_color" = "FFF",
"deco_wings" = "None",
"snout" = pick(GLOB.snouts_list),
"horns" = pick(GLOB.horns_list),
"horns" = "None",
"horns_color" = "85615a",
"ears" = "None",
"frills" = pick(GLOB.frills_list),
"spines" = pick(GLOB.spines_list),
@@ -174,7 +176,7 @@
"caps" = pick(GLOB.caps_list),
"insect_wings" = pick(GLOB.insect_wings_list),
"insect_fluff" = "None",
"insect_markings" = pick(GLOB.insect_markings_list),
"insect_markings" = pick(GLOB.insect_markings_list),
"taur" = "None",
"mam_body_markings" = snowflake_markings_list.len ? pick(snowflake_markings_list) : "None",
"mam_ears" = snowflake_ears_list ? pick(snowflake_ears_list) : "None",

View File

@@ -434,6 +434,29 @@ Turf and target are separate in case you want to teleport some distance from a t
return locate(x,y,A.z)
/**
* Get ranged target turf, but with direct targets as opposed to directions
*
* Starts at atom A and gets the exact angle between A and target
* Moves from A with that angle, Range amount of times, until it stops, bound to map size
* Arguments:
* * A - Initial Firer / Position
* * target - Target to aim towards
* * range - Distance of returned target turf from A
* * offset - Angle offset, 180 input would make the returned target turf be in the opposite direction
*/
/proc/get_ranged_target_turf_direct(atom/A, atom/target, range, offset)
var/angle = arctan(target.x - A.x, target.y - A.y)
if(offset)
angle += offset
var/turf/T = get_turf(A)
for(var/i in 1 to range)
var/turf/check = locate(A.x + cos(angle) * i, A.y + sin(angle) * i, A.z)
if(!check)
break
T = check
return T
// returns turf relative to A offset in dx and dy tiles
// bound to map limits

View File

@@ -162,7 +162,7 @@
#define ui_ghost_orbit "SOUTH:6,CENTER-1:24"
#define ui_ghost_reenter_corpse "SOUTH:6,CENTER:24"
#define ui_ghost_teleport "SOUTH:6,CENTER+1:24"
#define ui_ghost_pai "SOUTH: 6, CENTER+2:24"
#define ui_ghost_spawners "SOUTH: 6, CENTER+2:24"
//UI position overrides for 1:1 screen layout. (default is 7:5)

View File

@@ -36,13 +36,13 @@
var/mob/dead/observer/G = usr
G.dead_tele()
/obj/screen/ghost/pai
name = "pAI Candidate"
icon_state = "pai"
/obj/screen/ghost/spawners
name = "Ghost role spawners"
icon_state = "spawners"
/obj/screen/ghost/pai/Click()
/obj/screen/ghost/spawners/Click()
var/mob/dead/observer/G = usr
G.register_pai()
G.open_spawners_menu()
/datum/hud/ghost/New(mob/owner)
..()
@@ -68,8 +68,8 @@
using.hud = src
static_inventory += using
using = new /obj/screen/ghost/pai()
using.screen_loc = ui_ghost_pai
using = new /obj/screen/ghost/spawners()
using.screen_loc = ui_ghost_spawners
using.hud = src
static_inventory += using

View File

@@ -348,6 +348,11 @@
config_entry_value = 16
min_val = 0
/datum/config_entry/number/icemoon_budget
config_entry_value = 90
integer = FALSE
min_val = 0
/datum/config_entry/number/station_space_budget
config_entry_value = 10
min_val = 0

View File

@@ -16,6 +16,8 @@ SUBSYSTEM_DEF(mapping)
var/list/ruins_templates = list()
var/list/space_ruins_templates = list()
var/list/lava_ruins_templates = list()
var/list/ice_ruins_templates = list()
var/list/ice_ruins_underground_templates = list()
var/list/station_ruins_templates = list()
var/datum/space_level/isolated_ruins_z //Created on demand during ruin loading.
@@ -102,19 +104,32 @@ SUBSYSTEM_DEF(mapping)
loading_ruins = TRUE
var/list/lava_ruins = levels_by_trait(ZTRAIT_LAVA_RUINS)
if (lava_ruins.len)
seedRuins(lava_ruins, CONFIG_GET(number/lavaland_budget), /area/lavaland/surface/outdoors/unexplored, lava_ruins_templates)
seedRuins(lava_ruins, CONFIG_GET(number/lavaland_budget), list(/area/lavaland/surface/outdoors/unexplored), lava_ruins_templates)
for (var/lava_z in lava_ruins)
spawn_rivers(lava_z)
var/list/ice_ruins = levels_by_trait(ZTRAIT_ICE_RUINS)
if (ice_ruins.len)
// needs to be whitelisted for underground too so place_below ruins work
seedRuins(ice_ruins, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored), ice_ruins_templates)
for (var/ice_z in ice_ruins)
spawn_rivers(ice_z, 4, /turf/open/openspace/icemoon, /area/icemoon/surface/outdoors/unexplored/rivers)
var/list/ice_ruins_underground = levels_by_trait(ZTRAIT_ICE_RUINS_UNDERGROUND)
if (ice_ruins_underground.len)
seedRuins(ice_ruins_underground, CONFIG_GET(number/icemoon_budget), list(/area/icemoon/underground/unexplored), ice_ruins_underground_templates)
for (var/ice_z in ice_ruins_underground)
spawn_rivers(ice_z, 4, level_trait(ice_z, ZTRAIT_BASETURF), /area/icemoon/underground/unexplored/rivers)
// Generate deep space ruins
var/list/space_ruins = levels_by_trait(ZTRAIT_SPACE_RUINS)
if (space_ruins.len)
seedRuins(space_ruins, CONFIG_GET(number/space_budget), /area/space, space_ruins_templates)
seedRuins(space_ruins, CONFIG_GET(number/space_budget), list(/area/space), space_ruins_templates)
// Generate station space ruins
var/list/station_ruins = levels_by_trait(ZTRAIT_STATION)
if (station_ruins.len)
seedRuins(station_ruins, CONFIG_GET(number/station_space_budget), /area/space/station_ruins, station_ruins_templates)
seedRuins(station_ruins, (SSmapping.config.station_ruin_budget < 0) ? CONFIG_GET(number/station_space_budget) : SSmapping.config.station_ruin_budget, list(/area/space/station_ruins), station_ruins_templates)
SSmapping.seedStation()
loading_ruins = FALSE
#endif
@@ -182,6 +197,8 @@ SUBSYSTEM_DEF(mapping)
ruins_templates = SSmapping.ruins_templates
space_ruins_templates = SSmapping.space_ruins_templates
lava_ruins_templates = SSmapping.lava_ruins_templates
ice_ruins_templates = SSmapping.ice_ruins_templates
ice_ruins_underground_templates = SSmapping.ice_ruins_underground_templates
station_ruins_templates = SSmapping.station_ruins_templates
shuttle_templates = SSmapping.shuttle_templates
shelter_templates = SSmapping.shelter_templates
@@ -196,7 +213,7 @@ SUBSYSTEM_DEF(mapping)
z_list = SSmapping.z_list
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE)
/datum/controller/subsystem/mapping/proc/LoadGroup(list/errorList, name, path, files, list/traits, list/default_traits, silent = FALSE, orientation = SOUTH)
. = list()
var/start_time = REALTIMEOFDAY
@@ -236,7 +253,7 @@ SUBSYSTEM_DEF(mapping)
// load the maps
for (var/P in parsed_maps)
var/datum/parsed_map/pm = P
if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE))
if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE, orientation = orientation))
errorList |= pm.original_path
if(!silent)
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
@@ -252,7 +269,7 @@ SUBSYSTEM_DEF(mapping)
// load the station
station_start = world.maxz + 1
INIT_ANNOUNCE("Loading [config.map_name]...")
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION)
LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION, FALSE, config.orientation)
if(SSdbcore.Connect())
var/datum/DBQuery/query_round_map_name = SSdbcore.NewQuery("UPDATE [format_table_name("round")] SET map_name = '[config.map_name]' WHERE id = [GLOB.round_id]")
@@ -268,7 +285,7 @@ SUBSYSTEM_DEF(mapping)
// load mining
if(config.minetype == "lavaland")
LoadGroup(FailedZs, "Lavaland", "map_files/Mining", "Lavaland.dmm", default_traits = ZTRAITS_LAVALAND)
else if (!isnull(config.minetype))
else if (!isnull(config.minetype) && config.minetype != "none")
INIT_ANNOUNCE("WARNING: An unknown minetype '[config.minetype]' was set! This is being ignored! Update the maploader code!")
#endif
@@ -372,6 +389,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
// Still supporting bans by filename
var/list/banned = generateMapList("[global.config.directory]/lavaruinblacklist.txt")
banned += generateMapList("[global.config.directory]/spaceruinblacklist.txt")
banned += generateMapList("[global.config.directory]/iceruinblacklist.txt")
banned += generateMapList("[global.config.directory]/stationruinblacklist.txt")
for(var/item in sortList(subtypesof(/datum/map_template/ruin), /proc/cmp_ruincost_priority))
@@ -389,6 +407,10 @@ GLOBAL_LIST_EMPTY(the_station_areas)
if(istype(R, /datum/map_template/ruin/lavaland))
lava_ruins_templates[R.name] = R
else if(istype(R, /datum/map_template/ruin/icemoon/underground))
ice_ruins_underground_templates[R.name] = R
else if(istype(R, /datum/map_template/ruin/icemoon))
ice_ruins_templates[R.name] = R
else if(istype(R, /datum/map_template/ruin/space))
space_ruins_templates[R.name] = R
else if(istype(R, /datum/map_template/ruin/station))

View File

@@ -3,7 +3,6 @@ PROCESSING_SUBSYSTEM_DEF(projectiles)
wait = 1
stat_tag = "PP"
flags = SS_NO_INIT|SS_TICKER
var/global_max_tick_moves = 10
var/global_pixel_speed = 2
var/global_iterations_per_move = 16

View File

@@ -413,15 +413,6 @@
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
/datum/crafting_recipe/paperwork
name = "Filed Paper Work"
result = /obj/item/folder/paperwork_correct
time = 10 //Takes time for people to file and complete paper work!
tools = list(/obj/item/pen)
reqs = list(/obj/item/folder/paperwork = 1)
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
/datum/crafting_recipe/coconut_bong
name = "Coconut Bong"
result = /obj/item/bong/coconut

View File

@@ -1,13 +1,18 @@
/datum/component/knockback
/// distance the atom will be thrown
var/throw_distance
/// whether this can throw anchored targets (tables, etc)
var/throw_anchored
/// whether this is a gentle throw (default false means people thrown into walls are stunned / take damage)
var/throw_gentle
/datum/component/knockback/Initialize(throw_distance=1)
/datum/component/knockback/Initialize(throw_distance=1, throw_gentle=FALSE)
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent))
return COMPONENT_INCOMPATIBLE
src.throw_distance = throw_distance
src.throw_anchored = throw_anchored
src.throw_gentle = throw_gentle
/datum/component/knockback/RegisterWithParent()
. = ..()
@@ -22,17 +27,29 @@
. = ..()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/// triggered after an item attacks something
/datum/component/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return
do_knockback(target, user, get_dir(source, target))
/// triggered after a hostile simplemob attacks something
/datum/component/knockback/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target)
do_knockback(target, attacker, get_dir(attacker, target))
/// triggered after a projectile hits something
/datum/component/knockback/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
do_knockback(target, null, angle2dir(Angle))
/**
* Throw a target in a direction
*
* Arguments:
* * target - Target atom to throw
* * thrower - Thing that caused this atom to be thrown
* * throw_dir - Direction to throw the atom
*/
/datum/component/knockback/proc/do_knockback(atom/target, mob/thrower, throw_dir)
if(!ismovable(target) || throw_dir == null)
return
@@ -43,4 +60,4 @@
throw_dir = turn(throw_dir, 180)
throw_distance *= -1
var/atom/throw_target = get_edge_target_turf(throwee, throw_dir)
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower)
throwee.safe_throw_at(throw_target, throw_distance, 1, thrower) //, gentle = throw_gentle)

View File

@@ -20,6 +20,8 @@
var/ride_check_ridden_incapacitated = FALSE
var/list/offhands = list() // keyed list containing all the current riding offsets associated by mob
var/del_on_unbuckle_all = FALSE
/datum/component/riding/Initialize()
if(!ismovable(parent))
return COMPONENT_INCOMPATIBLE
@@ -28,8 +30,11 @@
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/vehicle_moved)
/datum/component/riding/proc/vehicle_mob_unbuckle(datum/source, mob/living/M, force = FALSE)
var/atom/movable/AM = parent
restore_position(M)
unequip_buckle_inhands(M)
if(del_on_unbuckle_all && !AM.has_buckled_mobs())
qdel(src)
/datum/component/riding/proc/vehicle_mob_buckle(datum/source, mob/living/M, force = FALSE)
handle_vehicle_offsets()
@@ -194,6 +199,7 @@
///////Yes, I said humans. No, this won't end well...//////////
/datum/component/riding/human
del_on_unbuckle_all = TRUE
var/fireman_carrying = FALSE
/datum/component/riding/human/Initialize()
@@ -261,6 +267,7 @@
user.visible_message("<span class='warning'>[AM] pushes [user] off of [AM.p_them()]!</span>")
/datum/component/riding/cyborg
del_on_unbuckle_all = TRUE
/datum/component/riding/cyborg/Initialize()
. = ..()

View File

@@ -1,28 +1,20 @@
/datum/element/dusts_on_leaving_area
element_flags = ELEMENT_DETACH | ELEMENT_BESPOKE
id_arg_index = 2
var/list/attached_mobs = list()
var/list/area_types = list()
/datum/element/dusts_on_leaving_area/Attach(datum/target,types)
. = ..()
if(!ismob(target))
return ELEMENT_INCOMPATIBLE
attached_mobs += target
area_types = types
START_PROCESSING(SSprocessing,src)
RegisterSignal(target,COMSIG_ENTER_AREA,.proc/check_dust)
/datum/element/dusts_on_leaving_area/Detach(mob/M)
. = ..()
if(M in attached_mobs)
attached_mobs -= M
if(!attached_mobs.len)
STOP_PROCESSING(SSprocessing,src)
UnregisterSignal(M,COMSIG_ENTER_AREA)
/datum/element/dusts_on_leaving_area/process()
for(var/m in attached_mobs)
var/mob/M = m
var/area/A = get_area(M)
if(!(A.type in area_types))
M.dust(force = TRUE)
Detach(M)
/datum/element/dusts_on_leaving_area/proc/check_dust(datum/source, area/A)
var/mob/M = source
if(istype(M) && !(A.type in area_types))
M.dust(force = TRUE)

View File

@@ -0,0 +1,31 @@
/datum/element/snailcrawl
element_flags = ELEMENT_DETACH
/datum/element/snailcrawl/Attach(datum/target)
. = ..()
if(!ismovable(target))
return ELEMENT_INCOMPATIBLE
var/P
if(iscarbon(target))
P = .proc/snail_crawl
else
P = .proc/lubricate
RegisterSignal(target, COMSIG_MOVABLE_MOVED, P)
/datum/element/snailcrawl/Detach(mob/living/carbon/target)
. = ..()
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
if(istype(target))
target.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
/datum/element/snailcrawl/proc/snail_crawl(mob/living/carbon/snail)
if(snail.resting && !snail.buckled && lubricate(snail))
snail.add_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
else
snail.remove_movespeed_modifier(/datum/movespeed_modifier/snail_crawl)
/datum/element/snailcrawl/proc/lubricate(atom/movable/snail)
var/turf/open/OT = get_turf(snail)
if(istype(OT))
OT.MakeSlippery(TURF_WET_LUBE, 20)
return TRUE

View File

@@ -0,0 +1,112 @@
// Hey! Listen! Update \config\iceruinblacklist.txt with your new ruins!
/datum/map_template/ruin/icemoon
prefix = "_maps/RandomRuins/IceRuins/"
allow_duplicates = FALSE
cost = 5
// above ground only
/datum/map_template/ruin/icemoon/lust
name = "Ruin of Lust"
id = "lust"
description = "Not exactly what you expected."
suffix = "icemoon_surface_lust.dmm"
/datum/map_template/ruin/icemoon/asteroid
name = "Asteroid Site"
id = "asteroidsite"
description = "Surprised to see us here?"
suffix = "icemoon_surface_asteroid.dmm"
/datum/map_template/ruin/icemoon/hotsprings
name = "Hot Springs"
id = "hotsprings"
description = "Just relax and take a dip, nothing will go wrong, I swear!"
suffix = "icemoon_surface_hotsprings.dmm"
/datum/map_template/ruin/icemoon/engioutpost
name = "Engineer Outpost"
id = "engioutpost"
description = "Blown up by an unfortunate accident."
suffix = "icemoon_surface_engioutpost.dmm"
/datum/map_template/ruin/icemoon/fountain
name = "Fountain Hall"
id = "fountain"
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "fountain_hall.dmm"
// above and below ground together
/datum/map_template/ruin/icemoon/mining_site
name = "Mining Site"
id = "miningsite"
description = "Ruins of a site where people once mined with primitive tools for ore."
suffix = "icemoon_surface_mining_site.dmm"
always_place = TRUE
always_spawn_with = list(/datum/map_template/ruin/icemoon/underground/mining_site_below = PLACE_BELOW)
/datum/map_template/ruin/icemoon/underground/mining_site_below
name = "Mining Site Underground"
id = "miningsite-underground"
description = "Who knew ladders could be so useful?"
suffix = "icemoon_underground_mining_site.dmm"
unpickable = TRUE
// below ground only
/datum/map_template/ruin/icemoon/underground
name = "underground ruin"
/datum/map_template/ruin/icemoon/underground/abandonedvillage
name = "Abandoned Village"
id = "abandonedvillage"
description = "Who knows what lies within?"
suffix = "icemoon_underground_abandoned_village.dmm"
/datum/map_template/ruin/icemoon/underground/library
name = "Buried Library"
id = "buriedlibrary"
description = "A once grand library, now lost to the confines of the Ice Moon."
suffix = "icemoon_underground_library.dmm"
/datum/map_template/ruin/icemoon/underground/wrath
name = "Ruin of Wrath"
id = "wrath"
description = "You'll fight and fight and just keep fighting."
suffix = "icemoon_underground_wrath.dmm"
/datum/map_template/ruin/icemoon/underground/lavaland
name = "Lavaland Site"
id = "lavalandsite"
description = "I guess we never really left you huh?"
suffix = "icemoon_underground_lavaland.dmm"
/datum/map_template/ruin/icemoon/underground/puzzle
name = "Ancient Puzzle"
id = "puzzle"
description = "Mystery to be solved."
suffix = "icemoon_underground_puzzle.dmm"
/datum/map_template/ruin/icemoon/underground/bathhouse
name = "Bath House"
id = "bathhouse"
description = "A taste of paradise, locked in the hell of the Ice Moon."
suffix = "icemoon_underground_bathhouse.dmm"
/datum/map_template/ruin/icemoon/underground/wendigo_cave
name = "Wendigo Cave"
id = "wendigocave"
description = "Into the jaws of the beast."
suffix = "icemoon_underground_wendigo_cave.dmm"
/datum/map_template/ruin/icemoon/underground/free_golem
name = "Free Golem Ship"
id = "golem-ship"
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
Seem very intent on research and individual liberty, and also geology-based naming?"
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "golem_ship.dmm"
allow_duplicates = FALSE

View File

@@ -67,7 +67,8 @@
description = "Lumbering humanoids, made out of precious metals, move inside this ship. They frequently leave to mine more minerals, which they somehow turn into more of them. \
Seem very intent on research and individual liberty, and also geology based naming?"
cost = 20
suffix = "lavaland_surface_golem_ship.dmm"
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "golem_ship.dmm"
allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/animal_hospital
@@ -175,7 +176,8 @@
name = "Fountain Hall"
id = "fountain"
description = "The fountain has a warning on the side. DANGER: May have undeclared side effects that only become obvious when implemented."
suffix = "lavaland_surface_fountain_hall.dmm"
prefix = "_maps/RandomRuins/AnywhereRuins/"
suffix = "fountain_hall.dmm"
cost = 5
allow_duplicates = FALSE

View File

@@ -23,14 +23,14 @@
mappath = "[prefix][shuttle_id].dmm"
. = ..()
/datum/map_template/shuttle/preload_size(path, cache)
/datum/map_template/shuttle/preload_size(path = mappath, force_cache = FALSE)
. = ..(path, TRUE) // Done this way because we still want to know if someone actualy wanted to cache the map
if(!cached_map)
return
discover_port_offset()
if(!cache)
if(!cached_map)
cached_map = null
/datum/map_template/shuttle/proc/discover_port_offset()
@@ -53,12 +53,11 @@
++xcrd
--ycrd
/datum/map_template/shuttle/load(turf/T, centered, register=TRUE)
/datum/map_template/shuttle/load(turf/T, centered = FALSE, orientation = SOUTH, annihilate = default_annihilate, force_cache = FALSE, rotate_placement_to_orientation = FALSE, register = TRUE)
. = ..()
if(!.)
return
var/list/turfs = block( locate(.[MAP_MINX], .[MAP_MINY], .[MAP_MINZ]),
locate(.[MAP_MAXX], .[MAP_MAXY], .[MAP_MAXZ]))
var/list/turfs = get_last_loaded_turf_block()
for(var/i in 1 to turfs.len)
var/turf/place = turfs[i]
if(istype(place, /turf/open/space)) // This assumes all shuttles are loaded in a single spot then moved to their real destination.

View File

@@ -391,78 +391,34 @@
owner.underlays -= marked_underlay //if this is being called, we should have an owner at this point.
..()
/datum/status_effect/saw_bleed
/datum/status_effect/stacking/saw_bleed
id = "saw_bleed"
duration = -1 //removed under specific conditions
tick_interval = 6
alert_type = null
var/mutable_appearance/bleed_overlay
var/mutable_appearance/bleed_underlay
var/bleed_amount = 3
var/bleed_buildup = 3
var/delay_before_decay = 5
delay_before_decay = 5
stack_threshold = 10
max_stacks = 10
overlay_file = 'icons/effects/bleed.dmi'
underlay_file = 'icons/effects/bleed.dmi'
overlay_state = "bleed"
underlay_state = "bleed"
var/bleed_damage = 200
var/needs_to_bleed = FALSE
/datum/status_effect/saw_bleed/Destroy()
if(owner)
owner.cut_overlay(bleed_overlay)
owner.underlays -= bleed_underlay
QDEL_NULL(bleed_overlay)
return ..()
/datum/status_effect/stacking/saw_bleed/fadeout_effect()
new /obj/effect/temp_visual/bleed(get_turf(owner))
/datum/status_effect/saw_bleed/on_apply()
if(owner.stat == DEAD)
return FALSE
bleed_overlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
bleed_underlay = mutable_appearance('icons/effects/bleed.dmi', "bleed[bleed_amount]")
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
bleed_overlay.pixel_x = -owner.pixel_x
bleed_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
bleed_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the bleed overlay's size based on the target's icon size
bleed_underlay.pixel_x = -owner.pixel_x
bleed_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
bleed_underlay.alpha = 40
owner.add_overlay(bleed_overlay)
owner.underlays += bleed_underlay
return ..()
/datum/status_effect/stacking/saw_bleed/threshold_cross_effect()
owner.adjustBruteLoss(bleed_damage)
var/turf/T = get_turf(owner)
new /obj/effect/temp_visual/bleed/explode(T)
for(var/d in GLOB.alldirs)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
playsound(T, "desceration", 100, TRUE, -1)
/datum/status_effect/saw_bleed/tick()
if(owner.stat == DEAD)
qdel(src)
else
add_bleed(-1)
/datum/status_effect/saw_bleed/proc/add_bleed(amount)
owner.cut_overlay(bleed_overlay)
owner.underlays -= bleed_underlay
bleed_amount += amount
if(bleed_amount)
if(bleed_amount >= 10)
needs_to_bleed = TRUE
qdel(src)
else
if(amount > 0)
tick_interval += delay_before_decay
bleed_overlay.icon_state = "bleed[bleed_amount]"
bleed_underlay.icon_state = "bleed[bleed_amount]"
owner.add_overlay(bleed_overlay)
owner.underlays += bleed_underlay
else
qdel(src)
/datum/status_effect/saw_bleed/on_remove()
. = ..()
if(needs_to_bleed)
var/turf/T = get_turf(owner)
new /obj/effect/temp_visual/bleed/explode(T)
for(var/d in GLOB.alldirs)
new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d)
playsound(T, "desceration", 200, 1, -1)
owner.adjustBruteLoss(bleed_damage)
else
new /obj/effect/temp_visual/bleed(get_turf(owner))
/datum/status_effect/stacking/saw_bleed/bloodletting
id = "bloodletting"
stack_threshold = 7
max_stacks = 7
bleed_damage = 20
/datum/status_effect/neck_slice
id = "neck_slice"

View File

@@ -7,7 +7,6 @@
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
var/mob/living/owner //The mob affected by the status effect.
var/status_type = STATUS_EFFECT_UNIQUE //How many of the effect can be on one mob, and what happens when you try to add another
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
var/alert_type = /obj/screen/alert/status_effect //the alert thrown by the status effect, contains name and description
@@ -16,6 +15,8 @@
/// If this is TRUE, the user will have sprint forcefully disabled while this is active.
var/blocks_sprint = FALSE
var/obj/screen/alert/status_effect/linked_alert = null //the alert itself, if it exists
/// How many of the effect can be on one mob, and what happens when you try to add another
var/status_type = STATUS_EFFECT_UNIQUE
/datum/status_effect/New(list/arguments)
on_creation(arglist(arguments))
@@ -67,6 +68,9 @@
/datum/status_effect/proc/tick() //Called every tick.
/datum/status_effect/proc/before_remove() //! Called before being removed; returning FALSE will cancel removal
return TRUE
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
SHOULD_CALL_PARENT(TRUE)
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
@@ -123,12 +127,13 @@
S1 = new effect(arguments)
. = S1
/mob/living/proc/remove_status_effect(effect) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
/mob/living/proc/remove_status_effect(effect, ...) //removes all of a given status effect from this mob, returning TRUE if at least one was removed
. = FALSE
var/list/arguments = args.Copy(2)
if(status_effects)
var/datum/status_effect/S1 = effect
for(var/datum/status_effect/S in status_effects)
if(initial(S1.id) == S.id)
if(initial(S1.id) == S.id && S.before_remove(arguments))
qdel(S)
. = TRUE
@@ -147,3 +152,129 @@
for(var/datum/status_effect/S in status_effects)
if(initial(S1.id) == S.id)
. += S
//////////////////////
// STACKING EFFECTS //
//////////////////////
/datum/status_effect/stacking
id = "stacking_base"
duration = -1 //removed under specific conditions
alert_type = null
var/stacks = 0 //how many stacks are accumulated, also is # of stacks that target will have when first applied
var/delay_before_decay //deciseconds until ticks start occuring, which removes stacks (first stack will be removed at this time plus tick_interval)
tick_interval = 10 //deciseconds between decays once decay starts
var/stack_decay = 1 //how many stacks are lost per tick (decay trigger)
var/stack_threshold //special effects trigger when stacks reach this amount
var/max_stacks //stacks cannot exceed this amount
var/consumed_on_threshold = TRUE //if status should be removed once threshold is crossed
var/threshold_crossed = FALSE //set to true once the threshold is crossed, false once it falls back below
var/overlay_file
var/underlay_file
var/overlay_state // states in .dmi must be given a name followed by a number which corresponds to a number of stacks. put the state name without the number in these state vars
var/underlay_state // the number is concatonated onto the string based on the number of stacks to get the correct state name
var/mutable_appearance/status_overlay
var/mutable_appearance/status_underlay
/datum/status_effect/stacking/proc/threshold_cross_effect() //what happens when threshold is crossed
/datum/status_effect/stacking/proc/stacks_consumed_effect() //runs if status is deleted due to threshold being crossed
/datum/status_effect/stacking/proc/fadeout_effect() //runs if status is deleted due to being under one stack
/datum/status_effect/stacking/proc/stack_decay_effect() //runs every time tick() causes stacks to decay
/datum/status_effect/stacking/proc/on_threshold_cross()
threshold_cross_effect()
if(consumed_on_threshold)
stacks_consumed_effect()
qdel(src)
/datum/status_effect/stacking/proc/on_threshold_drop()
/datum/status_effect/stacking/proc/can_have_status()
return owner.stat != DEAD
/datum/status_effect/stacking/proc/can_gain_stacks()
return owner.stat != DEAD
/datum/status_effect/stacking/tick()
if(!can_have_status())
qdel(src)
else
add_stacks(-stack_decay)
stack_decay_effect()
/datum/status_effect/stacking/proc/add_stacks(stacks_added)
if(stacks_added > 0 && !can_gain_stacks())
return FALSE
owner.cut_overlay(status_overlay)
owner.underlays -= status_underlay
stacks += stacks_added
if(stacks > 0)
if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold
threshold_crossed = TRUE
on_threshold_cross()
if(consumed_on_threshold)
return
else if(stacks < stack_threshold && threshold_crossed)
threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
on_threshold_drop()
if(stacks_added > 0)
tick_interval += delay_before_decay //refreshes time until decay
stacks = min(stacks, max_stacks)
status_overlay.icon_state = "[overlay_state][stacks]"
status_underlay.icon_state = "[underlay_state][stacks]"
owner.add_overlay(status_overlay)
owner.underlays += status_underlay
else
fadeout_effect()
qdel(src) //deletes status if stacks fall under one
/datum/status_effect/stacking/on_creation(mob/living/new_owner, stacks_to_apply)
. = ..()
if(.)
add_stacks(stacks_to_apply)
/datum/status_effect/stacking/on_apply()
if(!can_have_status())
return FALSE
status_overlay = mutable_appearance(overlay_file, "[overlay_state][stacks]")
status_underlay = mutable_appearance(underlay_file, "[underlay_state][stacks]")
var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
var/icon_height = I.Height()
status_overlay.pixel_x = -owner.pixel_x
status_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
status_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the status's overlay size based on the target's icon size
status_underlay.pixel_x = -owner.pixel_x
status_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
status_underlay.alpha = 40
owner.add_overlay(status_overlay)
owner.underlays += status_underlay
return ..()
/datum/status_effect/stacking/Destroy()
if(owner)
owner.cut_overlay(status_overlay)
owner.underlays -= status_underlay
QDEL_NULL(status_overlay)
return ..()
/// Status effect from multiple sources, when all sources are removed, so is the effect
/datum/status_effect/grouped
status_type = STATUS_EFFECT_MULTIPLE //! Adds itself to sources and destroys itself if one exists already, there are never multiple
var/list/sources = list()
/datum/status_effect/grouped/on_creation(mob/living/new_owner, source)
var/datum/status_effect/grouped/existing = new_owner.has_status_effect(type)
if(existing)
existing.sources |= source
qdel(src)
return FALSE
else
sources |= source
return ..()
/datum/status_effect/grouped/before_remove(source)
sources -= source
return !length(sources)

View File

@@ -1,49 +1,96 @@
//The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
/**
* Causes weather to occur on a z level in certain area types
*
* The effects of weather occur across an entire z-level. For instance, lavaland has periodic ash storms that scorch most unprotected creatures.
* Weather always occurs on different z levels at different times, regardless of weather type.
* Can have custom durations, targets, and can automatically protect indoor areas.
*
*/
/datum/weather
/// name of weather
var/name = "space wind"
/// description of weather
var/desc = "Heavy gusts of wind blanket the area, periodically knocking down anyone caught in the open."
var/telegraph_message = "<span class='warning'>The wind begins to pick up.</span>" //The message displayed in chat to foreshadow the weather's beginning
var/telegraph_duration = 300 //In deciseconds, how long from the beginning of the telegraph until the weather begins
var/telegraph_sound //The sound file played to everyone on an affected z-level
var/telegraph_overlay //The overlay applied to all tiles on the z-level
/// The message displayed in chat to foreshadow the weather's beginning
var/telegraph_message = "<span class='warning'>The wind begins to pick up.</span>"
var/weather_message = "<span class='userdanger'>The wind begins to blow ferociously!</span>" //Displayed in chat once the weather begins in earnest
var/weather_duration = 1200 //In deciseconds, how long the weather lasts once it begins
var/weather_duration_lower = 1200 //See above - this is the lowest possible duration
var/weather_duration_upper = 1500 //See above - this is the highest possible duration
/// In deciseconds, how long from the beginning of the telegraph until the weather begins
var/telegraph_duration = 300
/// The sound file played to everyone on an affected z-level
var/telegraph_sound
/// The overlay applied to all tiles on the z-level
var/telegraph_overlay
/// Displayed in chat once the weather begins in earnest
var/weather_message = "<span class='userdanger'>The wind begins to blow ferociously!</span>"
///In deciseconds, how long the weather lasts once it begins
var/weather_duration = 1200
///See above - this is the lowest possible duration
var/weather_duration_lower = 1200
///See above - this is the highest possible duration
var/weather_duration_upper = 1500
/// Looping sound while weather is occuring
var/weather_sound
/// Area overlay while the weather is occuring
var/weather_overlay
/// Color to apply to the area while weather is occuring
var/weather_color = null
var/end_message = "<span class='danger'>The wind relents its assault.</span>" //Displayed once the weather is over
var/end_duration = 300 //In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
/// Displayed once the weather is over
var/end_message = "<span class='danger'>The wind relents its assault.</span>"
/// In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely
var/end_duration = 300
/// Sound that plays while weather is ending
var/end_sound
/// Area overlay while weather is ending
var/end_overlay
var/area_type = /area/space //Types of area to affect
var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins
var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas.
var/impacted_z_levels // The list of z-levels that this weather is actively affecting
/// Types of area to affect
var/area_type = /area/space
/// TRUE value protects areas with outdoors marked as false, regardless of area type
var/protect_indoors = FALSE
/// Areas to be affected by the weather, calculated when the weather begins
var/list/impacted_areas = list()
var/overlay_layer = AREA_LAYER //Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
var/aesthetic = FALSE //If the weather has no purpose other than looks
var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather
/// Areas that are protected and excluded from the affected areas.
var/list/protected_areas = list()
/// The list of z-levels that this weather is actively affecting
var/impacted_z_levels
var/stage = END_STAGE //The stage of the weather, from 1-4
/// Since it's above everything else, this is the layer used by default. TURF_LAYER is below mobs and walls if you need to use that.
var/overlay_layer = AREA_LAYER
/// Plane for the overlay
var/overlay_plane = BLACKNESS_PLANE
/// If the weather has no purpose but aesthetics.
var/aesthetic = FALSE
/// Used by mobs to prevent them from being affected by the weather
var/immunity_type = "storm"
// These are read by the weather subsystem and used to determine when and where to run the weather.
var/probability = 0 // Weight amongst other eligible weather. If zero, will never happen randomly.
var/target_trait = ZTRAIT_STATION // The z-level trait to affect when run randomly or when not overridden.
/// The stage of the weather, from 1-4
var/stage = END_STAGE
/// Weight amongst other eligible weather. if zero, will never happen randomly.
var/probability = 0
/// The z-level trait to affect when run randomly or when not overridden.
var/target_trait = ZTRAIT_STATION
/// Whether a barometer can predict when the weather will happen
var/barometer_predictable = FALSE
var/next_hit_time = 0 //For barometers to know when the next storm will hit
/// For barometers to know when the next storm will hit
var/next_hit_time = 0
/datum/weather/New(z_levels)
..()
impacted_z_levels = z_levels
/**
* Telegraphs the beginning of the weather on the impacted z levels
*
* Sends sounds and details to mobs in the area
* Calculates duration and hit areas, and makes a callback for the actual weather to start
*
*/
/datum/weather/proc/telegraph()
if(stage == STARTUP_STAGE)
return
@@ -58,6 +105,8 @@
affectareas -= get_areas(V)
for(var/V in affectareas)
var/area/A = V
if(protect_indoors && !A.outdoors)
continue
if(A.z in impacted_z_levels)
impacted_areas |= A
weather_duration = rand(weather_duration_lower, weather_duration_upper)
@@ -72,6 +121,13 @@
SEND_SOUND(M, sound(telegraph_sound))
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
/**
* Starts the actual weather and effects from it
*
* Updates area overlays and sends sounds and messages to mobs to notify them
* Begins dealing effects from weather to mobs in the area
*
*/
/datum/weather/proc/start()
if(stage >= MAIN_STAGE)
return
@@ -86,6 +142,13 @@
SEND_SOUND(M, sound(weather_sound))
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
/**
* Weather enters the winding down phase, stops effects
*
* Updates areas to be in the winding down phase
* Sends sounds and messages to mobs to notify them
*
*/
/datum/weather/proc/wind_down()
if(stage >= WIND_DOWN_STAGE)
return
@@ -100,6 +163,13 @@
SEND_SOUND(M, sound(end_sound))
addtimer(CALLBACK(src, .proc/end), end_duration)
/**
* Fully ends the weather
*
* Effects no longer occur and area overlays are removed
* Removes weather from processing completely
*
*/
/datum/weather/proc/end()
if(stage == END_STAGE)
return 1
@@ -115,7 +185,11 @@
if(can_weather_act(L))
weather_act(L)
/datum/weather/proc/can_weather_act(mob/living/L) //Can this weather impact a mob?
/**
* Returns TRUE if the living mob can be affected by the weather
*
*/
/datum/weather/proc/can_weather_act(mob/living/L)
var/turf/mob_turf = get_turf(L)
if(mob_turf && !(mob_turf.z in impacted_z_levels))
return
@@ -123,11 +197,19 @@
return
if(!(get_area(L) in impacted_areas))
return
return 1
return TRUE
/datum/weather/proc/weather_act(mob/living/L) //What effect does this weather have on the hapless mob?
/**
* Affects the mob with whatever the weather does
*
*/
/datum/weather/proc/weather_act(mob/living/L)
return
/**
* Updates the overlays on impacted areas
*
*/
/datum/weather/proc/update_areas()
for(var/V in impacted_areas)
var/area/N = V

View File

@@ -17,8 +17,9 @@
end_message = "<span class='boldannounce'>The downpour gradually slows to a light shower. It should be safe outside now.</span>"
end_sound = 'sound/ambience/acidrain_end.ogg'
area_type = /area/lavaland/surface/outdoors
target_trait = ZTRAIT_MINING
area_type = /area
protect_indoors = TRUE
target_trait = ZTRAIT_ACIDRAIN
immunity_type = "acid" // temp

View File

@@ -16,8 +16,9 @@
end_duration = 300
end_overlay = "light_ash"
area_type = /area/lavaland/surface/outdoors
target_trait = ZTRAIT_MINING
area_type = /area
protect_indoors = TRUE
target_trait = ZTRAIT_ASHSTORM
immunity_type = "ash"

View File

@@ -15,8 +15,9 @@
end_duration = 100
end_message = "<span class='boldannounce'>The snowfall dies down, it should be safe to go outside again.</span>"
area_type = /area/awaymission/snowdin/outside
target_trait = ZTRAIT_AWAY
area_type = /area
protect_indoors = TRUE
target_trait = ZTRAIT_SNOWSTORM
immunity_type = "snow"

View File

@@ -11,13 +11,27 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
invisibility = INVISIBILITY_LIGHTING
var/map_name // Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
/// Set in New(); preserves the name set by the map maker, even if renamed by the Blueprints.
var/map_name
var/valid_territory = TRUE // If it's a valid territory for gangs to claim
var/blob_allowed = TRUE // Does it count for blobs score? By default, all areas count.
var/clockwork_warp_allowed = TRUE // Can servants warp into this area from Reebe?
/// If it's valid territory for gangs/cults to summon
var/valid_territory = TRUE
/// if blobs can spawn there and if it counts towards their score.
var/blob_allowed = TRUE
/// whether servants can warp into this area from Reebe
var/clockwork_warp_allowed = TRUE
/// Message to display when the clockwork warp fails
var/clockwork_warp_fail = "The structure there is too dense for warping to pierce. (This is normal in high-security areas.)"
/// If mining tunnel generation is allowed in this area
var/tunnel_allowed = FALSE
/// If flora are allowed to spawn in this area randomly through tunnel generation
var/flora_allowed = FALSE
/// if mobs can be spawned by natural random generation
var/mob_spawn_allowed = FALSE
/// If megafauna can be spawned by natural random generation
var/megafauna_spawn_allowed = FALSE
var/fire = null
var/atmos = TRUE
var/atmosalm = FALSE
@@ -25,11 +39,14 @@
var/lightswitch = TRUE
var/requires_power = TRUE
var/always_unpowered = FALSE // This gets overridden to 1 for space in area/Initialize().
/// This gets overridden to 1 for space in area/Initialize().
var/always_unpowered = FALSE
var/outdoors = FALSE //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
/// For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room)
var/outdoors = FALSE
var/areasize = 0 //Size of the area in open turfs, only calculated for indoors areas.
/// Size of the area in open turfs, only calculated for indoors areas.
var/areasize = 0
var/power_equip = TRUE
var/power_light = TRUE
@@ -43,9 +60,12 @@
var/static_environ
var/has_gravity = 0
var/noteleport = FALSE //Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
var/hidden = FALSE //Hides area from player Teleport function.
var/safe = FALSE //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
/// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
var/noteleport = FALSE
/// Hides area from player Teleport function.
var/hidden = FALSE
/// Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers
var/safe = FALSE
/// If false, loading multiple maps with this area type will create multiple instances.
var/unique = TRUE

View File

@@ -3,6 +3,7 @@
/area/mine
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
flora_allowed = TRUE
/area/mine/explored
name = "Mine"
@@ -17,6 +18,7 @@
outdoors = TRUE
flags_1 = NONE
ambientsounds = MINING
flora_allowed = FALSE
/area/mine/unexplored
name = "Mine"
@@ -31,6 +33,7 @@
outdoors = TRUE
flags_1 = NONE
ambientsounds = MINING
tunnel_allowed = TRUE
/area/mine/lobby
name = "Mining Station"
@@ -82,6 +85,7 @@
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
flora_allowed = TRUE
/area/lavaland/surface
name = "Lavaland"
@@ -114,9 +118,79 @@
/area/lavaland/surface/outdoors/unexplored //monsters and ruins spawn here
icon_state = "unexplored"
tunnel_allowed = TRUE
mob_spawn_allowed = TRUE
/area/lavaland/surface/outdoors/unexplored/danger //megafauna will also spawn here
icon_state = "danger"
megafauna_spawn_allowed = TRUE
/area/lavaland/surface/outdoors/explored
name = "Lavaland Labor Camp"
flora_allowed = FALSE
/**********************Ice Moon Areas**************************/
/area/icemoon
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
flora_allowed = TRUE
blob_allowed = FALSE
/area/icemoon/surface
name = "Icemoon"
icon_state = "explored"
always_unpowered = TRUE
poweralm = FALSE
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
requires_power = TRUE
ambientsounds = MINING
/area/icemoon/underground
name = "Icemoon Caves"
outdoors = TRUE
always_unpowered = TRUE
requires_power = TRUE
poweralm = FALSE
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
ambientsounds = MINING
/area/icemoon/underground/unexplored // mobs and megafauna and ruins spawn here
name = "Icemoon Caves"
icon_state = "unexplored"
tunnel_allowed = TRUE
mob_spawn_allowed = TRUE
megafauna_spawn_allowed = TRUE
/area/icemoon/underground/unexplored/rivers // rivers spawn here
icon_state = "danger"
/area/icemoon/underground/explored
name = "Icemoon Underground"
flora_allowed = FALSE
/area/icemoon/surface/outdoors
name = "Icemoon Wastes"
outdoors = TRUE
/area/icemoon/surface/outdoors/labor_camp
name = "Icemoon Labor Camp"
flora_allowed = FALSE
/area/icemoon/surface/outdoors/unexplored //monsters and ruins spawn here
icon_state = "unexplored"
tunnel_allowed = TRUE
mob_spawn_allowed = TRUE
/area/icemoon/surface/outdoors/unexplored/rivers // rivers spawn here
icon_state = "danger"
/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters
mob_spawn_allowed = FALSE

View File

@@ -0,0 +1,9 @@
// Icemoon Ruins
/area/ruin/unpowered/buried_library
name = "Buried Library"
icon_state = "dk_yellow"
/area/ruin/powered/bathhouse
name = "Bath House"
icon_state = "dk_yellow"

View File

@@ -25,6 +25,7 @@
var/inertia_move_delay = 5
var/pass_flags = 0
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
var/atom/movable/moving_from_pull //attempt to resume grab after moving instead of before.
var/list/client_mobs_in_contents // This contains all the client mobs within this container
var/list/acted_explosions //for explosion dodging
glide_size = 8
@@ -207,6 +208,7 @@
if(!Process_Spacemove(get_dir(pulling.loc, A)))
return
step(pulling, get_dir(pulling.loc, A))
return TRUE
/atom/movable/proc/check_pulling()
if(pulling)
@@ -224,6 +226,8 @@
if(pulling.anchored || pulling.move_resist > move_force)
stop_pulling()
return
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)

View File

@@ -20,6 +20,9 @@
if(!newloc.Enter(src, src.loc))
return
if (SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_MOVE, newloc) & COMPONENT_MOVABLE_BLOCK_PRE_MOVE)
return
// Past this is the point of no return
var/atom/oldloc = loc
var/area/oldarea = get_area(oldloc)
@@ -51,13 +54,8 @@
/atom/movable/Move(atom/newloc, direct)
var/atom/movable/pullee = pulling
var/turf/T = loc
if(pulling)
if(pullee && get_dist(src, pullee) > 1)
stop_pulling()
if(pullee && pullee.loc != loc && !isturf(pullee.loc) ) //to be removed once all code that changes an object's loc uses forceMove().
log_game("DEBUG:[src]'s pull on [pullee] wasn't broken despite [pullee] being in [pullee.loc]. Pull stopped manually.")
stop_pulling()
if(!moving_from_pull)
check_pulling()
if(!loc || !newloc)
return FALSE
var/atom/oldloc = loc
@@ -130,19 +128,16 @@
if(has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s)
return FALSE
if(pulling && pulling == pullee) //we were pulling a thing and didn't lose it during our move.
if(pulling && pulling == pullee && pulling != moving_from_pull) //we were pulling a thing and didn't lose it during our move.
if(pulling.anchored)
stop_pulling()
else
var/pull_dir = get_dir(src, pulling)
//puller and pullee more than one tile away or in diagonal position
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir)))
pulling.moving_from_pull = src
pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up
stop_pulling()
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
pulling.moving_from_pull = null
Moved(oldloc, direct)
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)

View File

@@ -642,6 +642,9 @@
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
if(isturf(L.loc))
spawn_locs += L.loc
for(var/obj/effect/landmark/loneopspawn/L in GLOB.landmarks_list)
if(isturf(L.loc))
spawn_locs += L.loc
if(!spawn_locs.len)
return FALSE
spawn_loc = pick(spawn_locs)

View File

@@ -62,6 +62,9 @@
/datum/material/mythril
)
/// Base print speed
var/base_print_speed = 10
/obj/machinery/autolathe/Initialize()
AddComponent(/datum/component/material_container, allowed_materials, _show_on_examine=TRUE, _after_insert=CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
@@ -206,7 +209,7 @@
busy = TRUE
use_power(power)
icon_state = "autolathe_n"
var/time = is_stack ? 32 : 32*coeff*multiplier
var/time = is_stack ? 10 : base_print_speed * coeff * multiplier
addtimer(CALLBACK(src, .proc/make_item, power, materials_used, custom_materials, multiplier, coeff, is_stack), time)
else
to_chat(usr, "<span class=\"alert\">Not enough materials for this operation.</span>")
@@ -254,10 +257,12 @@
T += MB.rating*75000
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
materials.max_amount = T
T=1.2
var/manips = 0
var/total_manip_rating = 0
for(var/obj/item/stock_parts/manipulator/M in component_parts)
T -= M.rating*0.2
prod_coeff = min(1,max(0,T)) // Coeff going 1 -> 0,8 -> 0,6 -> 0,4
total_manip_rating += M.rating
manips++
prod_coeff = STANDARD_PART_LEVEL_LATHE_COEFFICIENT(total_manip_rating / (manips? manips : 1))
/obj/machinery/autolathe/examine(mob/user)
. += ..()
@@ -440,6 +445,7 @@
hackable = FALSE
circuit = /obj/item/circuitboard/machine/autolathe/secure
stored_research = /datum/techweb/specialized/autounlocking/autolathe/public
base_print_speed = 20
/obj/machinery/autolathe/toy
name = "autoylathe"

View File

@@ -55,8 +55,12 @@
M.buckling = null
return FALSE
if(M.pulledby && buckle_prevents_pull)
M.pulledby.stop_pulling()
if(M.pulledby)
if(buckle_prevents_pull)
M.pulledby.stop_pulling()
else if(isliving(M.pulledby))
var/mob/living/L = M.pulledby
L.reset_pull_offsets(M, TRUE)
if(!check_loc && M.loc != loc)
M.forceMove(loc)
@@ -137,4 +141,7 @@
"<span class='notice'>You unbuckle yourself from [src].</span>",\
"<span class='italics'>You hear metal clanking.</span>")
add_fingerprint(user)
if(isliving(M.pulledby))
var/mob/living/L = M.pulledby
L.set_pull_offsets(M, L.grab_state)
return M

View File

@@ -313,6 +313,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
name = "carpspawn"
icon_state = "carp_spawn"
// lone op (optional)
/obj/effect/landmark/loneopspawn
name = "loneop+ninjaspawn"
icon_state = "snukeop_spawn"
// observer-start.
/obj/effect/landmark/observer_start
name = "Observer-Start"
@@ -492,7 +497,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
if(!template)
return FALSE
testing("Room \"[template_name]\" placed at ([T.x], [T.y], [T.z])")
template.load(T, centered = FALSE)
template.load(T, centered = FALSE, orientation = dir, rotate_placement_to_orientation = TRUE)
template.loaded++
GLOB.stationroom_landmarks -= src
qdel(src)
@@ -504,7 +509,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
templates = list("Engine SM" = 3, "Engine Singulo" = 3, "Engine Tesla" = 3)
icon = 'icons/rooms/box/engine.dmi'
/obj/effect/landmark/stationroom/box/engine/New()
. = ..()
templates = CONFIG_GET(keyed_list/box_random_engine)
@@ -513,3 +517,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
/obj/effect/landmark/stationroom/lavaland/station
templates = list("Public Mining Base" = 3)
icon = 'icons/rooms/Lavaland/Mining.dmi'
// handled in portals.dm, id connected to one-way portal
/obj/effect/landmark/portal_exit
name = "portal exit"
icon_state = "portal_exit"
var/id

View File

@@ -29,6 +29,7 @@
var/allow_anchored = FALSE
var/innate_accuracy_penalty = 0
var/last_effect = 0
var/force_teleport = FALSE
/obj/effect/portal/anom
name = "wormhole"
@@ -162,7 +163,7 @@
no_effect = TRUE
else
last_effect = world.time
if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel))
if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel, forced = force_teleport))
if(istype(M, /obj/item/projectile))
var/obj/item/projectile/P = M
P.ignore_source_check = TRUE
@@ -183,3 +184,47 @@
else
real_target = get_turf(linked)
return real_target
/obj/effect/portal/permanent
name = "permanent portal"
desc = "An unwavering portal that will never fade."
hardlinked = FALSE // dont qdel my portal nerd
force_teleport = TRUE // force teleports because they're a mapmaker tool
var/id // var edit or set id in map editor
/obj/effect/portal/permanent/proc/set_linked()
if(!id)
return
for(var/obj/effect/portal/permanent/P in GLOB.portals - src)
if(P.id == id)
P.linked = src
linked = P
break
/obj/effect/portal/permanent/teleport(atom/movable/M, force = FALSE)
set_linked() // update portal links
. = ..()
/obj/effect/portal/permanent/one_way // doesn't have a return portal, can have multiple exits, /obj/effect/landmark/portal_exit to mark them
name = "one-way portal"
desc = "You get the feeling that this might not be the safest thing you've ever done."
/obj/effect/portal/permanent/one_way/set_linked()
if(!id)
return
var/list/possible_turfs = list()
for(var/obj/effect/landmark/portal_exit/PE in GLOB.landmarks_list)
if(PE.id == id)
var/turf/T = get_turf(PE)
if(T)
possible_turfs |= T
if(possible_turfs.len)
hard_target = pick(possible_turfs)
/obj/effect/portal/permanent/one_way/one_use
name = "one-use portal"
desc = "This is probably the worst decision you'll ever make in your life."
/obj/effect/portal/permanent/one_way/one_use/teleport(atom/movable/M, force = FALSE)
. = ..()
qdel(src)

View File

@@ -351,6 +351,12 @@
light_color = "#FFAA44"
flashlight_power = 0.8
/obj/item/flashlight/lantern/jade
name = "jade lantern"
desc = "An ornate, green lantern."
color = LIGHT_COLOR_GREEN
light_color = LIGHT_COLOR_GREEN
/obj/item/flashlight/slime
gender = PLURAL
name = "glowing slime extract"

View File

@@ -8,6 +8,7 @@
level = 1
var/trigger_mob = TRUE
var/trigger_item = FALSE
var/specific_item = null
var/trigger_silent = FALSE
var/sound/trigger_sound = 'sound/effects/pressureplate.ogg'
var/obj/item/assembly/signaler/sigdev = null
@@ -35,6 +36,8 @@
. = ..()
if(!can_trigger || !active)
return
if(trigger_item && !istype(AM, specific_item))
return
if(trigger_mob && isliving(AM))
var/mob/living/L = AM
to_chat(L, "<span class='warning'>You feel something click beneath you!</span>")

View File

@@ -3,6 +3,7 @@
* Fork
* Kitchen knives
* Ritual Knife
* Bloodletter
* Butcher's cleaver
* Combat Knife
* Rolling Pins
@@ -97,6 +98,28 @@
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
w_class = WEIGHT_CLASS_NORMAL
/obj/item/kitchen/knife/bloodletter
name = "bloodletter"
desc = "An occult looking dagger that is cold to the touch. Somehow, the flawless orb on the pommel is made entirely of liquid blood."
icon = 'icons/obj/ice_moon/artifacts.dmi'
icon_state = "bloodletter"
w_class = WEIGHT_CLASS_NORMAL
/// Bleed stacks applied when an organic mob target is hit
var/bleed_stacks_per_hit = 3
/obj/item/kitchen/knife/bloodletter/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!isliving(target) || !proximity_flag)
return
var/mob/living/M = target
if(!(M.mob_biotypes & MOB_ORGANIC))
return
var/datum/status_effect/stacking/saw_bleed/bloodletting/B = M.has_status_effect(/datum/status_effect/stacking/saw_bleed/bloodletting)
if(!B)
M.apply_status_effect(/datum/status_effect/stacking/saw_bleed/bloodletting, bleed_stacks_per_hit)
else
B.add_stacks(bleed_stacks_per_hit)
/obj/item/kitchen/knife/butcher
name = "butcher's cleaver"
icon_state = "butch"

View File

@@ -123,11 +123,3 @@
w_class = WEIGHT_CLASS_BULKY
attack_verb = list("skubbed")
/obj/item/supermatterspray
name = "supermatter spray"
desc = "A spray bottle containing some kind of magical spray to fix the SM. \"Do not inhale.\" is written on the side. Unless aimed at the supermatter, it does nothing."
icon = 'icons/obj/supermatter.dmi'
icon_state = "supermatterspray"
w_class = WEIGHT_CLASS_SMALL
var/usesleft = 2

View File

@@ -0,0 +1,146 @@
//**************
//*****Keys*******************
//************** ** **
/obj/item/keycard
name = "security keycard"
desc = "This feels like it belongs to a door."
icon = 'icons/obj/puzzle_small.dmi'
icon_state = "keycard"
force = 0
throwforce = 0
w_class = WEIGHT_CLASS_TINY
throw_speed = 1
throw_range = 7
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
var/puzzle_id = null
//Two test keys for use alongside the two test doors.
/obj/item/keycard/cheese
name = "cheese keycard"
desc = "Look, I still don't understand the reference. What the heck is a keyzza?"
color = "#f0da12"
puzzle_id = "cheese"
/obj/item/keycard/swordfish
name = "titanic keycard"
desc = "Smells like it was at the bottom of a harbor."
color = "#3bbbdb"
puzzle_id = "swordfish"
//***************
//*****Doors*****
//***************
/obj/machinery/door/keycard
name = "locked door"
desc = "This door only opens when a keycard is swiped. It looks virtually indestructable."
icon = 'icons/obj/doors/puzzledoor/default.dmi'
icon_state = "door_closed"
explosion_block = 3
heat_proof = TRUE
max_integrity = 600
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 100, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
damage_deflection = 70
/// Make sure that the key has the same puzzle_id as the keycard door!
var/puzzle_id = null
/// Message that occurs when the door is opened
var/open_message = "The door beeps, and slides opens."
//Standard Expressions to make keycard doors basically un-cheeseable
/obj/machinery/door/keycard/Bumped(atom/movable/AM)
return !density && ..()
/obj/machinery/door/keycard/emp_act(severity)
return
/obj/machinery/door/keycard/ex_act(severity, target)
return
/obj/machinery/door/keycard/try_to_activate_door(mob/user)
add_fingerprint(user)
if(operating)
return
/obj/machinery/door/keycard/attackby(obj/item/I, mob/user, params)
. = ..()
if(istype(I,/obj/item/keycard))
var/obj/item/keycard/key = I
if((!puzzle_id || puzzle_id == key.puzzle_id) && density)
if(open_message)
to_chat(user, "<span class='notice'>[open_message]</span>")
open()
return
else if(puzzle_id != key.puzzle_id)
to_chat(user, "<span class='notice'>[src] buzzes. This must not be the right key.</span>")
return
else
to_chat(user, "<span class='notice'>This door doesn't appear to close.</span>")
return
//Test doors. Gives admins a few doors to use quickly should they so choose.
/obj/machinery/door/keycard/cheese
name = "blue airlock"
desc = "Smells like... pizza?"
puzzle_id = "cheese"
/obj/machinery/door/keycard/swordfish
name = "blue airlock"
desc = "If nautical nonsense be something you wish."
puzzle_id = "swordfish"
//*************************
//***Box Pushing Puzzles***
//*************************
//We're working off a subtype of pressureplates, which should work just a BIT better now.
/obj/structure/holobox
name = "holobox"
desc = "A hard-light box, containing a secure decryption key."
icon = 'icons/obj/puzzle_small.dmi'
icon_state = "laserbox"
density = TRUE
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
//Uses the pressure_plate settings for a pretty basic custom pattern that waits for a specific item to trigger. Easy enough to retool for mapping purposes or subtypes.
/obj/item/pressure_plate/hologrid
name = "hologrid"
desc = "A high power, electronic input port for a holobox, which can unlock the hologrid's storage compartment. Safe to stand on."
icon = 'icons/obj/puzzle_small.dmi'
icon_state = "lasergrid"
anchored = TRUE
trigger_mob = FALSE
trigger_item = TRUE
specific_item = /obj/structure/holobox
removable_signaller = FALSE //Being a pressure plate subtype, this can also use signals.
roundstart_signaller_freq = FREQ_HOLOGRID_SOLUTION //Frequency is kept on it's own default channel however.
active = TRUE
trigger_delay = 10
resistance_flags = INDESTRUCTIBLE | FIRE_PROOF | ACID_PROOF | LAVA_PROOF
var/reward = /obj/item/reagent_containers/food/snacks/cookie
var/claimed = FALSE
/obj/item/pressure_plate/hologrid/examine(mob/user)
. = ..()
if(claimed)
. += "<span class='notice'>This one appears to be spent already.</span>"
/obj/item/pressure_plate/hologrid/trigger()
if(!claimed)
new reward(loc)
flick("lasergrid_a",src)
icon_state = "lasergrid_full"
claimed = TRUE
/obj/item/pressure_plate/hologrid/Crossed(atom/movable/AM)
. = ..()
if(trigger_item && istype(AM, specific_item) && !claimed)
AM.anchored = TRUE
flick("laserbox_burn", AM)
trigger()
sleep(15)
qdel(AM)
// snowflake code until undertile elements
/obj/item/pressure_plate/hologrid/hide()
. = ..()
anchored = TRUE

View File

@@ -178,6 +178,11 @@ GLOBAL_LIST_INIT(leather_recipes, list ( \
icon_state = "sinew"
novariants = TRUE
/obj/item/stack/sheet/sinew/wolf
name = "wolf sinew"
desc = "Long stringy filaments which came from the insides of a wolf."
singular_name = "wolf sinew"
GLOBAL_LIST_INIT(sinew_recipes, list ( \
new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/sinew, 1), \
@@ -202,6 +207,11 @@ GLOBAL_LIST_INIT(sinew_recipes, list ( \
w_class = WEIGHT_CLASS_NORMAL
layer = MOB_LAYER
/obj/item/stack/sheet/animalhide/goliath_hide/polar_bear_hide
name = "polar bear hides"
desc = "Pieces of a polar bear's fur, these might be able to make your suit a bit more durable to attack from the local fauna."
icon_state = "polar_bear_hide"
singular_name = "polar bear hide"
/obj/item/stack/sheet/animalhide/ashdrake
name = "ash drake hide"

View File

@@ -350,11 +350,28 @@
icon = 'icons/obj/flora/rocks.dmi'
resistance_flags = FIRE_PROOF
density = TRUE
/// Itemstack that is dropped when a rock is mined with a pickaxe
var/obj/item/stack/mineResult = /obj/item/stack/ore/glass/basalt
/// Amount of the itemstack to drop
var/mineAmount = 20
/obj/structure/flora/rock/Initialize()
. = ..()
icon_state = "[icon_state][rand(1,3)]"
/obj/structure/flora/rock/attackby(obj/item/W, mob/user, params)
if(!mineResult || W.tool_behaviour != TOOL_MINING)
return ..()
if(flags_1 & NODECONSTRUCT_1)
return ..()
to_chat(user, "<span class='notice'>You start mining...</span>")
if(W.use_tool(src, user, 40, volume=50))
to_chat(user, "<span class='notice'>You finish mining the rock.</span>")
if(mineResult && mineAmount)
new mineResult(get_turf(src), mineAmount)
SSblackbox.record_feedback("tally", "pick_used_mining", 1, W.type)
qdel(src)
/obj/structure/flora/rock/pile
icon_state = "lavarocks"
desc = "A pile of rocks."

View File

@@ -0,0 +1,178 @@
GLOBAL_LIST_INIT(ore_probability, list(/obj/item/stack/ore/uranium = 50,
/obj/item/stack/ore/iron = 100,
/obj/item/stack/ore/plasma = 75,
/obj/item/stack/ore/silver = 50,
/obj/item/stack/ore/gold = 50,
/obj/item/stack/ore/diamond = 25,
/obj/item/stack/ore/bananium = 5,
/obj/item/stack/ore/titanium = 75))
/obj/structure/spawner/ice_moon
name = "cave entrance"
desc = "A hole in the ground, filled with monsters ready to defend it."
icon = 'icons/mob/nest.dmi'
icon_state = "hole"
faction = list("mining")
max_mobs = 3
max_integrity = 250
mob_types = list(/mob/living/simple_animal/hostile/asteroid/wolf)
move_resist = INFINITY
anchored = TRUE
/obj/structure/spawner/ice_moon/Initialize()
. = ..()
clear_rock()
/**
* Clears rocks around the spawner when it is created
*
*/
/obj/structure/spawner/ice_moon/proc/clear_rock()
for(var/turf/F in RANGE_TURFS(2, src))
if(abs(src.x - F.x) + abs(src.y - F.y) > 3)
continue
if(ismineralturf(F))
var/turf/closed/mineral/M = F
M.ScrapeAway(null, CHANGETURF_IGNORE_AIR)
/obj/structure/spawner/ice_moon/deconstruct(disassembled)
destroy_effect()
drop_loot()
return ..()
/**
* Effects and messages created when the spawner is destroyed
*
*/
/obj/structure/spawner/ice_moon/proc/destroy_effect()
playsound(loc,'sound/effects/explosionfar.ogg', 200, TRUE)
visible_message("<span class='boldannounce'>[src] collapses, sealing everything inside!</span>\n<span class='warning'>Ores fall out of the cave as it is destroyed!</span>")
/**
* Drops items after the spawner is destroyed
*
*/
/obj/structure/spawner/ice_moon/proc/drop_loot()
for(var/type in GLOB.ore_probability)
var/chance = GLOB.ore_probability[type]
if(!prob(chance))
continue
new type(loc, rand(5, 10))
/obj/structure/spawner/ice_moon/polarbear
max_mobs = 1
spawn_time = 60 SECONDS
mob_types = list(/mob/living/simple_animal/hostile/asteroid/polarbear)
/obj/structure/spawner/ice_moon/polarbear/clear_rock()
for(var/turf/F in RANGE_TURFS(1, src))
if(ismineralturf(F))
var/turf/closed/mineral/M = F
M.ScrapeAway(null, CHANGETURF_IGNORE_AIR)
/obj/structure/spawner/ice_moon/demonic_portal
name = "demonic portal"
desc = "A portal that goes to another world, normal creatures couldn't survive there."
icon_state = "nether"
mob_types = list(/mob/living/simple_animal/hostile/asteroid/ice_demon)
light_range = 1
light_color = LIGHT_COLOR_RED
/obj/structure/spawner/ice_moon/demonic_portal/clear_rock()
for(var/turf/F in RANGE_TURFS(3, src))
if(abs(src.x - F.x) + abs(src.y - F.y) > 5)
continue
if(ismineralturf(F))
var/turf/closed/mineral/M = F
M.ScrapeAway(null, CHANGETURF_IGNORE_AIR)
/obj/structure/spawner/ice_moon/demonic_portal/destroy_effect()
new /obj/effect/collapsing_demonic_portal(loc)
/obj/structure/spawner/ice_moon/demonic_portal/drop_loot()
return
/obj/structure/spawner/ice_moon/demonic_portal/ice_whelp
mob_types = list(/mob/living/simple_animal/hostile/asteroid/ice_whelp)
/obj/structure/spawner/ice_moon/demonic_portal/snowlegion
mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/snow/tendril)
/obj/effect/collapsing_demonic_portal
name = "collapsing demonic portal"
desc = "It's slowly fading!"
layer = TABLE_LAYER
icon = 'icons/mob/nest.dmi'
icon_state = "nether"
anchored = TRUE
density = TRUE
/obj/effect/collapsing_demonic_portal/Initialize()
. = ..()
playsound(loc,'sound/effects/tendril_destroyed.ogg', 200, FALSE, 50, TRUE, TRUE)
visible_message("<span class='boldannounce'>[src] begins to collapse, cutting it off from this world!</span>")
animate(src, transform = matrix().Scale(0, 1), alpha = 50, time = 5 SECONDS)
addtimer(CALLBACK(src, .proc/collapse), 5 SECONDS)
/obj/effect/collapsing_demonic_portal/proc/collapse()
visible_message("<span class='warning'>Something slips out of [src]!</span>")
var/loot = rand(1, 28)
switch(loot)
if(1)
new /obj/item/clothing/suit/space/hardsuit/cult(loc)
if(2)
new /obj/item/clothing/glasses/godeye(loc)
if(3)
new /obj/item/reagent_containers/glass/bottle/potion/flight(loc)
if(4)
new /obj/item/organ/heart/cursed/wizard(loc)
if(5)
new /obj/item/jacobs_ladder(loc)
if(6)
new /obj/item/rod_of_asclepius(loc)
if(7)
new /obj/item/warp_cube/red(loc)
if(8)
new /obj/item/wisp_lantern(loc)
if(9)
new /obj/item/immortality_talisman(loc)
if(10)
new /obj/item/book/granter/spell/summonitem(loc)
if(11)
new /obj/item/clothing/neck/necklace/memento_mori(loc)
if(12)
new /obj/item/borg/upgrade/modkit/lifesteal(loc)
new /obj/item/bedsheet/cult(loc)
if(13)
new /obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe(loc)
if(14)
new /obj/item/disk/design_disk/modkit_disc/bounty(loc)
if(15)
new /obj/item/ship_in_a_bottle(loc)
new /obj/item/oar(loc)
if(16)
new /obj/item/seeds/gatfruit(loc)
if(17)
new /obj/item/reagent_containers/food/drinks/drinkingglass/filled/nuka_cola(loc)
if(18)
new /obj/item/assembly/signaler/anomaly/bluespace(loc)
if(19)
new /obj/item/disk/design_disk/modkit_disc/resonator_blast(loc)
if(20)
new /obj/item/disk/design_disk/modkit_disc/rapid_repeater(loc)
if(21)
new /obj/item/slimepotion/transference(loc)
if(22)
new /obj/item/slime_extract/adamantine(loc)
if(23)
new /obj/item/weldingtool/abductor(loc)
if(24)
new /obj/structure/elite_tumor(loc)
if(25)
new /mob/living/simple_animal/hostile/retaliate/clown/clownhulk(loc)
if(26)
new /obj/item/clothing/shoes/winterboots/ice_boots(loc)
if(27)
new /obj/item/book/granter/spell/sacredflame(loc)
if(28)
new /mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/doom(loc)

View File

@@ -0,0 +1,86 @@
//If you look at the "geyser_soup" overlay icon_state, you'll see that the first frame has 25 ticks.
//That's because the first 18~ ticks are completely skipped for some ungodly weird fucking byond reason
/obj/structure/geyser
name = "geyser"
icon = 'icons/obj/lavaland/terrain.dmi'
icon_state = "geyser"
anchored = TRUE
var/erupting_state = null //set to null to get it greyscaled from "[icon_state]_soup". Not very usable with the whole random thing, but more types can be added if you change the spawn prob
var/activated = FALSE //whether we are active and generating chems
var/reagent_id = /datum/reagent/fuel/oil
var/potency = 2 //how much reagents we add every process (2 seconds)
var/max_volume = 500
var/start_volume = 50
/obj/structure/geyser/proc/start_chemming()
activated = TRUE
create_reagents(max_volume, DRAINABLE)
reagents.add_reagent(reagent_id, start_volume)
START_PROCESSING(SSfluids, src) //It's main function is to be plumbed, so use SSfluids
if(erupting_state)
icon_state = erupting_state
else
var/mutable_appearance/I = mutable_appearance('icons/obj/lavaland/terrain.dmi', "[icon_state]_soup")
I.color = mix_color_from_reagents(reagents.reagent_list)
add_overlay(I)
/obj/structure/geyser/process()
if(activated && reagents.total_volume <= reagents.maximum_volume) //this is also evaluated in add_reagent, but from my understanding proc calls are expensive
reagents.add_reagent(reagent_id, potency)
/obj/structure/geyser/plunger_act(obj/item/plunger/P, mob/living/user, _reinforced)
if(!_reinforced)
to_chat(user, "<span class='warning'>The [P.name] isn't strong enough!</span>")
return
if(activated)
to_chat(user, "<span class'warning'>The [name] is already active!</span>")
return
to_chat(user, "<span class='notice'>You start vigorously plunging [src]!</span>")
if(do_after(user, 50 * P.plunge_mod, target = src) && !activated)
start_chemming()
/obj/structure/geyser/random
erupting_state = null
var/list/options = list(/datum/reagent/clf3 = 10, /datum/reagent/water/hollowwater = 10, /datum/reagent/medicine/omnizine/protozine = 6, /datum/reagent/wittel = 1)
/obj/structure/geyser/random/Initialize()
. = ..()
reagent_id = pickweight(options)
/obj/item/plunger
name = "plunger"
desc = "It's a plunger for plunging."
icon = 'icons/obj/watercloset.dmi'
icon_state = "plunger"
slot_flags = ITEM_SLOT_MASK
var/plunge_mod = 1 //time*plunge_mod = total time we take to plunge an object
var/reinforced = FALSE //whether we do heavy duty stuff like geysers
/obj/item/plunger/attack_obj(obj/O, mob/living/user)
if(!O.plunger_act(src, user, reinforced))
return ..()
/obj/item/plunger/throw_impact(atom/hit_atom, datum/thrownthing/tt)
. = ..()
if(tt.target_zone != BODY_ZONE_HEAD)
return
if(iscarbon(hit_atom))
var/mob/living/carbon/H = hit_atom
if(!H.wear_mask)
H.equip_to_slot_if_possible(src, ITEM_SLOT_MASK)
H.visible_message("<span class='warning'>The plunger slams into [H]'s face!</span>", "<span class='warning'>The plunger suctions to your face!</span>")
/obj/item/plunger/reinforced
name = "reinforced plunger"
desc = "It's an M. 7 Reinforced Plunger© for heavy duty plunging."
icon_state = "reinforced_plunger"
reinforced = TRUE
plunge_mod = 0.8
custom_premium_price = 1200

View File

@@ -25,6 +25,9 @@
/obj/structure/spawner/lavaland/legion
mob_types = list(/mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril)
/obj/structure/spawner/lavaland/icewatcher
mob_types = list(/mob/living/simple_animal/hostile/asteroid/basilisk/watcher/icewing)
GLOBAL_LIST_INIT(tendrils, list())
/obj/structure/spawner/lavaland/Initialize()
. = ..()
@@ -94,4 +97,4 @@ GLOBAL_LIST_INIT(tendrils, list())
for(var/turf/T in range(2,src))
if(!T.density)
T.TerraformTurf(/turf/open/chasm/lavaland, /turf/open/chasm/lavaland, flags = CHANGETURF_INHERIT_AIR)
qdel(src)
qdel(src)

View File

@@ -38,7 +38,4 @@
user.show_message("<span class='notice'>You weave \the [S.name] into a workable fabric.</span>", MSG_VISUAL)
return TRUE
/obj/structure/loom/unanchored
anchored = FALSE
#undef FABRIC_PER_SHEET

View File

@@ -134,6 +134,15 @@
icon = 'icons/turf/walls.dmi'
icon_state = "icerock"
/turf/closed/indestructible/rock/snow/ice/ore
icon = 'icons/turf/walls/icerock_wall.dmi'
icon_state = "icerock"
smooth = SMOOTH_MORE|SMOOTH_BORDER
canSmoothWith = list (/turf/closed)
pixel_x = -4
pixel_y = -4
/turf/closed/indestructible/paper
name = "thick paper wall"
desc = "A wall layered with impenetrable sheets of paper."

View File

@@ -110,6 +110,9 @@
if(prob(12))
icon_state = "necro[rand(2,3)]"
/turf/open/indestructible/necropolis/ice
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/open/indestructible/necropolis/air
initial_gas_mix = OPENTURF_DEFAULT_ATMOS

View File

@@ -146,3 +146,13 @@ GLOBAL_DATUM_INIT(openspace_backdrop_one_for_all, /atom/movable/openspace_backdr
PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
return TRUE
return FALSE
/turf/open/openspace/icemoon
name = "ice chasm"
baseturfs = /turf/open/openspace/icemoon
can_cover_up = FALSE
can_build_on = FALSE
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/open/openspace/icemoon/can_zFall(atom/movable/A, levels = 1, turf/target)
return TRUE

View File

@@ -88,6 +88,15 @@
light_power = 0.65 //less bright, too
light_color = LIGHT_COLOR_LAVA //let's just say you're falling into lava, that makes sense right
// Chasms for Ice moon, with planetary atmos and glow
/turf/open/chasm/icemoon
icon = 'icons/turf/floors/icechasms.dmi'
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
planetary_atmos = TRUE
baseturfs = /turf/open/chasm/icemoon
light_range = 1.9
light_power = 0.65
light_color = LIGHT_COLOR_PURPLE
// Chasms for the jungle, with planetary atmos and a different icon
/turf/open/chasm/jungle
@@ -115,4 +124,4 @@
. = ..()
var/turf/T = safepick(get_area_turfs(/area/fabric_of_reality))
if(T)
set_target(T)
set_target(T)

View File

@@ -48,7 +48,9 @@
"oldburning","light-on-r","light-on-y","light-on-g","light-on-b", "wood", "carpetsymbol", "carpetstar",
"carpetcorner", "carpetside", "carpet", "ironsand1", "ironsand2", "ironsand3", "ironsand4", "ironsand5",
"ironsand6", "ironsand7", "ironsand8", "ironsand9", "ironsand10", "ironsand11",
"ironsand12", "ironsand13", "ironsand14", "ironsand15")
"ironsand12", "ironsand13", "ironsand14", "ironsand15",
"snow", "snow0", "snow1", "snow2", "snow3", "snow4", "snow5", "snow6", "snow7", "snow8", "snow9", "snow10", "snow11", "snow12", "snow-ice", "snow_dug",
"unsmooth", "smooth", "1-i", "2-i", "3-i", "4-i", "1-n", "2-n", "3-s", "4-s", "1-w", "2-e", "3-w", "4-e", "1-nw", "2-ne", "3-sw", "4-se", "1-f", "2-f", "3-f", "4-f")
if(broken || burnt || (icon_state in icons_to_ignore_at_floor_init)) //so damaged/burned tiles or plating icons aren't saved as the default
icon_regular_floor = "floor"
else

View File

@@ -13,11 +13,15 @@
barefootstep = FOOTSTEP_SAND
clawfootstep = FOOTSTEP_SAND
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
/// Environment type for the turf
var/environment_type = "asteroid"
/// Base turf type to be created by the tunnel
var/turf_type = /turf/open/floor/plating/asteroid //Because caves do whacky shit to revert to normal
var/floor_variance = 20 //probability floor has a different icon state
/// Probability the floor has a different icon state
var/floor_variance = 20
attachment_holes = FALSE
var/obj/item/stack/digResult = /obj/item/stack/ore/glass/basalt
/// Whether the turf has been dug or not
var/dug
/turf/open/floor/plating/asteroid/Initialize()
@@ -27,6 +31,7 @@
if(prob(floor_variance))
icon_state = "[environment_type][rand(0,12)]"
/// Drops itemstack when dug and changes icon
/turf/open/floor/plating/asteroid/proc/getDug()
new digResult(src, 5)
if(postdig_icon_change)
@@ -35,6 +40,7 @@
icon_state = "[environment_type]_dug"
dug = TRUE
/// If the user can dig the turf
/turf/open/floor/plating/asteroid/proc/can_dig(mob/user)
if(!dug)
return TRUE
@@ -135,16 +141,30 @@
#define SPAWN_BUBBLEGUM 6
/turf/open/floor/plating/asteroid/airless/cave
/// Length of the tunnel
var/length = 100
/// Mobs that can spawn in the tunnel, weighted list
var/list/mob_spawn_list
/// Megafauna that can spawn in the tunnel, weighted list
var/list/megafauna_spawn_list
/// Flora that can spawn in the tunnel, weighted list
var/list/flora_spawn_list
/// Turf type to choose when spawning in tunnel at 1% chance, weighted list
var/list/choose_turf_type
/// if the tunnel should keep being created
var/sanity = 1
/// Cave direction to move
var/forward_cave_dir = 1
/// Backwards cave direction for tracking
var/backward_cave_dir = 2
/// If the tunnel is moving backwards
var/going_backwards = TRUE
/// If this is a cave creating type
var/has_data = FALSE
/// The non-cave creating type
var/data_having_type = /turf/open/floor/plating/asteroid/airless/cave/has_data
/// Option tunnel width, wegihted list
var/list/pick_tunnel_width
turf_type = /turf/open/floor/plating/asteroid/airless
/turf/open/floor/plating/asteroid/airless/cave/has_data //subtype for producing a tunnel with given data
@@ -163,6 +183,47 @@
/turf/open/floor/plating/asteroid/airless/cave/volcanic/has_data //subtype for producing a tunnel with given data
has_data = TRUE
/turf/open/floor/plating/asteroid/airless/cave/snow
gender = PLURAL
name = "snow"
desc = "Looks cold."
icon = 'icons/turf/snow.dmi'
baseturfs = /turf/open/floor/plating/asteroid/snow/icemoon
icon_state = "snow"
icon_plating = "snow"
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
slowdown = 2
environment_type = "snow"
flags_1 = NONE
planetary_atmos = TRUE
burnt_states = list("snow_dug")
bullet_sizzle = TRUE
bullet_bounce_sound = null
digResult = /obj/item/stack/sheet/mineral/snow
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)
flora_spawn_list = list(/obj/structure/flora/tree/pine = 2, /obj/structure/flora/grass/both = 12)
data_having_type = /turf/open/floor/plating/asteroid/airless/cave/snow/has_data
turf_type = /turf/open/floor/plating/asteroid/snow/icemoon
choose_turf_type = list(/turf/open/floor/plating/asteroid/snow/icemoon = 19, /turf/open/floor/plating/ice/icemoon = 1)
pick_tunnel_width = list("1" = 6, "2" = 1)
/turf/open/floor/plating/asteroid/airless/cave/snow/underground
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)
flora_spawn_list = list(/obj/structure/flora/rock/icy = 6, /obj/structure/flora/rock/pile/icy = 6)
data_having_type = /turf/open/floor/plating/asteroid/airless/cave/snow/underground/has_data
choose_turf_type = null
/turf/open/floor/plating/asteroid/airless/cave/snow/has_data //subtype for producing a tunnel with given data
has_data = TRUE
/turf/open/floor/plating/asteroid/airless/cave/snow/underground/has_data //subtype for producing a tunnel with given data
has_data = TRUE
/turf/open/floor/plating/asteroid/airless/cave/Initialize()
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)
@@ -175,6 +236,7 @@
if(!has_data)
produce_tunnel_from_data()
/// Sets the tunnel length and direction
/turf/open/floor/plating/asteroid/airless/cave/proc/get_cave_data(set_length, exclude_dir = -1)
// If set_length (arg1) isn't defined, get a random length; otherwise assign our length to the length arg.
if(!set_length)
@@ -187,6 +249,7 @@
// Get the opposite direction of our facing direction
backward_cave_dir = angle2dir(dir2angle(forward_cave_dir) + 180)
/// Gets the tunnel length and direction then makes the tunnel
/turf/open/floor/plating/asteroid/airless/cave/proc/produce_tunnel_from_data(tunnel_length, excluded_dir = -1)
get_cave_data(tunnel_length, excluded_dir)
// Make our tunnels
@@ -196,10 +259,22 @@
// Kill ourselves by replacing ourselves with a normal floor.
SpawnFloor(src)
/**
* Makes the tunnel and spawns things inside of it
*
* Picks a tunnel width for the tunnel and then starts spawning turfs in the direction it moves in
* Can randomly change directions of the tunnel, stops if it hits the edge of the map, or a no tunnel area
* Can randomly make new tunnels out of itself
*
*/
/turf/open/floor/plating/asteroid/airless/cave/proc/make_tunnel(dir)
var/turf/closed/mineral/tunnel = src
var/next_angle = pick(45, -45)
var/tunnel_width = 1
if(pick_tunnel_width)
tunnel_width = text2num(pickweight(pick_tunnel_width))
for(var/i = 0; i < length; i++)
if(!sanity)
break
@@ -210,9 +285,11 @@
// Expand the edges of our tunnel
for(var/edge_angle in L)
var/turf/closed/mineral/edge = get_step(tunnel, angle2dir(dir2angle(dir) + edge_angle))
if(istype(edge))
SpawnFloor(edge)
var/turf/closed/mineral/edge = tunnel
for(var/current_tunnel_width = 1 to tunnel_width)
edge = get_step(edge, angle2dir(dir2angle(dir) + edge_angle))
if(istype(edge))
SpawnFloor(edge)
if(!sanity)
break
@@ -223,9 +300,12 @@
if(istype(tunnel))
// Small chance to have forks in our tunnel; otherwise dig our tunnel.
if(i > 3 && prob(20))
if(istype(tunnel.loc, /area/mine/explored) || (istype(tunnel.loc, /area/lavaland/surface/outdoors) && !istype(tunnel.loc, /area/lavaland/surface/outdoors/unexplored)))
sanity = 0
break
if(isarea(tunnel.loc))
var/area/A = tunnel.loc
if(!A.tunnel_allowed)
sanity = 0
break
var/turf/open/floor/plating/asteroid/airless/cave/C = tunnel.ChangeTurf(data_having_type, null, CHANGETURF_IGNORE_AIR)
C.going_backwards = FALSE
C.produce_tunnel_from_data(rand(10, 15), dir)
@@ -241,26 +321,35 @@
setDir(angle2dir(dir2angle(dir) )+ next_angle)
/// Spawns the floor of the tunnel and any type of structure or mob it can have
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnFloor(turf/T)
for(var/S in RANGE_TURFS(1, src))
var/turf/NT = S
if(!NT || isspaceturf(NT) || istype(NT.loc, /area/mine/explored) || (istype(NT.loc, /area/lavaland/surface/outdoors) && !istype(NT.loc, /area/lavaland/surface/outdoors/unexplored)))
sanity = 0
break
if(!sanity)
var/area/A = T.loc
if(!A.tunnel_allowed)
sanity = 0
return
SpawnFlora(T)
SpawnMonster(T)
if(choose_turf_type)
turf_type = pickweight(choose_turf_type)
if(turf_type == initial(turf_type)) // Don't spawn different turf types under flora or terrain
var/spawned_flora = FALSE
if(is_mining_level(z))
spawned_flora = SpawnFlora(T)
if(!spawned_flora) // no rocks beneath mob spawners / mobs.
SpawnMonster(T)
T.ChangeTurf(turf_type, null, CHANGETURF_IGNORE_AIR)
/// Spawns a random mob or megafauna in the tunnel
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnMonster(turf/T)
if(!isarea(loc))
return
var/area/A = loc
if(prob(30))
if(istype(loc, /area/mine/explored) || !istype(loc, /area/lavaland/surface/outdoors/unexplored))
if(!A.mob_spawn_allowed)
return
var/randumb = pickweight(mob_spawn_list)
if(!randumb)
return
while(randumb == SPAWN_MEGAFAUNA)
if(istype(loc, /area/lavaland/surface/outdoors/unexplored/danger)) //this is danger. it's boss time.
if(A.megafauna_spawn_allowed && megafauna_spawn_list && megafauna_spawn_list.len) //this is danger. it's boss time.
var/maybe_boss = pickweight(megafauna_spawn_list)
if(megafauna_spawn_list[maybe_boss])
randumb = maybe_boss
@@ -278,22 +367,26 @@
return //prevents tendrils spawning in each other's collapse range
new randumb(T)
return
return TRUE
#undef SPAWN_MEGAFAUNA
#undef SPAWN_BUBBLEGUM
/// Spawns a random flora in the tunnel, can spawn clumps of them.
/turf/open/floor/plating/asteroid/airless/cave/proc/SpawnFlora(turf/T)
if(prob(12))
if(istype(loc, /area/mine/explored) || istype(loc, /area/lavaland/surface/outdoors/explored))
return
if(isarea(loc))
var/area/A = loc
if(!A.flora_allowed)
return
var/randumb = pickweight(flora_spawn_list)
for(var/obj/structure/flora/ash/F in range(4, T)) //Allows for growing patches, but not ridiculous stacks of flora
if(!randumb)
return
for(var/obj/structure/flora/F in range(4, T)) // Allows for growing patches, but not ridiculous stacks of flora
if(!istype(F, randumb))
return
new randumb(T)
return TRUE
/turf/open/floor/plating/asteroid/snow
gender = PLURAL
@@ -322,6 +415,15 @@
return TRUE
return FALSE
/turf/open/floor/plating/asteroid/snow/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/open/lava/plasma/ice_moon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
baseturfs = /turf/open/lava/plasma/ice_moon
planetary_atmos = TRUE
/turf/open/floor/plating/asteroid/snow/ice
name = "icy snow"
desc = "Looks colder."
@@ -336,6 +438,15 @@
clawfootstep = FOOTSTEP_HARD_CLAW
heavyfootstep = FOOTSTEP_GENERIC_HEAVY
/turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
planetary_atmos = TRUE
/turf/open/floor/plating/asteroid/snow/ice/icemoon/solarpanel
icon = 'icons/turf/floors.dmi'
icon_state = "solarpanel"
/turf/open/floor/plating/asteroid/snow/ice/burn_tile()
return FALSE
@@ -347,4 +458,4 @@
/turf/open/floor/plating/asteroid/snow/atmosphere
initial_gas_mix = FROZEN_ATMOS
planetary_atmos = FALSE
planetary_atmos = FALSE

View File

@@ -3,6 +3,10 @@
icon_state = "plating"
initial_gas_mix = AIRLESS_ATMOS
/turf/open/floor/plating/icemoon
icon_state = "plating"
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/open/floor/plating/abductor
name = "alien floor"
icon_state = "alienpod1"
@@ -209,6 +213,8 @@
/turf/open/floor/plating/ice/burn_tile()
return
/turf/open/floor/plating/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/open/floor/plating/snowed
name = "snowed-over plating"
@@ -240,4 +246,6 @@
/turf/open/floor/plating/snowed/temperatre
temperature = 255.37
/turf/open/floor/plating/snowed/smoothed/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS

View File

@@ -147,6 +147,11 @@
var/mineralChance = 13
var/display_icon_state = "rock"
/turf/closed/mineral/random/more_caves
mineralSpawnChanceList = list(/turf/closed/mineral/uranium = 5, /turf/closed/mineral/diamond = 1, /turf/closed/mineral/gold = 10,
/turf/closed/mineral/silver = 12, /turf/closed/mineral/plasma = 20, /turf/closed/mineral/iron = 40, /turf/closed/mineral/titanium = 11,
/turf/closed/mineral/gibtonite = 4, /turf/open/floor/plating/asteroid/airless/cave = 15, /turf/closed/mineral/bscrystal = 1)
/turf/closed/mineral/random/Initialize()
mineralSpawnChanceList = typelist("mineralSpawnChanceList", mineralSpawnChanceList)
@@ -195,11 +200,27 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/volcanic = 35, /turf/closed/mineral/diamond/volcanic = 30, /turf/closed/mineral/gold/volcanic = 45, /turf/closed/mineral/titanium/volcanic = 45,
/turf/closed/mineral/silver/volcanic = 50, /turf/closed/mineral/plasma/volcanic = 50, /turf/closed/mineral/bscrystal/volcanic = 20)
/turf/closed/mineral/random/high_chance/snow
name = "snowy mountainside"
icon = 'icons/turf/mining.dmi'
smooth_icon = 'icons/turf/walls/mountain_wall.dmi'
icon_state = "mountainrock"
smooth = SMOOTH_MORE|SMOOTH_BORDER
canSmoothWith = list (/turf/closed)
defer_change = TRUE
environment_type = "snow"
turf_type = /turf/open/floor/plating/asteroid/snow/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/ice/icemoon = 35, /turf/closed/mineral/diamond/ice/icemoon = 30, /turf/closed/mineral/gold/ice/icemoon = 45, /turf/closed/mineral/titanium/ice/icemoon = 45,
/turf/closed/mineral/silver/ice/icemoon = 50, /turf/closed/mineral/plasma/ice/icemoon = 50, /turf/closed/mineral/bscrystal/ice/icemoon = 20)
/turf/closed/mineral/random/high_chance/earth_like
icon_state = "rock_highchance_oxy"
turf_type = /turf/open/floor/plating/asteroid
@@ -236,7 +257,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
mineralChance = 10
mineralSpawnChanceList = list(
@@ -244,6 +265,36 @@
/turf/closed/mineral/silver/volcanic = 12, /turf/closed/mineral/plasma/volcanic = 20, /turf/closed/mineral/iron/volcanic = 40,
/turf/closed/mineral/gibtonite/volcanic = 4, /turf/open/floor/plating/asteroid/airless/cave/volcanic = 1, /turf/closed/mineral/bscrystal/volcanic = 1)
/turf/closed/mineral/random/volcanic/more_caves
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/volcanic = 5, /turf/closed/mineral/diamond/volcanic = 1, /turf/closed/mineral/gold/volcanic = 10, /turf/closed/mineral/titanium/volcanic = 11,
/turf/closed/mineral/silver/volcanic = 12, /turf/closed/mineral/plasma/volcanic = 20, /turf/closed/mineral/iron/volcanic = 40,
/turf/closed/mineral/gibtonite/volcanic = 4, /turf/open/floor/plating/asteroid/airless/cave/volcanic = 15, /turf/closed/mineral/bscrystal/volcanic = 1)
/turf/closed/mineral/random/snow
name = "snowy mountainside"
icon = 'icons/turf/mining.dmi'
smooth_icon = 'icons/turf/walls/mountain_wall.dmi'
icon_state = "mountainrock"
smooth = SMOOTH_MORE|SMOOTH_BORDER
canSmoothWith = list (/turf/closed)
defer_change = TRUE
environment_type = "snow"
turf_type = /turf/open/floor/plating/asteroid/snow/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
mineralChance = 10
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/ice/icemoon = 5, /turf/closed/mineral/diamond/ice/icemoon = 1, /turf/closed/mineral/gold/ice/icemoon = 10, /turf/closed/mineral/titanium/ice/icemoon = 11,
/turf/closed/mineral/silver/ice/icemoon = 12, /turf/closed/mineral/plasma/ice/icemoon = 20, /turf/closed/mineral/iron/ice/icemoon = 40,
/turf/closed/mineral/gibtonite/ice/icemoon = 4, /turf/open/floor/plating/asteroid/airless/cave/snow = 1, /turf/closed/mineral/bscrystal/ice/icemoon = 1)
/turf/closed/mineral/random/snow/no_caves
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/ice/icemoon = 5, /turf/closed/mineral/diamond/ice/icemoon = 1, /turf/closed/mineral/gold/ice/icemoon = 10, /turf/closed/mineral/titanium/ice/icemoon = 11,
/turf/closed/mineral/silver/ice/icemoon = 12, /turf/closed/mineral/plasma/ice/icemoon = 20, /turf/closed/mineral/iron/ice/icemoon = 40,
/turf/closed/mineral/gibtonite/ice/icemoon = 4, /turf/closed/mineral/bscrystal/ice/icemoon = 1)
/turf/closed/mineral/random/labormineral
mineralSpawnChanceList = list(
@@ -252,18 +303,51 @@
/turf/closed/mineral/gibtonite = 2)
icon_state = "rock_labor"
/turf/closed/mineral/random/snow/underground
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/ice/icemoon = 5, /turf/closed/mineral/diamond/ice/icemoon = 1, /turf/closed/mineral/gold/ice/icemoon = 10, /turf/closed/mineral/titanium/ice/icemoon = 11,
/turf/closed/mineral/silver/ice/icemoon = 12, /turf/closed/mineral/plasma/ice/icemoon = 20, /turf/closed/mineral/iron/ice/icemoon = 40,
/turf/closed/mineral/gibtonite/ice/icemoon = 4, /turf/open/floor/plating/asteroid/airless/cave/snow/underground = 1, /turf/closed/mineral/bscrystal/ice/icemoon = 1)
/turf/closed/mineral/random/snow/more_caves
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/ice/icemoon = 5, /turf/closed/mineral/diamond/ice/icemoon = 1, /turf/closed/mineral/gold/ice/icemoon = 10, /turf/closed/mineral/titanium/ice/icemoon = 11,
/turf/closed/mineral/silver/ice/icemoon = 12, /turf/closed/mineral/plasma/ice/icemoon = 20, /turf/closed/mineral/iron/ice/icemoon = 40,
/turf/closed/mineral/gibtonite/ice/icemoon = 4, /turf/open/floor/plating/asteroid/airless/cave/snow = 15, /turf/closed/mineral/bscrystal/ice/icemoon = 1)
/turf/closed/mineral/random/labormineral/volcanic
environment_type = "basalt"
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/volcanic = 3, /turf/closed/mineral/diamond/volcanic = 1, /turf/closed/mineral/gold/volcanic = 8, /turf/closed/mineral/titanium/volcanic = 8,
/turf/closed/mineral/silver/volcanic = 20, /turf/closed/mineral/plasma/volcanic = 30, /turf/closed/mineral/bscrystal/volcanic = 1, /turf/closed/mineral/gibtonite/volcanic = 2,
/turf/closed/mineral/iron/volcanic = 95)
//Subtypes for placing ores manually.
/turf/closed/mineral/random/labormineral/ice
name = "snowy mountainside"
icon = 'icons/turf/mining.dmi'
smooth_icon = 'icons/turf/walls/mountain_wall.dmi'
icon_state = "mountainrock"
smooth = SMOOTH_MORE|SMOOTH_BORDER
canSmoothWith = list (/turf/closed)
defer_change = TRUE
environment_type = "snow"
turf_type = /turf/open/floor/plating/asteroid/snow/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
defer_change = TRUE
mineralSpawnChanceList = list(
/turf/closed/mineral/uranium/ice/icemoon = 3, /turf/closed/mineral/diamond/ice/icemoon = 1, /turf/closed/mineral/gold/ice/icemoon = 8, /turf/closed/mineral/titanium/ice/icemoon = 8,
/turf/closed/mineral/silver/ice/icemoon = 20, /turf/closed/mineral/plasma/ice/icemoon = 30, /turf/closed/mineral/bscrystal/ice/icemoon = 1, /turf/closed/mineral/gibtonite/ice/icemoon = 2,
/turf/closed/mineral/iron/ice/icemoon = 95)
/turf/closed/mineral/iron
mineralType = /obj/item/stack/ore/iron
@@ -294,6 +378,11 @@
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/iron/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/uranium
mineralType = /obj/item/stack/ore/uranium
@@ -306,7 +395,21 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/uranium/ice
environment_type = "snow_cavern"
icon_state = "icerock_Uranium"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/uranium/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/uranium/earth_like
icon_state = "rock_oxy"
@@ -327,7 +430,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/diamond/earth_like
icon_state = "rock_oxy"
@@ -345,6 +448,11 @@
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/diamond/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/gold
mineralType = /obj/item/stack/ore/gold
@@ -357,7 +465,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/gold/earth_like
icon_state = "rock_oxy"
@@ -366,6 +474,19 @@
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/gold/ice
environment_type = "snow_cavern"
icon_state = "icerock_gold"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/gold/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/silver
mineralType = /obj/item/stack/ore/silver
@@ -378,7 +499,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/silver/earth_like
icon_state = "rock_oxy"
@@ -387,6 +508,19 @@
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/silver/ice
environment_type = "snow_cavern"
icon_state = "icerock_silver"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/silver/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/titanium
mineralType = /obj/item/stack/ore/titanium
@@ -399,7 +533,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/titanium/earth_like
icon_state = "rock_oxy"
@@ -408,6 +542,19 @@
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/titanium/ice
environment_type = "snow_cavern"
icon_state = "icerock_titanium"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/titanium/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/plasma
mineralType = /obj/item/stack/ore/plasma
@@ -420,7 +567,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/plasma/earth_like
icon_state = "rock_oxy"
@@ -438,6 +585,10 @@
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/plasma/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/bananium
@@ -454,6 +605,21 @@
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/bananium/ice
environment_type = "snow_cavern"
icon_state = "icerock_Bananium"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/bananium/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/bscrystal
mineralType = /obj/item/stack/ore/bluespace_crystal
mineralAmt = 1
@@ -466,7 +632,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/bscrystal/earth_like
icon_state = "rock_oxy"
@@ -475,6 +641,19 @@
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/bscrystal/ice
environment_type = "snow_cavern"
icon_state = "icerock_BScrystal"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/bscrystal/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/volcanic
environment_type = "basalt"
@@ -486,7 +665,7 @@
environment_type = "basalt"
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/earth_like
icon_state = "rock_oxy"
@@ -506,7 +685,7 @@
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
environment_type = "waste"
turf_type = /turf/open/floor/plating/ashplanet/rocky
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/snowmountain
name = "snowy mountainside"
@@ -521,6 +700,11 @@
turf_type = /turf/open/floor/plating/asteroid/snow
defer_change = TRUE
/turf/closed/mineral/snowmountain/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
/turf/closed/mineral/snowmountain/cavern
name = "ice cavern rock"
icon = 'icons/turf/mining.dmi'
@@ -532,6 +716,11 @@
environment_type = "snow_cavern"
turf_type = /turf/open/floor/plating/asteroid/snow/ice
/turf/closed/mineral/snowmountain/cavern/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS
//GIBTONITE
/turf/closed/mineral/gibtonite
@@ -634,7 +823,7 @@
turf_type = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
baseturfs = /turf/open/floor/plating/asteroid/basalt/lava_land_surface
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
defer_change = 1
defer_change = TRUE
/turf/closed/mineral/gibtonite/earth_like
icon_state = "rock_oxy"
@@ -642,3 +831,18 @@
baseturfs = /turf/open/floor/plating/asteroid
initial_gas_mix = OPENTURF_DEFAULT_ATMOS
defer_change = TRUE
/turf/closed/mineral/gibtonite/ice
environment_type = "snow_cavern"
icon_state = "icerock_Gibtonite"
smooth_icon = 'icons/turf/walls/icerock_wall.dmi'
turf_type = /turf/open/floor/plating/asteroid/snow/ice
baseturfs = /turf/open/floor/plating/asteroid/snow/ice
initial_gas_mix = FROZEN_ATMOS
defer_change = TRUE
/turf/closed/mineral/gibtonite/ice/icemoon
turf_type = /turf/open/floor/plating/asteroid/snow/ice/icemoon
baseturfs = /turf/open/floor/plating/asteroid/snow/ice/icemoon
initial_gas_mix = ICEMOON_DEFAULT_ATMOS

View File

@@ -8,8 +8,9 @@ GLOBAL_LIST(topic_status_cache)
//This happens after the Master subsystem new(s) (it's a global datum)
//So subsystems globals exist, but are not initialised
/world/New()
if(fexists("byond-extools.dll"))
call("byond-extools.dll", "maptick_initialize")()
var/extools = world.GetConfig("env", "EXTOOLS_DLL") || "./byond-extools.dll"
if (fexists(extools))
call(extools, "maptick_initialize")()
enable_debugger()
world.Profile(PROFILE_START)

View File

@@ -764,7 +764,6 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
for(var/arg in arguments)
new_args[++new_args.len] = SDQL_expression(source, arg)
if(object == GLOB) // Global proc.
procname = "/proc/[procname]"
return superuser? (call(procname)(new_args)) : (WrapAdminProcCall(GLOBAL_PROC, procname, new_args))
return superuser? (call(object, procname)(new_args)) : (WrapAdminProcCall(object, procname, new_args))

View File

@@ -705,10 +705,17 @@
var/list/names = list()
names += "---- Space Ruins ----"
for(var/name in SSmapping.space_ruins_templates)
names[name] = list(SSmapping.space_ruins_templates[name], ZTRAIT_SPACE_RUINS, /area/space)
names[name] = list(SSmapping.space_ruins_templates[name], ZTRAIT_SPACE_RUINS, list(/area/space))
names += "---- Lava Ruins ----"
for(var/name in SSmapping.lava_ruins_templates)
names[name] = list(SSmapping.lava_ruins_templates[name], ZTRAIT_LAVA_RUINS, /area/lavaland/surface/outdoors/unexplored)
names[name] = list(SSmapping.lava_ruins_templates[name], ZTRAIT_LAVA_RUINS, list(/area/lavaland/surface/outdoors/unexplored))
names += "---- Ice Ruins ----"
for(var/name in SSmapping.ice_ruins_templates)
names[name] = list(SSmapping.ice_ruins_templates[name], ZTRAIT_ICE_RUINS, list(/area/icemoon/surface/outdoors/unexplored, /area/icemoon/underground/unexplored))
names += "---- Ice Underground Ruins ----"
for(var/name in SSmapping.ice_ruins_underground_templates)
names[name] = list(SSmapping.ice_ruins_underground_templates[name], ZTRAIT_ICE_RUINS_UNDERGROUND, list(/area/icemoon/underground/unexplored))
var/ruinname = input("Select ruin", "Spawn Ruin") as null|anything in names
var/data = names[ruinname]

View File

@@ -18,9 +18,12 @@
var/image/item = image('icons/turf/overlays.dmi',S,"greenOverlay")
item.plane = ABOVE_LIGHTING_PLANE
preview += item
var/list/orientations = list("South" = SOUTH, "North" = NORTH, "East" = EAST, "West" = WEST)
var/choice = input(src, "Which orientation? Maps are normally facing SOUTH.", "Template Orientation", "South") as null|anything in orientations
var/orientation = orientations[choice]
images += preview
if(alert(src,"Confirm location.","Template Confirm","Yes","No") == "Yes")
if(template.load(T, centered = TRUE))
if(template.load(T, centered = TRUE, orientation = orientation))
message_admins("<span class='adminnotice'>[key_name_admin(src)] has placed a map template ([template.name]) at [ADMIN_COORDJMP(T)]</span>")
else
to_chat(src, "Failed to place map")

View File

@@ -27,6 +27,9 @@
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
if(isturf(L.loc))
spawn_locs += L.loc
for(var/obj/effect/landmark/loneopspawn/L in GLOB.landmarks_list)
if(isturf(L.loc))
spawn_locs += L.loc
if(!spawn_locs)
message_admins("No valid spawn locations found, aborting...")

View File

@@ -90,7 +90,7 @@
. = TRUE
update_icon()
/obj/item/assembly/signaler/attackby(obj/item/W, mob/user, params)
if(issignaler(W))
var/obj/item/assembly/signaler/signaler2 = W
@@ -162,7 +162,6 @@
return
return ..(signal)
// Embedded signaller used in anomalies.
/obj/item/assembly/signaler/anomaly
name = "anomaly core"
@@ -179,12 +178,53 @@
return FALSE
if(signal.data["code"] != code)
return FALSE
if(suicider)
manual_suicide(suicider)
for(var/obj/effect/anomaly/A in get_turf(src))
A.anomalyNeutralize()
return TRUE
/obj/item/assembly/signaler/anomaly/attack_self()
return
/obj/item/assembly/signaler/anomaly/manual_suicide(mob/living/carbon/user)
user.visible_message("<span class='suicide'>[user]'s [src] is reacting to the radio signal, warping [user.p_their()] body!</span>")
user.suiciding = TRUE
user.suicide_log()
user.gib()
/obj/item/assembly/signaler/anomaly/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_ANALYZER)
to_chat(user, "<span class='notice'>Analyzing... [src]'s stabilized field is fluctuating along frequency [format_frequency(frequency)], code [code].</span>")
..()
//Anomaly cores
/obj/item/assembly/signaler/anomaly/pyro
name = "\improper pyroclastic anomaly core"
desc = "The neutralized core of a pyroclastic anomaly. It feels warm to the touch. It'd probably be valuable for research."
icon_state = "pyro core"
anomaly_type = /obj/effect/anomaly/pyro
/obj/item/assembly/signaler/anomaly/grav
name = "\improper gravitational anomaly core"
desc = "The neutralized core of a gravitational anomaly. It feels much heavier than it looks. It'd probably be valuable for research."
icon_state = "grav core"
anomaly_type = /obj/effect/anomaly/grav
/obj/item/assembly/signaler/anomaly/flux
name = "\improper flux anomaly core"
desc = "The neutralized core of a flux anomaly. Touching it makes your skin tingle. It'd probably be valuable for research."
icon_state = "flux core"
anomaly_type = /obj/effect/anomaly/flux
/obj/item/assembly/signaler/anomaly/bluespace
name = "\improper bluespace anomaly core"
desc = "The neutralized core of a bluespace anomaly. It keeps phasing in and out of view. It'd probably be valuable for research."
icon_state = "anomaly core"
anomaly_type = /obj/effect/anomaly/bluespace
/obj/item/assembly/signaler/anomaly/vortex
name = "\improper vortex anomaly core"
desc = "The neutralized core of a vortex anomaly. It won't sit still, as if some invisible force is acting on it. It'd probably be valuable for research."
icon_state = "vortex core"
anomaly_type = /obj/effect/anomaly/bhole
/obj/item/assembly/signaler/cyborg

View File

@@ -28,6 +28,8 @@
/obj/machinery/atmospherics/pipe/manifold/update_icon()
cut_overlays()
if(!center)
center = mutable_appearance(icon, "manifold_center")
PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
add_overlay(center)

View File

@@ -26,6 +26,8 @@
/obj/machinery/atmospherics/pipe/manifold4w/update_icon()
cut_overlays()
if(!center)
center = mutable_appearance(icon, "manifold_center")
PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
add_overlay(center)

View File

@@ -76,19 +76,3 @@
/datum/export/manifest_correct_denied/get_cost(obj/O)
var/obj/item/paper/fluff/jobs/cargo/manifest/M = O
return ..() - M.order_cost
// Paper work done correctly
/datum/export/paperwork_correct
cost = 120 // finicky number 20 x 120 = 2400 per crate
k_elasticity = 0
unit_name = "correct paperwork"
export_types = list(/obj/item/folder/paperwork_correct)
// Paper work not done retruned
/datum/export/paperwork_incorrect
cost = -500 // Failed to meet NT standers
k_elasticity = 0
unit_name = "returned incorrect paperwork"
export_types = list(/obj/item/folder/paperwork)

View File

@@ -148,15 +148,7 @@
crate_name = "supermatter shard crate"
crate_type = /obj/structure/closet/crate/secure/engineering
dangerous = TRUE
/datum/supply_pack/engine/supermatter_spray
name = "Supermatter Spray Crate"
desc = "The single thing that can truly heal the supermatter."
cost = 2000
contains = list(/obj/item/supermatterspray)
crate_name = "supermatter shard crate"
crate_type = /obj/structure/closet/crate/engineering/electrical
/datum/supply_pack/engine/tesla_coils
name = "Tesla Coil Crate"
desc = "Whether it's high-voltage executions, creating research points, or just plain old power generation: This pack of four Tesla coils can do it all!"

View File

@@ -129,14 +129,6 @@
/obj/item/rcd_ammo)
crate_name = "rcd ammo"
/datum/supply_pack/materials/loom
name = "Loom"
desc = "A large pre-made loom."
cost = 1000
contains = list(/obj/structure/loom/unanchored)
crate_name = "loom crate"
crate_type = /obj/structure/closet/crate/large
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// Canisters //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

View File

@@ -87,37 +87,12 @@
crate_type = /obj/structure/closet/crate/wooden
crate_name = "calligraphy crate"
/datum/supply_pack/misc/paper_work
name = "Freelance Paper work"
desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
cost = 700 // Net of 0 credits but makes (120 x 10 = 1200)
contains = list(/obj/item/folder/paperwork,
/obj/item/pen/fountain
)
crate_name = "Paperwork"
/datum/supply_pack/misc/paper_work/generate()
. = ..()
for(var/i in 1 to 9)
new /obj/item/folder/paperwork(.)
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////// Entertainment ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////
/datum/supply_pack/misc/randombedsheets
name = "Bedsheet Crate (R)"
desc = "Snuggle up in some sweet sheets with this assorted bedsheet crate. Each set comes with eight random bedsheets for your slumbering pleasure!"
cost = 2000
contains = list(/obj/item/bedsheet/random)
crate_name = "random bedsheet crate"
/datum/supply_pack/misc/randombedsheets/generate()
. = ..()
for(var/i in 1 to 7)
new /obj/item/bedsheet/random(.)
/datum/supply_pack/misc/coloredsheets
name = "Bedsheet Crate (C)"
name = "Bedsheet Crate"
desc = "Give your night life a splash of color with this crate filled with bedsheets! Contains a total of nine different-colored sheets."
cost = 1250
contains = list(/obj/item/bedsheet/blue,

View File

@@ -94,8 +94,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/skin_tone = "caucasian1" //Skin color
var/use_custom_skin_tone = FALSE
var/eye_color = "000" //Eye color
var/horn_color = "85615a" //Horn color
var/wing_color = "fff" //Wing color
var/datum/species/pref_species = new /datum/species/human() //Mutant race
var/list/features = list("mcolor" = "FFF",
"mcolor2" = "FFF",
@@ -104,8 +102,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"tail_human" = "None",
"snout" = "Round",
"horns" = "None",
"horns_color" = "85615a",
"ears" = "None",
"wings" = "None",
"wings_color" = "FFF",
"frills" = "None",
"deco_wings" = "None",
"spines" = "None",
@@ -496,7 +496,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h3>Horns</h3>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=horns;task=input'>[features["horns"]]</a>"
dat += "<span style='border:1px solid #161616; background-color: #[horn_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=horns_color;task=input'>Change</a><BR>"
dat += "<span style='border:1px solid #161616; background-color: #[features["horns_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=horns_color;task=input'>Change</a><BR>"
mutant_category++
@@ -609,7 +609,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h3>Decorative wings</h3>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=deco_wings;task=input'>[features["deco_wings"]]</a>"
dat += "<span style='border:1px solid #161616; background-color: #[wing_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=wings_color;task=input'>Change</a><BR>"
dat += "<span style='border:1px solid #161616; background-color: #[features["wings_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=wings_color;task=input'>Change</a><BR>"
if(pref_species.mutant_bodyparts["insect_wings"])
if(!mutant_category)
@@ -618,7 +618,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<h3>Insect wings</h3>"
dat += "<a style='display:block;width:100px' href='?_src_=prefs;preference=insect_wings;task=input'>[features["insect_wings"]]</a>"
dat += "<span style='border:1px solid #161616; background-color: #[wing_color];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=wings_color;task=input'>Change</a><BR>"
dat += "<span style='border:1px solid #161616; background-color: #[features["wings_color"]];'>&nbsp;&nbsp;&nbsp;</span> <a href='?_src_=prefs;preference=wings_color;task=input'>Change</a><BR>"
mutant_category++
if(mutant_category >= MAX_MUTANT_ROWS)
dat += "</td>"
@@ -1770,12 +1770,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["horns"] = new_horns
if("horns_color")
var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+horn_color) as color|null
var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+features["horns_color"]) as color|null
if(new_horn_color)
if (new_horn_color == "#000000")
horn_color = "#85615A"
features["horns_color"] = "85615A"
else
horn_color = sanitize_hexcolor(new_horn_color)
features["horns_color"] = sanitize_hexcolor(new_horn_color)
if("wings")
var/new_wings
@@ -1784,12 +1784,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["wings"] = new_wings
if("wings_color")
var/new_wing_color = input(user, "Choose your character's wing colour:", "Character Preference","#"+wing_color) as color|null
var/new_wing_color = input(user, "Choose your character's wing colour:", "Character Preference","#"+features["wings_color"]) as color|null
if(new_wing_color)
if (new_wing_color == "#000000")
wing_color = "#FFFFFF"
features["wings_color"] = "#FFFFFF"
else
wing_color = sanitize_hexcolor(new_wing_color)
features["wings_color"] = sanitize_hexcolor(new_wing_color)
if("frills")
var/new_frills
@@ -2459,9 +2459,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
organ_eyes.old_eye_color = eye_color
character.hair_color = hair_color
character.facial_hair_color = facial_hair_color
character.horn_color = horn_color
character.wing_color = wing_color
character.skin_tone = skin_tone
character.dna.skin_tone_override = use_custom_skin_tone ? skin_tone : null
character.hair_style = hair_style

View File

@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 29
#define SAVEFILE_VERSION_MAX 30
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -181,7 +181,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(lickable)
ENABLE_BITFIELD(vore_flags,LICKABLE)
if(current_version < 29)
if(current_version < 30)
switch(features["taur"])
if("Husky", "Lab", "Shepherd", "Fox", "Wolf")
features["taur"] = "Canine"
@@ -190,6 +190,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if("Cow")
features["taur"] = "Cow (Spotted)"
if(current_version < 31)
S["wing_color"] >> features["wings_color"]
S["horn_color"] >> features["horns_color"]
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
@@ -421,15 +425,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(newtype)
pref_species = new newtype
if(!S["features["mcolor"]"] || S["features["mcolor"]"] == "#000")
WRITE_FILE(S["features["mcolor"]"] , "#FFF")
if(!S["features["horn_color"]"] || S["features["horn_color"]"] == "#000")
WRITE_FILE(S["features["horn_color"]"] , "#85615a")
if(!S["features["wing_color"]"] || S["features["wing_color"]"] == "#000")
WRITE_FILE(S["features["wing_color"]"] , "#FFF")
//Character
S["real_name"] >> real_name
S["nameless"] >> nameless
@@ -453,8 +448,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["shirt_color"] >> shirt_color
S["socks"] >> socks
S["socks_color"] >> socks_color
S["horn_color"] >> horn_color
S["wing_color"] >> wing_color
S["backbag"] >> backbag
S["jumpsuit_style"] >> jumpsuit_style
S["uplink_loc"] >> uplink_spawn_loc
@@ -564,15 +557,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(!custom_names[custom_name_id])
custom_names[custom_name_id] = get_default_name(custom_name_id)
if(!features["mcolor"] || features["mcolor"] == "#000")
features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
if(!features["horn_color"] || features["horn_color"] == "#000")
features["horn_color"] = "85615a"
if(!features["wing_color"] || features["wing_color"] == "#000")
features["wing_color"] = "FFFFFF"
nameless = sanitize_integer(nameless, 0, 1, initial(nameless))
be_random_name = sanitize_integer(be_random_name, 0, 1, initial(be_random_name))
be_random_body = sanitize_integer(be_random_body, 0, 1, initial(be_random_body))
@@ -599,8 +583,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
else
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones - GLOB.nonstandard_skin_tones, initial(skin_tone))
horn_color = sanitize_hexcolor(horn_color, 3, FALSE)
wing_color = sanitize_hexcolor(wing_color, 3, FALSE, "#FFFFFF")
features["horns_color"] = sanitize_hexcolor(features["horns_color"], 3, FALSE, "85615a")
features["wings_color"] = sanitize_hexcolor(features["wings_color"], 3, FALSE, "FFFFFF")
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
@@ -714,8 +698,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["shirt_color"] , shirt_color)
WRITE_FILE(S["socks"] , socks)
WRITE_FILE(S["socks_color"] , socks_color)
WRITE_FILE(S["horn_color"] , horn_color)
WRITE_FILE(S["wing_color"] , wing_color)
WRITE_FILE(S["horns_color"] , features["horns_color"])
WRITE_FILE(S["wings_color"] , features["wings_color"])
WRITE_FILE(S["backbag"] , backbag)
WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)

View File

@@ -143,6 +143,13 @@
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
/obj/item/clothing/shoes/winterboots/ice_boots
name = "ice hiking boots"
desc = "A pair of winter boots with special grips on the bottom, designed to prevent slipping on frozen surfaces."
icon_state = "iceboots"
item_state = "iceboots"
clothing_flags = NOSLIP_ICE
/obj/item/clothing/shoes/winterboots/christmasbootsr
name = "red christmas boots"
desc = "A pair of fluffy red christmas boots!"

View File

@@ -811,7 +811,7 @@
desc = "A dusty button up winter coat. The zipper tab looks like a tiny pickaxe."
icon_state = "coatminer"
item_state = "coatminer"
allowed = list(/obj/item/pickaxe, /obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter)
allowed = list(/obj/item/pickaxe, /obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter)
armor = list("melee" = 10, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
hoodtype = /obj/item/clothing/head/hooded/winterhood/miner

View File

@@ -19,6 +19,8 @@
var/list/spawn_locs = list()
for(var/obj/effect/landmark/carpspawn/L in GLOB.landmarks_list)
spawn_locs += L.loc
for(var/obj/effect/landmark/loneopspawn/L in GLOB.landmarks_list)
spawn_locs += L.loc
if(!spawn_locs.len)
return MAP_ERROR

View File

@@ -58,6 +58,9 @@
var/list/candidates = pollGhostCandidates("Do you wish to be considered for pirate crew?", ROLE_TRAITOR)
shuffle_inplace(candidates)
if(!SSmapping.empty_space)
SSmapping.empty_space = SSmapping.add_new_zlevel("Empty Area For Pirates", list(ZTRAIT_LINKAGE = SELFLOOPING))
var/datum/map_template/shuttle/pirate/default/ship = new
var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width)
var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height)

View File

@@ -1,63 +0,0 @@
dmm_suite{
/*
dmm_suite version 1.0
Released January 30th, 2011.
NOTE: Map saving functionality removed
defines the object /dmm_suite
- Provides the proc load_map()
- Loads the specified map file onto the specified z-level.
- provides the proc write_map()
- Returns a text string of the map in dmm format
ready for output to a file.
- provides the proc save_map()
- Returns a .dmm file if map is saved
- Returns FALSE if map fails to save
The dmm_suite provides saving and loading of map files in BYOND's native DMM map
format. It approximates the map saving and loading processes of the Dream Maker
and Dream Seeker programs so as to allow editing, saving, and loading of maps at
runtime.
------------------------
To save a map at runtime, create an instance of /dmm_suite, and then call
write_map(), which accepts three arguments:
- A turf representing one corner of a three dimensional grid (Required).
- Another turf representing the other corner of the same grid (Required).
- Any, or a combination, of several bit flags (Optional, see documentation).
The order in which the turfs are supplied does not matter, the /dmm_writer will
determine the grid containing both, in much the same way as DM's block() function.
write_map() will then return a string representing the saved map in dmm format;
this string can then be saved to a file, or used for any other purose.
------------------------
To load a map at runtime, create an instance of /dmm_suite, and then call load_map(),
which accepts two arguments:
- A .dmm file to load (Required).
- A number representing the z-level on which to start loading the map (Optional).
The /dmm_suite will load the map file starting on the specified z-level. If no
z-level was specified, world.maxz will be increased so as to fit the map. Note
that if you wish to load a map onto a z-level that already has objects on it,
you will have to handle the removal of those objects. Otherwise the new map will
simply load the new objects on top of the old ones.
Also note that all type paths specified in the .dmm file must exist in the world's
code, and that the /dmm_reader trusts that files to be loaded are in fact valid
.dmm files. Errors in the .dmm format will cause runtime errors.
*/
verb/load_map(var/dmm_file as file, var/x_offset as num, var/y_offset as num, var/z_offset as num, var/cropMap as num, var/measureOnly as num, no_changeturf as num){
// dmm_file: A .dmm file to load (Required).
// z_offset: A number representing the z-level on which to start loading the map (Optional).
// cropMap: When true, the map will be cropped to fit the existing world dimensions (Optional).
// measureOnly: When true, no changes will be made to the world (Optional).
// no_changeturf: When true, turf/AfterChange won't be called on loaded turfs
}
}

View File

@@ -22,6 +22,7 @@
var/traits = null
var/space_ruin_levels = 2
var/space_empty_levels = 1
var/station_ruin_budget = -1 // can be set to manually override the station ruins budget on maps that don't support station ruins, stopping the error from being unable to place the ruins.
var/minetype = "lavaland"
@@ -38,6 +39,10 @@
var/year_offset = 540 //The offset of ingame year from the actual IRL year. You know you want to make a map that takes place in the 90's. Don't lie.
// "fun things"
/// Orientation to load in by default.
var/orientation = SOUTH //byond defaults to placing everyting SOUTH.
/proc/load_map_config(filename = "data/next_map.json", default_to_box, delete_after, error_if_missing = TRUE)
var/datum/map_config/config = new
if (default_to_box)
@@ -130,6 +135,9 @@
log_world("map_config space_empty_levels is not a number!")
return
if("station_ruin_budget" in json)
station_ruin_budget = json["station_ruin_budget"]
temp = json["year_offset"]
if (isnum(temp))
year_offset = temp
@@ -139,13 +147,18 @@
if ("minetype" in json)
minetype = json["minetype"]
if ("maptype" in json)
maptype = json["maptype"]
if ("announcertype" in json)
announcertype = json["announcertype"]
if ("orientation" in json)
orientation = json["orientation"]
if(!(orientation in GLOB.cardinals))
orientation = SOUTH
allow_custom_shuttles = json["allow_custom_shuttles"] != FALSE
defaulted = FALSE
@@ -161,3 +174,23 @@
/datum/map_config/proc/MakeNextMap()
return config_filename == "data/next_map.json" || fcopy(config_filename, "data/next_map.json")
/// badmin moments. Keep up to date with LoadConfig()!
/datum/map_config/proc/WriteNextMap()
var/list/jsonlist = list()
jsonlist["map_name"] = map_name
jsonlist["map_path"] = map_path
jsonlist["map_file"] = map_file
jsonlist["shuttles"] = shuttles
jsonlist["traits"] = traits
jsonlist["space_ruin_levels"] = space_ruin_levels
jsonlist["year_offset"] = year_offset
jsonlist["minetype"] = minetype
jsonlist["maptype"] = maptype
jsonlist["announcertype"] = announcertype
jsonlist["orientation"] = orientation
jsonlist["allow_custom_shuttles"] = allow_custom_shuttles
if(fexists("data/next_map.json"))
fdel("data/next_map.json")
var/F = file("data/next_map.json")
WRITE_FILE(F, json_encode(jsonlist))

View File

@@ -0,0 +1,46 @@
GLOBAL_LIST_INIT(map_orientation_patterns, list(
TEXT_NORTH = new /datum/map_orientation_pattern/north,
TEXT_SOUTH = new /datum/map_orientation_pattern/south,
TEXT_EAST = new /datum/map_orientation_pattern/east,
TEXT_WEST = new /datum/map_orientation_pattern/west
))
/datum/map_orientation_pattern
var/invert_x
var/invert_y
var/swap_xy
var/xi
var/yi
var/turn_angle
/datum/map_orientation_pattern/north
invert_y = TRUE
invert_x = TRUE
swap_xy = FALSE
xi = -1
yi = 1
turn_angle = 180
/datum/map_orientation_pattern/south
invert_y = FALSE
invert_x = FALSE
swap_xy = FALSE
xi = 1
yi = -1
turn_angle = 0
/datum/map_orientation_pattern/east
invert_y = TRUE
invert_x = FALSE
swap_xy = TRUE
xi = 1
yi = 1
turn_angle = 90
/datum/map_orientation_pattern/west
invert_y = FALSE
invert_x = TRUE
swap_xy = TRUE
xi = -1
yi = -1
turn_angle = 270

View File

@@ -1,11 +1,14 @@
/datum/map_template
var/name = "Default Template Name"
var/width = 0
var/width = 0 //all these are for SOUTH!
var/height = 0
var/mappath = null
var/zdepth = 1
var/mappath
var/loaded = 0 // Times loaded this round
var/datum/parsed_map/cached_map
var/keep_cached_map = FALSE
var/default_annihilate = FALSE
var/list/ztraits //zlevel traits for load_new_z
/datum/map_template/New(path = null, rename = null, cache = FALSE)
if(path)
@@ -15,16 +18,45 @@
if(rename)
name = rename
/datum/map_template/proc/preload_size(path, cache = FALSE)
/datum/map_template/Destroy()
QDEL_NULL(cached_map)
return ..()
/datum/map_template/proc/preload_size(path = mappath, force_cache = FALSE)
if(cached_map)
return cached_map.parsed_bounds
var/datum/parsed_map/parsed = new(file(path))
var/bounds = parsed?.bounds
var/bounds = parsed?.parsed_bounds
if(bounds)
width = bounds[MAP_MAXX] // Assumes all templates are rectangular, have a single Z level, and begin at 1,1,1
height = bounds[MAP_MAXY]
if(cache)
width = bounds[MAP_MAXX] - bounds[MAP_MINX] + 1
height = bounds[MAP_MAXY] - bounds[MAP_MINY] + 1
zdepth = bounds[MAP_MAXZ] - bounds[MAP_MINZ] + 1
if(force_cache || keep_cached_map)
cached_map = parsed
return bounds
/datum/map_template/proc/get_parsed_bounds()
return preload_size(mappath)
/datum/map_template/proc/get_last_loaded_bounds()
if(cached_map)
return cached_map.bounds
return get_parsed_bounds()
/datum/map_template/proc/get_last_loaded_turf_block()
if(!cached_map)
CRASH("Improper use of get_last_loaded_turf_block, no cached_map.")
var/list/B = cached_map.bounds
return block(locate(B[MAP_MINX], B[MAP_MINY], B[MAP_MINZ]), locate(B[MAP_MAXX], B[MAP_MAXY], B[MAP_MAXZ]))
/datum/map_template/proc/get_size(orientation = SOUTH)
if(!width || !height || !zdepth)
preload_size(mappath)
var/rotate = (orientation & (NORTH|SOUTH)) != NONE
if(rotate)
return list(height, width, zdepth)
return list(width, height, zdepth)
/datum/parsed_map/proc/initTemplateBounds()
var/list/obj/machinery/atmospherics/atmos_machines = list()
var/list/obj/structure/cable/cables = list()
@@ -55,12 +87,12 @@
SSmachines.setup_template_powernets(cables)
SSair.setup_template_machinery(atmos_machines)
/datum/map_template/proc/load_new_z(list/traits = list(ZTRAIT_AWAY = TRUE))
var/x = round((world.maxx - width)/2)
var/y = round((world.maxy - height)/2)
/datum/map_template/proc/load_new_z(orientation = SOUTH, list/ztraits = src.ztraits || list(ZTRAIT_AWAY = TRUE), centered = TRUE)
var/x = centered? max(round((world.maxx - width) / 2), 1) : 1
var/y = centered? max(round((world.maxy - height) / 2), 1) : 1
var/datum/space_level/level = SSmapping.add_new_zlevel(name, traits)
var/datum/parsed_map/parsed = load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=TRUE)
var/datum/space_level/level = SSmapping.add_new_zlevel(name, ztraits)
var/datum/parsed_map/parsed = load_map(file(mappath), x, y, level.z_value, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop = TRUE, orientation = orientation)
var/list/bounds = parsed.bounds
if(!bounds)
return FALSE
@@ -71,31 +103,67 @@
parsed.initTemplateBounds()
smooth_zlevel(world.maxz)
log_game("Z-level [name] loaded at [x],[y],[world.maxz]")
on_map_loaded(world.maxz, parsed.bounds)
return level
/datum/map_template/proc/load(turf/T, centered = FALSE)
//Override for custom behavior
/datum/map_template/proc/on_map_loaded(z, list/bounds)
loaded++
/**
* Proc to trigger a load at a specific area. Calls on_map_loaded(T.z, loaded_bounds) afterwards.
*
* @params
* * turf/T - Turf to load at
* * centered - Center at T or load with the bottomright corner being at T
* * orientation - SOUTH is default, anything else rotates the map to face it with the point of reference being the map itself is facing south by default. Cardinals only, don't be a 4head and put in multiple flags. It won't work or be pretty if you try.
* * annihilate - Should we destroy stuff in our bounds while loading
* * force_cache - Should we force the parsed shuttle to cache instead of being GC'd post loading if it wasn't going to be cached by default
* * rotate_placement_to_orientation - Has no effect if centered. Should we rotate where we load it around the turf we're loading at? Used for stuff like engine submaps when the station is rotated.
*
*/
/datum/map_template/proc/load(turf/T, centered = FALSE, orientation = SOUTH, annihilate = default_annihilate, force_cache = FALSE, rotate_placement_to_orientation = FALSE)
var/old_T = T
if(centered)
T = locate(T.x - round(width/2) , T.y - round(height/2) , T.z)
T = locate(T.x - round(((orientation & (NORTH|SOUTH))? width : height) / 2) , T.y - round(((orientation & (NORTH|SOUTH)) ? height : width) / 2) , T.z) // %180 catches East/West (90,270) rotations on true, North/South (0,180) rotations on false
else if(rotate_placement_to_orientation && (orientation != SOUTH))
var/newx = T.x
var/newy = T.y
if(orientation == NORTH)
newx -= width
newy -= height - 1
else if(orientation == WEST)
newy -= width
else if(orientation == EAST)
newx -= height - 1
// eh let's not silently fail.
if(!ISINRANGE(newx, 1, world.maxx) || !ISINRANGE(newy, 1, world.maxy))
stack_trace("Warning: Rotation placed a map template load spot ([COORD(T)]) out of bounds of the game world. Clamping to world borders, this might cause issues.")
T = locate(clamp(newx, 1, world.maxx), clamp(newy, 1, world.maxy), T.z)
if(!T)
return
if(T.x+width > world.maxx)
if(T.x+width-1 > world.maxx)
return
if(T.y+height > world.maxy)
if(T.y+height-1 > world.maxy)
return
var/list/border = block(locate(max(T.x-1, 1), max(T.y-1, 1), T.z),
locate(min(T.x+width+1, world.maxx), min(T.y+height+1, world.maxy), T.z))
for(var/L in border)
var/turf/turf_to_disable = L
var/list/border = block(locate(max(T.x - 1, 1), max(T.y - 1, 1), T.z),
locate(min(T.x + width + 1, world.maxx), min(T.y + height + 1, world.maxy), T.z))
for(var/i in border)
var/turf/turf_to_disable = i
SSair.remove_from_active(turf_to_disable) //stop processing turfs along the border to prevent runtimes, we return it in initTemplateBounds()
turf_to_disable.atmos_adjacent_turfs?.Cut()
if(annihilate == MAP_TEMPLATE_ANNIHILATE_PRELOAD)
annihilate_bounds(old_T, centered, orientation)
// Accept cached maps, but don't save them automatically - we don't want
// ruins clogging up memory for the whole round.
var/datum/parsed_map/parsed = cached_map || new(file(mappath))
cached_map = keep_cached_map ? parsed : null
if(!parsed.load(T.x, T.y, T.z, cropMap=TRUE, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=TRUE))
var/is_cached = cached_map
var/datum/parsed_map/parsed = is_cached || new(file(mappath))
cached_map = (force_cache || keep_cached_map) ? parsed : is_cached
if(!parsed.load(T.x, T.y, T.z, cropMap=TRUE, no_changeturf=(SSatoms.initialized == INITIALIZATION_INSSATOMS), placeOnTop=TRUE, orientation = orientation, annihilate_tiles = (annihilate == MAP_TEMPLATE_ANNIHILATE_LOADING)))
return
var/list/bounds = parsed.bounds
if(!bounds)
@@ -108,19 +176,36 @@
parsed.initTemplateBounds()
log_game("[name] loaded at [T.x],[T.y],[T.z]")
on_map_loaded(T.z, parsed.bounds)
return bounds
/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE)
var/turf/placement = T
if(centered)
var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z)
if(corner)
placement = corner
return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z))
//This, get_affected_turfs, and load() calculations for bounds/center can probably be optimized. Later.
/datum/map_template/proc/annihilate_bounds(turf/origin, centered = FALSE, orientation = SOUTH)
var/deleted_atoms = 0
log_world("Annihilating objects in map loading location.")
var/list/turfs_to_clean = get_affected_turfs(origin, centered, orientation)
if(turfs_to_clean.len)
var/list/kill_these = list()
for(var/i in turfs_to_clean)
var/turf/T = i
kill_these += T.contents
for(var/i in kill_these)
qdel(i)
CHECK_TICK
deleted_atoms++
log_world("Annihilated [deleted_atoms] objects.")
//for your ever biggening badminnery kevinz000
//❤ - Cyberboss
/proc/load_new_z_level(file, name, list/traits)
/proc/load_new_z_level(file, name, orientation, list/ztraits)
var/datum/map_template/template = new(file, name)
return template.load_new_z(traits)
return template.load_new_z(orientation, ztraits)
/datum/map_template/proc/get_affected_turfs(turf/T, centered = FALSE, orientation = SOUTH)
var/turf/placement = T
if(centered)
var/turf/corner = locate(placement.x - round(((orientation & (NORTH|SOUTH))? width : height) / 2), placement.y - round(((orientation & (NORTH|SOUTH))? height : width) / 2), placement.z) // %180 catches East/West (90,270) rotations on true, North/South (0,180) rotations on false
if(corner)
placement = corner
return block(placement, locate(placement.x + ((orientation & (NORTH|SOUTH)) ? width : height) - 1, placement.y + ((orientation & (NORTH|SOUTH))? height : width) - 1, placement.z))

View File

@@ -7,13 +7,21 @@ GLOBAL_DATUM_INIT(_preloader, /datum/map_preloader, new)
parent_type = /datum
var/list/attributes
var/target_path
var/turn_angle
var/swap_x
var/swap_y
var/swap_xy
/world/proc/preloader_setup(list/the_attributes, path)
if(the_attributes.len)
/world/proc/preloader_setup(list/the_attributes, path, turn_angle, swap_x, swap_y, swap_xy)
if(length(the_attributes) || turn_angle)
GLOB.use_preloader = TRUE
var/datum/map_preloader/preloader_local = GLOB._preloader
preloader_local.attributes = the_attributes
preloader_local.target_path = path
preloader_local.turn_angle = turn_angle
preloader_local.swap_x = swap_x
preloader_local.swap_y = swap_y
preloader_local.swap_xy = swap_xy
/world/proc/preloader_load(atom/what)
GLOB.use_preloader = FALSE
@@ -29,6 +37,21 @@ GLOBAL_DATUM_INIT(_preloader, /datum/map_preloader, new)
GLOB.dirty_vars += message
#endif
what.vars[attribute] = value
// handle post processing, so things like directions on subtypes don't break.
if(preloader_local.turn_angle) //safe way to check for if this is necessary
what.dir = turn(what.dir, preloader_local.turn_angle)
var/px = what.pixel_x
var/py = what.pixel_y
if(preloader_local.swap_y) //same order of operations as the load rotation, mirror and then x/y swapping.
py = -py
if(preloader_local.swap_x)
px = -px
if(preloader_local.swap_xy)
var/opx = px
px = py
py = opx
what.pixel_x = px
what.pixel_y = py
/area/template_noop
name = "Area Passthrough"

View File

@@ -19,9 +19,13 @@
/// Unoffset bounds. Null on parse failure.
var/list/parsed_bounds
var/width
var/height
/// Offset bounds. Same as parsed_bounds until load().
var/list/bounds
var/datum/map_template/template_host
// raw strings used to represent regexes more accurately
// '' used to avoid confusing syntax highlighting
var/static/regex/dmmRegex = new(@'"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}', "g")
@@ -41,14 +45,33 @@
/// - `no_changeturf`: When true, [turf/AfterChange] won't be called on loaded turfs
/// - `x_lower`, `x_upper`, `y_lower`, `y_upper`: Coordinates (relative to the map) to crop to (Optional).
/// - `placeOnTop`: Whether to use [turf/PlaceOnTop] rather than [turf/ChangeTurf] (Optional).
/proc/load_map(dmm_file as file, x_offset as num, y_offset as num, z_offset as num, cropMap as num, measureOnly as num, no_changeturf as num, x_lower = -INFINITY as num, x_upper = INFINITY as num, y_lower = -INFINITY as num, y_upper = INFINITY as num, placeOnTop = FALSE as num)
var/datum/parsed_map/parsed = new(dmm_file, x_lower, x_upper, y_lower, y_upper, measureOnly)
/proc/load_map(
dmm_file as file,
x_offset as num,
y_offset as num,
z_offset as num,
cropMap as num,
measureOnly as num,
no_changeturf as num,
x_lower = -INFINITY as num,
x_upper = INFINITY as num,
y_lower = -INFINITY as num,
y_upper = INFINITY as num,
placeOnTop = FALSE as num,
orientation = SOUTH as num,
annihilate_tiles = FALSE,
z_lower = -INFINITY as num,
z_upper = INFINITY as num
)
var/datum/parsed_map/parsed = new(dmm_file, x_lower, x_upper, y_lower, y_upper, z_lower, z_upper, measureOnly)
if(parsed.bounds && !measureOnly)
parsed.load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop)
parsed.load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, orientation, annihilate_tiles)
return parsed
/// Parse a map, possibly cropping it.
/datum/parsed_map/New(tfile, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper=INFINITY, measureOnly=FALSE)
//WHY THE HECK DO WE EVEN SUPPORT NEGATIVE COORDINATES, ALL IT IS IS A WASTE OF TIME AND CPU!!!???
//DO NOT USE THIS TO TRIM MAPS UNLESS STRICTLY NEEDED! IT IS EXTREMELY EXPENSIVE TO DO SO!
/datum/parsed_map/New(tfile, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, z_lower = -INFINITY, z_upper = INFINITY, measureOnly = FALSE)
if(isfile(tfile))
original_path = "[tfile]"
tfile = file2text(tfile)
@@ -57,6 +80,9 @@
return
bounds = parsed_bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
ASSERT(x_upper >= x_lower)
ASSERT(y_upper >= y_lower)
ASSERT(z_upper >= z_lower)
var/stored_index = 1
//multiz lool
@@ -82,20 +108,23 @@
CRASH("Coords before model definition in DMM")
var/curr_x = text2num(dmmRegex.group[3])
var/curr_y = text2num(dmmRegex.group[4])
var/curr_z = text2num(dmmRegex.group[5])
if(curr_x < x_lower || curr_x > x_upper)
if(curr_x < x_lower || curr_y < y_lower || curr_z < z_lower || curr_z > z_upper)
continue
var/datum/grid_set/gridSet = new
gridSet.xcrd = curr_x
//position of the currently processed square
gridSet.ycrd = text2num(dmmRegex.group[4])
gridSet.zcrd = text2num(dmmRegex.group[5])
gridSet.ycrd = curr_y
gridSet.zcrd = curr_z
bounds[MAP_MINX] = min(bounds[MAP_MINX], clamp(gridSet.xcrd, x_lower, x_upper))
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], gridSet.zcrd)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], gridSet.zcrd)
bounds[MAP_MINX] = min(bounds[MAP_MINX], curr_x) //since down is up for y/gridlines, we now know the lower left corner.
bounds[MAP_MINY] = min(bounds[MAP_MINY], curr_y)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], curr_z)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], curr_z) //we know max z now
var/list/gridLines = splittext(dmmRegex.group[6], "\n")
gridSet.gridLines = gridLines
@@ -105,102 +134,132 @@
if(leadingBlanks > 1)
gridLines.Cut(1, leadingBlanks) // Remove all leading blank lines.
if(!gridLines.len) // Skip it if only blank lines exist.
continue
gridSets += gridSet
if(gridLines.len && gridLines[gridLines.len] == "")
gridLines.Cut(gridLines.len) // Remove only one blank line at the end.
var/lines = length(gridLines)
if(lines)
if(gridLines[gridLines.len] == "")
gridLines.Cut(gridLines.len) // Remove only one blank line at the end.
var/right_length = y_upper - curr_y + 1
if(lines > right_length)
gridLines.len = right_length //this can't be negative due to our ASSERTions above, hopefully.
bounds[MAP_MINY] = min(bounds[MAP_MINY], clamp(gridSet.ycrd, y_lower, y_upper))
if(!gridLines.len) // Skip it if there's no content.
continue
//do not use curr_y after this point, ycrd has changed. use it before because local var.
gridSet.ycrd += gridLines.len - 1 // Start at the top and work down
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], clamp(gridSet.ycrd, y_lower, y_upper))
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], gridSet.ycrd) //we know max y now
var/maxx = gridSet.xcrd
if(gridLines.len) //Not an empty map
maxx = max(maxx, gridSet.xcrd + length(gridLines[1]) / key_len - 1)
var/linelength = length(gridLines[1]) //yes it only samples the first line, this is why you use TGM instead of DMM!
var/xlength = linelength / key_len
bounds[MAP_MAXX] = clamp(max(bounds[MAP_MAXX], maxx), x_lower, x_upper)
var/maxx = gridSet.xcrd + xlength - 1
if(maxx > x_upper)
for(var/i in 1 to length(gridLines))
gridLines[i] = copytext(gridLines[i], 1, key_len * (x_upper - curr_x + 1))
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], maxx)
CHECK_TICK
// Indicate failure to parse any coordinates by nulling bounds
if(bounds[1] == 1.#INF)
bounds = null
else
width = bounds[MAP_MAXX] - bounds[MAP_MINX] + 1
height = bounds[MAP_MAXY] - bounds[MAP_MINY] + 1
parsed_bounds = bounds
/datum/parsed_map/Destroy()
if(template_host && template_host.cached_map == src)
template_host.cached_map = null
return ..()
/// Load the parsed map into the world. See [/proc/load_map] for arguments.
/datum/parsed_map/proc/load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop)
/datum/parsed_map/proc/load(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, orientation, annihilate_tiles, datum/map_orientation_pattern/forced_pattern)
//How I wish for RAII
Master.StartLoadingMap()
. = _load_impl(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop)
. = _load_impl(x_offset, y_offset, z_offset, cropMap, no_changeturf, x_lower, x_upper, y_lower, y_upper, placeOnTop, orientation, annihilate_tiles, forced_pattern)
Master.StopLoadingMap()
// Do not call except via load() above.
/datum/parsed_map/proc/_load_impl(x_offset = 1, y_offset = 1, z_offset = world.maxz + 1, cropMap = FALSE, no_changeturf = FALSE, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, placeOnTop = FALSE)
// Lower/upper here refers to the actual map template's parsed coordinates, NOT ACTUAL COORDINATES! Figure it out yourself my head hurts too much to implement that too.
/datum/parsed_map/proc/_load_impl(x_offset = 1, y_offset = 1, z_offset = world.maxz + 1, cropMap = FALSE, no_changeturf = FALSE, x_lower = -INFINITY, x_upper = INFINITY, y_lower = -INFINITY, y_upper = INFINITY, placeOnTop = FALSE, orientation = SOUTH, annihilate_tiles = FALSE, datum/map_orientation_pattern/forced_pattern)
var/list/areaCache = list()
var/list/modelCache = build_cache(no_changeturf)
var/space_key = modelCache[SPACE_KEY]
var/list/bounds
src.bounds = bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
var/datum/map_orientation_pattern/mode = forced_pattern || GLOB.map_orientation_patterns["[orientation]"] || GLOB.map_orientation_patterns["[SOUTH]"]
var/invert_y = mode.invert_y
var/invert_x = mode.invert_x
var/swap_xy = mode.swap_xy
var/xi = mode.xi
var/yi = mode.yi
var/turn_angle = round(SIMPLIFY_DEGREES(mode.turn_angle), 90)
var/delta_swap = x_offset - y_offset
for(var/I in gridSets)
var/datum/grid_set/gset = I
var/ycrd = gset.ycrd + y_offset - 1
var/zcrd = gset.zcrd + z_offset - 1
if(!cropMap && ycrd > world.maxy)
world.maxy = ycrd // Expand Y here. X is expanded in the loop below
var/zexpansion = zcrd > world.maxz
for(var/__I in gridSets)
var/datum/grid_set/gridset = __I
var/parsed_z = gridset.zcrd + z_offset - 1
var/zexpansion = parsed_z > world.maxz
if(zexpansion)
if(cropMap)
continue
else
while (zcrd > world.maxz) //create a new z_level if needed
while(parsed_z > world.maxz)
world.incrementMaxZ()
if(!no_changeturf)
WARNING("Z-level expansion occurred without no_changeturf set, this may cause problems when /turf/AfterChange is called")
//these values are the same until a new gridset is reached.
var/edge_dist_x = gridset.xcrd - 1 //from left side, 0 is right on the x_offset
var/edge_dist_y = gridset.ycrd - length(gridset.gridLines) //from bottom, 0 is right on the y_offset
var/actual_x_starting = invert_x? (x_offset + width - edge_dist_x - 1) : (x_offset + edge_dist_x) //this value is not changed, cache.
//this value is changed
var/actual_y = invert_y? (y_offset + edge_dist_y) : (y_offset + gridset.ycrd - 1)
for(var/line in gridset.gridLines)
var/actual_x = actual_x_starting
for(var/pos = 1 to (length(line) - key_len + 1) step key_len)
var/placement_x = swap_xy? (actual_y + delta_swap) : actual_x
var/placement_y = swap_xy? (actual_x - delta_swap) : actual_y
if(placement_x > world.maxx)
if(cropMap)
actual_x += xi
continue
else
world.maxx = placement_x
if(placement_y > world.maxy)
if(cropMap)
break
else
world.maxy = placement_y
if(placement_x < 1)
actual_x += xi
continue
if(placement_y < 1)
break
var/model_key = copytext(line, pos, pos + key_len)
var/no_afterchange = no_changeturf || zexpansion
if(!no_afterchange || (model_key != space_key))
var/list/cache = modelCache[model_key]
if(!cache)
CRASH("Undefined model key in DMM: [model_key]")
build_coordinate(areaCache, cache, locate(placement_x, placement_y, parsed_z), no_afterchange, placeOnTop, turn_angle, annihilate_tiles, swap_xy, invert_y, invert_x)
for(var/line in gset.gridLines)
if((ycrd - y_offset + 1) < y_lower || (ycrd - y_offset + 1) > y_upper) //Reverse operation and check if it is out of bounds of cropping.
--ycrd
continue
if(ycrd <= world.maxy && ycrd >= 1)
var/xcrd = gset.xcrd + x_offset - 1
for(var/tpos = 1 to length(line) - key_len + 1 step key_len)
if((xcrd - x_offset + 1) < x_lower || (xcrd - x_offset + 1) > x_upper) //Same as above.
++xcrd
continue //X cropping.
if(xcrd > world.maxx)
if(cropMap)
break
else
world.maxx = xcrd
if(xcrd >= 1)
var/model_key = copytext(line, tpos, tpos + key_len)
var/no_afterchange = no_changeturf || zexpansion
if(!no_afterchange || (model_key != space_key))
var/list/cache = modelCache[model_key]
if(!cache)
CRASH("Undefined model key in DMM: [model_key]")
build_coordinate(areaCache, cache, locate(xcrd, ycrd, zcrd), no_afterchange, placeOnTop)
// only bother with bounds that actually exist
bounds[MAP_MINX] = min(bounds[MAP_MINX], xcrd)
bounds[MAP_MINY] = min(bounds[MAP_MINY], ycrd)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], zcrd)
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], xcrd)
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], ycrd)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], zcrd)
#ifdef TESTING
else
++turfsSkipped
#endif
CHECK_TICK
++xcrd
--ycrd
CHECK_TICK
// only bother with bounds that actually exist
bounds[MAP_MINX] = min(bounds[MAP_MINX], placement_x)
bounds[MAP_MINY] = min(bounds[MAP_MINY], placement_y)
bounds[MAP_MINZ] = min(bounds[MAP_MINZ], parsed_z)
bounds[MAP_MAXX] = max(bounds[MAP_MAXX], placement_x)
bounds[MAP_MAXY] = max(bounds[MAP_MAXY], placement_y)
bounds[MAP_MAXZ] = max(bounds[MAP_MAXZ], parsed_z)
#ifdef TESTING
else
++turfsSkipped
#endif
actual_x += xi
CHECK_TICK
actual_y += yi
CHECK_TICK
if(!no_changeturf)
for(var/t in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
@@ -294,7 +353,7 @@
.[model_key] = list(members, members_attributes)
/datum/parsed_map/proc/build_coordinate(list/areaCache, list/model, turf/crds, no_changeturf as num, placeOnTop as num)
/datum/parsed_map/proc/build_coordinate(list/areaCache, list/model, turf/crds, no_changeturf as num, placeOnTop as num, turn_angle as num, annihilate_tiles = FALSE, swap_xy, invert_y, invert_x)
var/index
var/list/members = model[1]
var/list/members_attributes = model[2]
@@ -306,6 +365,8 @@
//The next part of the code assumes there's ALWAYS an /area AND a /turf on a given tile
//first instance the /area and remove it from the members list
index = members.len
if(annihilate_tiles && crds)
crds.empty(null)
if(members[index] != /area/template_noop)
var/atype = members[index]
world.preloader_setup(members_attributes[index], atype)//preloader for assigning set variables on atom creation
@@ -332,20 +393,20 @@
//instanciate the first /turf
var/turf/T
if(members[first_turf_index] != /turf/template_noop)
T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],crds,no_changeturf,placeOnTop)
T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],crds,no_changeturf,placeOnTop,turn_angle, swap_xy, invert_y, invert_x)
if(T)
//if others /turf are presents, simulates the underlays piling effect
index = first_turf_index + 1
while(index <= members.len - 1) // Last item is an /area
var/underlay = T.appearance
T = instance_atom(members[index],members_attributes[index],crds,no_changeturf,placeOnTop)//instance new turf
T = instance_atom(members[index],members_attributes[index],crds,no_changeturf,placeOnTop,turn_angle, swap_xy, invert_y, invert_x)//instance new turf
T.underlays += underlay
index++
//finally instance all remainings objects/mobs
for(index in 1 to first_turf_index-1)
instance_atom(members[index],members_attributes[index],crds,no_changeturf,placeOnTop)
instance_atom(members[index],members_attributes[index],crds,no_changeturf,placeOnTop,turn_angle, swap_xy, invert_y, invert_x)
//Restore initialization to the previous value
SSatoms.map_loader_stop()
@@ -354,8 +415,8 @@
////////////////
//Instance an atom at (x,y,z) and gives it the variables in attributes
/datum/parsed_map/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf, placeOnTop)
world.preloader_setup(attributes, path)
/datum/parsed_map/proc/instance_atom(path,list/attributes, turf/crds, no_changeturf, placeOnTop, turn_angle = 0, swap_xy, invert_y, invert_x)
world.preloader_setup(attributes, path, turn_angle, invert_x, invert_y, swap_xy)
if(crds)
if(ispath(path, /turf))

View File

@@ -11,9 +11,17 @@
for(var/turf/check in get_affected_turfs(central_turf,1))
var/area/new_area = get_area(check)
if(!(istype(new_area, allowed_areas)) || check.flags_1 & NO_RUINS_1)
valid = FALSE
valid = FALSE // set to false before we check
if(check.flags_1 & NO_RUINS_1)
break
for(var/type in allowed_areas)
if(istype(new_area, type)) // it's at least one of our types so it's whitelisted
valid = TRUE
break
if(!valid)
break
if(!valid)
continue
@@ -51,7 +59,7 @@
new /obj/effect/landmark/ruin(center, src)
return center
/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = /area/space, list/potentialRuins)
/proc/seedRuins(list/z_levels = null, budget = 0, whitelist = list(/area/space), list/potentialRuins)
if(!z_levels || !z_levels.len)
WARNING("No Z levels provided - Not generating ruins")
return

View File

@@ -659,6 +659,7 @@
nemesis_factions = list("mining", "boss")
var/transform_cooldown
var/swiping = FALSE
var/bleed_stacks_per_hit = 3
total_mass = 2.75
total_mass_on = 5
@@ -701,12 +702,11 @@
user.changeNext_move(CLICK_CD_MELEE * 0.5) //when closed, it attacks very rapidly
/obj/item/melee/transforming/cleaving_saw/nemesis_effects(mob/living/user, mob/living/target)
var/datum/status_effect/saw_bleed/B = target.has_status_effect(STATUS_EFFECT_SAWBLEED)
var/datum/status_effect/stacking/saw_bleed/B = target.has_status_effect(STATUS_EFFECT_SAWBLEED)
if(!B)
if(!active) //This isn't in the above if-check so that the else doesn't care about active
target.apply_status_effect(STATUS_EFFECT_SAWBLEED)
target.apply_status_effect(STATUS_EFFECT_SAWBLEED,bleed_stacks_per_hit)
else
B.add_bleed(B.bleed_buildup)
B.add_stacks(bleed_stacks_per_hit)
/obj/item/melee/transforming/cleaving_saw/attack(mob/living/target, mob/living/carbon/human/user)
if(!active || swiping || !target.density || get_turf(target) == get_turf(user))

View File

@@ -37,16 +37,19 @@
/obj/machinery/mineral/ore_redemption/RefreshParts()
var/ore_pickup_rate_temp = 15
var/point_upgrade_temp = 1
var/ore_multiplier_temp = 1
var/avg_bin_level = 0
var/bins = 0
for(var/obj/item/stock_parts/matter_bin/B in component_parts)
ore_multiplier_temp = 0.65 + (0.35 * B.rating)
avg_bin_level = B.rating
bins++
for(var/obj/item/stock_parts/manipulator/M in component_parts)
ore_pickup_rate_temp = 15 * M.rating
for(var/obj/item/stock_parts/micro_laser/L in component_parts)
point_upgrade_temp = 0.65 + (0.35 * L.rating)
avg_bin_level /= bins? bins : 1
ore_multiplier = STANDARD_PART_LEVEL_ORE_COEFFICIENT(avg_bin_level)
ore_pickup_rate = ore_pickup_rate_temp
point_upgrade = point_upgrade_temp
ore_multiplier = round(ore_multiplier_temp, 0.01)
/obj/machinery/mineral/ore_redemption/examine(mob/user)
. = ..()

View File

@@ -18,8 +18,6 @@
hair_color = random_short_color()
facial_hair_color = hair_color
eye_color = random_eye_color()
horn_color = "85615a"
wing_color = "fff"
if(!pref_species)
var/rando_race = pick(GLOB.roundstart_races)
pref_species = new rando_race()

View File

@@ -67,10 +67,8 @@
//Special / holdover traits for Citadel specific sprites.
var/extra = FALSE
var/extra_color_src = MUTCOLORS2 //The color source for the extra overlay.
var/extra_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
var/extra2 = FALSE
var/extra2_color_src = MUTCOLORS3
var/extra2_icon = 'modular_citadel/icons/mob/mam_tails.dmi'
//for snowflake/donor specific sprites
var/list/ckeys_allowed

View File

@@ -223,6 +223,8 @@
icon_state = "cat"
icon = 'icons/mob/mutant_bodyparts.dmi'
color_src = HAIR
extra = TRUE
extra_color_src = NONE
/datum/sprite_accessory/mam_ears/catbig
name = "Cat, Big"

View File

@@ -21,8 +21,6 @@
/datum/sprite_accessory/taur
icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
extra2_icon = 'modular_citadel/icons/mob/mam_taur.dmi'
center = TRUE
dimension_x = 64
color_src = MATRIXED

View File

@@ -1,6 +1,7 @@
/datum/sprite_accessory/snouts
icon = 'icons/mob/mutant_bodyparts.dmi'
mutant_part_string = "snout"
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/snouts/sharp
name = "Sharp"
@@ -154,6 +155,7 @@
icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
recommended_species = list("mammal", "slimeperson", "insect", "podweak")
mutant_part_string = "snout"
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/mam_snouts/none
name = "None"
@@ -386,4 +388,4 @@
/datum/sprite_accessory/mam_snouts/froundlight
name = "Round + Light (Top)"
icon_state = "froundlight"
color_src = MUTCOLORS
color_src = MUTCOLORS

View File

@@ -1,8 +1,10 @@
/datum/sprite_accessory/spines
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
/datum/sprite_accessory/spines_animated
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
/datum/sprite_accessory/spines/none
name = "None"
@@ -51,4 +53,4 @@
/datum/sprite_accessory/spines_animated/aqautic
name = "Aquatic"
icon_state = "aqua"
icon_state = "aqua"

View File

@@ -523,6 +523,7 @@
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
mutant_part_string = "tailwag"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/mam_tails_animated/none
name = "None"

View File

@@ -7,6 +7,7 @@
/datum/sprite_accessory/wings_open
icon = 'icons/mob/wings.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/wings_open/angel
name = "Angel"
@@ -49,6 +50,7 @@
dimension_x = 46
center = TRUE
dimension_y = 34
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
/datum/sprite_accessory/deco_wings/bat
name = "Bat"

View File

@@ -11,7 +11,7 @@
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
blocks_emissive = EMISSIVE_BLOCK_UNIQUE
//Hair colour and style
var/hair_color = "000"
var/hair_style = "Bald"
@@ -23,10 +23,6 @@
//Eye colour
var/eye_color = "000"
var/horn_color = "85615a" //specific horn colors, because why not?
var/wing_color = "fff" //wings too
var/skin_tone = "caucasian1" //Skin tone
var/lip_style = null //no lipstick by default- arguably misleading, as it could be used for general makeup

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