Skip to content

Commit

Permalink
Merge branch 'master' into launchbay-400-->-200
Browse files Browse the repository at this point in the history
  • Loading branch information
Zonespace27 committed Dec 26, 2023
2 parents 2bfe1f9 + 47a18d5 commit fbe956e
Show file tree
Hide file tree
Showing 355 changed files with 25,583 additions and 19,388 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"**/.pnp.*": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"files.eol": "\n",
"files.insertFinalNewline": true,
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/__game.dm
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ block( \
#define CHAT_FFATTACKLOGS (1<<11)
#define CHAT_GHOSTHIVEMIND (1<<12)
#define CHAT_NICHELOGS (1<<13)
#define CHAT_LISTENINGBUG (1<<14)

//toggles_ghost
#define GHOST_HEALTH_SCAN (1<<0)
Expand Down Expand Up @@ -391,6 +392,7 @@ block( \
#define FIRE_MISSION_WEAPON_REMOVED 8
#define FIRE_MISSION_WEAPON_UNUSABLE 16
#define FIRE_MISSION_WEAPON_OUT_OF_AMMO 32
#define FIRE_MISSION_BAD_DIRECTION 64
#define FIRE_MISSION_NOT_EXECUTABLE -1

//Defines for firemission state
Expand Down
7 changes: 7 additions & 0 deletions code/__DEFINES/alerts.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#define ALERT_BUCKLED "buckled"
#define ALERT_HANDCUFFED "handcuffed"
#define ALERT_LEGCUFFED "legcuffed"
#define ALERT_FLOORED "floored"
#define ALERT_INCAPACITATED "incapacitated"
#define ALERT_KNOCKEDOUT "knockedout"
#define ALERT_IMMOBILIZED "immobilized"
5 changes: 0 additions & 5 deletions code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@
#define COMSIG_LIVING_SPEAK "living_speak"
#define COMPONENT_OVERRIDE_SPEAK (1<<0)

#define COMSIG_LIVING_APPLY_EFFECT "living_apply_effect"
#define COMSIG_LIVING_ADJUST_EFFECT "living_adjust_effect"
#define COMSIG_LIVING_SET_EFFECT "living_set_effect"
#define COMPONENT_CANCEL_EFFECT (1<<0)

/// From /obj/structure/proc/do_climb(var/mob/living/user, mods)
#define COMSIG_LIVING_CLIMB_STRUCTURE "climb_over_structure"
/// From /mob/living/Collide(): (atom/A)
Expand Down
3 changes: 3 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@
#define COMSIG_MOB_MOVE_OR_LOOK "mob_move_or_look"
#define COMPONENT_OVERRIDE_MOB_MOVE_OR_LOOK (1<<0)

///from rejuv
#define COMSIG_LIVING_POST_FULLY_HEAL "living_post_fully_heal"

///from /mob/living/emote(): ()
#define COMSIG_MOB_EMOTE "mob_emote"

Expand Down
9 changes: 9 additions & 0 deletions code/__DEFINES/dcs/signals/atom/signals_item.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,12 @@

//from /datum/authority/branch/role/proc/equip_role()
#define COMSIG_POST_SPAWN_UPDATE "post_spawn_update"

#define COMSIG_CAMERA_MAPNAME_ASSIGNED "camera_manager_mapname_assigned"
#define COMSIG_CAMERA_REGISTER_UI "camera_manager_register_ui"
#define COMSIG_CAMERA_UNREGISTER_UI "camera_manager_unregister_ui"
#define COMSIG_CAMERA_SET_NVG "camera_manager_set_nvg"
#define COMSIG_CAMERA_CLEAR_NVG "camera_manager_clear_nvg"
#define COMSIG_CAMERA_SET_TARGET "camera_manager_set_target"
#define COMSIG_CAMERA_SET_AREA "camera_manager_set_area"
#define COMSIG_CAMERA_CLEAR "camera_manager_clear_target"
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/atom/signals_obj.dm
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@
/// from /obj/proc/afterbuckle()
#define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle"

#define COMSIG_DROPSHIP_ADD_EQUIPMENT "dropship_add_equipment"
#define COMSIG_DROPSHIP_REMOVE_EQUIPMENT "dropship_remove_equipment"
#define COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED "structure_crate_squad_launched"
1 change: 1 addition & 0 deletions code/__DEFINES/dcs/signals/signals_global.dm
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,4 @@
#define COMSIG_GLOB_GENERATOR_SET_OVERLOADING "!generator_set_overloading"

#define COMSIG_GLOB_HIJACK_IMPACTED "!hijack_impacted"
#define COMSIG_GLOB_HIJACK_LANDED "!hijack_landed"
1 change: 1 addition & 0 deletions code/__DEFINES/layers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
///--------------- FULLSCREEN RUNECHAT BUBBLES ------------
#define LIGHTING_PLANE 100
#define EXTERIOR_LIGHTING_PLANE 101
#define NVG_PLANE 110

///Popup Chat Messages
#define RUNECHAT_PLANE 501
Expand Down
1 change: 1 addition & 0 deletions code/__DEFINES/maps.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require only minor tweaks.
#define ZTRAIT_FOG "Fog"
#define ZTRAIT_LOCKDOWN "Lockdown"
#define ZTRAIT_BASIC_RT "BasicRT"
#define ZTRAIT_IN_SPACE "InSpace" // Is our ground_level considered in space or on a space station

// boolean - weather types that occur on the level
#define ZTRAIT_SNOWSTORM "weather_snowstorm"
Expand Down
3 changes: 3 additions & 0 deletions code/__DEFINES/mobs.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/// Multiplier for Stun/KD/KO/etc durations in new backend, due to old system being based on life ticks
#define GLOBAL_STATUS_MULTIPLIER 20 // each in-code unit is worth 20ds of duration

#define HEALTH_THRESHOLD_DEAD -100
#define HEALTH_THRESHOLD_CRIT -50

Expand Down
10 changes: 9 additions & 1 deletion code/__DEFINES/mode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,16 @@ GLOBAL_LIST_INIT(whitelist_hierarchy, list(WHITELIST_NORMAL, WHITELIST_COUNCIL,

#define FACTION_LIST_MARINE list(FACTION_MARINE)
#define FACTION_LIST_HUMANOID list(FACTION_MARINE, FACTION_PMC, FACTION_WY, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_MARSHAL, FACTION_UPP, FACTION_FREELANCER, FACTION_SURVIVOR, FACTION_NEUTRAL, FACTION_COLONIST, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_YAUTJA, FACTION_ZOMBIE, FACTION_TWE)
#define FACTION_LIST_ERT list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_MARSHAL, FACTION_TWE)
#define FACTION_LIST_ERT list(FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO)
#define FACTION_LIST_WY list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY)
#define FACTION_LIST_UPP list(FACTION_UPP)
#define FACTION_LIST_CLF list(FACTION_CLF)
#define FACTION_LIST_TWE list(FACTION_TWE)
#define FACTION_LIST_FREELANCER list(FACTION_FREELANCER)
#define FACTION_LIST_CONTRACTOR list(FACTION_CONTRACTOR)
#define FACTION_LIST_MERCENARY list(FACTION_MERCENARY)
#define FACTION_LIST_MARSHAL list(FACTION_MARSHAL)
#define FACTION_LIST_DUTCH list(FACTION_DUTCH)
#define FACTION_LIST_MARINE_WY list(FACTION_MARINE, FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY)
#define FACTION_LIST_MARINE_UPP list(FACTION_MARINE, FACTION_UPP)
#define FACTION_LIST_MARINE_TWE list(FACTION_MARINE, FACTION_TWE)
Expand Down
25 changes: 25 additions & 0 deletions code/__DEFINES/status_effects.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
///if it allows multiple instances of the effect
#define STATUS_EFFECT_MULTIPLE 0
///if it allows only one, preventing new instances
#define STATUS_EFFECT_UNIQUE 1
///if it allows only one, but new instances replace
#define STATUS_EFFECT_REPLACE 2
/// if it only allows one, and new instances just instead refresh the timer
#define STATUS_EFFECT_REFRESH 3

///Processing flags - used to define the speed at which the status will work
///This is fast - 0.2s between ticks (I believe!)
#define STATUS_EFFECT_FAST_PROCESS 0
///This is slower and better for more intensive status effects - 1s between ticks
#define STATUS_EFFECT_NORMAL_PROCESS 1

//Incapacitated status effect flags
/// If the incapacitated status effect will ignore a mob in restraints (handcuffs)
#define IGNORE_RESTRAINTS (1<<0)
/// If the incapacitated status effect will ignore a mob in stasis (stasis beds)
#define IGNORE_STASIS (1<<1)
/// If the incapacitated status effect will ignore a mob being agressively grabbed
#define IGNORE_GRAB (1<<2)

/// Time threshold after which we launch ending timer - this should be higher than the slowest processing rate
#define STATUS_EFFECT_TIME_THRESHOLD (2 SECONDS)
4 changes: 3 additions & 1 deletion code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,11 @@
#define SS_PRIORITY_FAST_OBJECTS 105
#define SS_PRIORITY_OBJECTS 104
#define SS_PRIORITY_DECORATOR 99
#define SS_PRIORITY_EFFECTS 97
#define SS_PRIORITY_FASTEFFECTS 96
#define SS_PRIORITY_HIJACK 97
#define SS_PRIORITY_POWER 95
#define SS_PRIORITY_EFFECTS 92
#define SS_PRIORITY_OLDEFFECTS 92
#define SS_PRIORITY_MACHINERY 90
#define SS_PRIORITY_FZ_TRANSITIONS 88
#define SS_PRIORITY_ROUND_RECORDING 83
Expand Down
9 changes: 9 additions & 0 deletions code/__DEFINES/surgery.dm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ unless the surgical tool is completely unsuited to what it's being used for.*/
///A tool that's perfect for the surgery.
#define SURGERY_TOOL_MULT_IDEAL 1

///The (no) chance of failure for surgery because the correct tools/conditions are used or skill compensates
#define SURGERY_FAILURE_IMPOSSIBLE 0
///The chance of failure for surgery because the the tool/ground is SURGERY_TOOL_MULT_BAD_SUBSTITUTE/SURGERY_SURFACE_MULT_UNSUITED and skill can't compensate enough
#define SURGERY_FAILURE_UNLIKELY 5
///The chance of failure for surgery because the the tool/ground is SURGERY_TOOL_MULT_AWFUL/SURGERY_SURFACE_MULT_AWFUL and skill can't compensate enough
#define SURGERY_FAILURE_POSSIBLE 25
///The chance of failure for surgery because the the tool and ground is some combination worse than awful and skill can't compensate enough
#define SURGERY_FAILURE_LIKELY 50

//When initiating surgeries, these define their order when listed in initiation selector or 'you can't use this tool for anything, but could x, y, or z' messages.
///Appears first in lists. Ex. larva surgery, opening incision. Immediately life-threatening or initiation surgeries.
#define SURGERY_PRIORITY_MAXIMUM 5
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ GLOBAL_LIST(trait_name_map)
#define TRAIT_SOURCE_XENO_ACTION_CHARGE "t_s_xeno_action_charge"
///Status trait coming from a xeno nest
#define XENO_NEST_TRAIT "xeno_nest"
///Status trait from a generic throw by xeno abilities
#define XENO_THROW_TRAIT "xeno_throw_trait"
//-- structure traits --
///Status trait coming from being flipped or unflipped.
#define TRAIT_SOURCE_FLIP_TABLE "t_s_flip_table"
Expand Down
2 changes: 0 additions & 2 deletions code/__DEFINES/xeno.dm
Original file line number Diff line number Diff line change
Expand Up @@ -580,9 +580,7 @@
#define XENO_STRUCTURE_CORE "hive core"
#define XENO_STRUCTURE_CLUSTER "hive cluster"
#define XENO_STRUCTURE_PYLON "hive pylon"
#define XENO_STRUCTURE_POOL "spawn pool"
#define XENO_STRUCTURE_EGGMORPH "egg morpher"
#define XENO_STRUCTURE_EVOPOD "evolution pod"
#define XENO_STRUCTURE_RECOVERY "recovery node"
#define XENO_STRUCTURE_NEST "thick resin nest"

Expand Down
44 changes: 1 addition & 43 deletions code/__HELPERS/#maths.dm
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,

// MATH DEFINES

#define Atan2(x, y) (!x && !y ? 0 : \
(y >= 0 ? \
arccos(x / sqrt(x*x + y*y)) : \
-(arccos(x / sqrt(x*x + y*y))) \
) \
)
#define Ceiling(x) (-round(-x))
#define Clamp(val, min_val, max_val) (max(min_val, min(val, max_val)))
#define CLAMP01(x) (clamp(x, 0, 1))
Expand Down Expand Up @@ -78,7 +72,7 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,

// Convert to polar coordinates
var/radius = sqrt(relative_coords[1]**2 + relative_coords[2]**2)
var/phi = Atan2(relative_coords[1], relative_coords[2])
var/phi = arctan(relative_coords[1], relative_coords[2])

// Rotate the point around the axis
phi += degrees
Expand Down Expand Up @@ -106,42 +100,6 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4,
return "[round((powerused * 0.000001),0.001)] MW"
return "[round((powerused * 0.000000001),0.0001)] GW"

///Calculate the angle between two movables and the west|east coordinate
/proc/get_angle(atom/movable/start, atom/movable/end)//For beams.
if(!start || !end)
return 0
var/dy =(32 * end.y + end.pixel_y) - (32 * start.y + start.pixel_y)
var/dx =(32 * end.x + end.pixel_x) - (32 * start.x + start.pixel_x)
if(!dy)
return (dx >= 0) ? 90 : 270
. = arctan(dx/dy)
if(dy < 0)
. += 180
else if(dx < 0)
. += 360

/// Angle between two arbitrary points and horizontal line same as [/proc/get_angle]
/proc/get_angle_raw(start_x, start_y, start_pixel_x, start_pixel_y, end_x, end_y, end_pixel_x, end_pixel_y)
var/dy = (32 * end_y + end_pixel_y) - (32 * start_y + start_pixel_y)
var/dx = (32 * end_x + end_pixel_x) - (32 * start_x + start_pixel_x)
if(!dy)
return (dx >= 0) ? 90 : 270
. = arctan(dx/dy)
if(dy < 0)
. += 180
else if(dx < 0)
. += 360

///for getting the angle when animating something's pixel_x and pixel_y
/proc/get_pixel_angle(y, x)
if(!y)
return (x >= 0) ? 90 : 270
. = arctan(x/y)
if(y < 0)
. += 180
else if(x < 0)
. += 360

/**
* Get a list of turfs in a line from `starting_atom` to `ending_atom`.
*
Expand Down
57 changes: 25 additions & 32 deletions code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -99,38 +99,29 @@
var/atom/movable/big_subject = subject
. += (big_subject.bound_height - world.icon_size) / 2

/proc/Get_Angle(atom/start,atom/end, tile_bound = FALSE)//For beams.
if(!start || !end) return 0
if(!start.z || !end.z) return 0 //Atoms are not on turfs.
var/dx
var/dy
if(tile_bound)
dy=end.y-start.y
dx=end.x-start.x
else
dy = get_pixel_position_y(end) - get_pixel_position_y(start)
dx = get_pixel_position_x(end) - get_pixel_position_x(start)
if(!dy)
return (dx>=0)?90:270
.=arctan(dx/dy)
if(dy<0)
.+=180
else if(dx<0)
.+=360

/proc/Get_Compass_Dir(atom/start,atom/end)//get_dir() only considers an object to be north/south/east/west if there is zero deviation. This uses rounding instead.
if(!start || !end) return 0
if(!start.z || !end.z) return 0 //Atoms are not on turfs.
var/dy=end.y-start.y
var/dx=end.x-start.x
if(!dy)
return (dx>=0)?4:8
var/angle=arctan(dx/dy)
if(dy<0)
angle+=180
else if(dx<0)
angle+=360

/// Calculate the angle between two atoms. Uses north-clockwise convention: NORTH = 0, EAST = 90, etc.
/proc/Get_Angle(atom/start, atom/end)//For beams.
if(!start || !end)
return 0
if(!start.z)
start = get_turf(start)
if(!start)
return 0 //Atoms are not on turfs.
if(!end.z)
end = get_turf(end)
if(!end)
return 0 //Atoms are not on turfs.
var/dy = get_pixel_position_y(end) - get_pixel_position_y(start)
var/dx = get_pixel_position_x(end) - get_pixel_position_x(start)
return delta_to_angle(dx, dy)

/// Calculate the angle produced by a pair of x and y deltas. Uses north-clockwise convention: NORTH = 0, EAST = 90, etc.
/proc/delta_to_angle(dx, dy)
. = arctan(dy, dx) //y-then-x results in north-clockwise convention: https://en.wikipedia.org/wiki/Atan2#East-counterclockwise,_north-clockwise_and_south-clockwise_conventions,_etc.
if(. < 0)
. += 360

/proc/angle_to_dir(angle)
switch(angle) //diagonal directions get priority over straight directions in edge cases
if (22.5 to 67.5)
return NORTHEAST
Expand All @@ -151,6 +142,8 @@
else
return NORTH

/proc/Get_Compass_Dir(atom/start, atom/end)//get_dir() only considers an object to be north/south/east/west if there is zero deviation. This uses rounding instead.
return angle_to_dir(Get_Angle(get_turf(start), get_turf(end)))

// Among other things, used by flamethrower and boiler spray to calculate if flame/spray can pass through.
// Returns an atom for specific effects (primarily flames and acid spray) that damage things upon contact
Expand Down
1 change: 1 addition & 0 deletions code/_onclick/hud/hud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
hud_version = display_hud_version
persistent_inventory_update(screenmob)
mymob.update_action_buttons(TRUE)
reorganize_alerts(screenmob)
mymob.reload_fullscreens()

// ensure observers get an accurate and up-to-date view
Expand Down
8 changes: 8 additions & 0 deletions code/_onclick/hud/rendering/plane_master.dm
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@
remove_filter("AO")
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))

/atom/movable/screen/plane_master/nvg_plane
name = "NVG plane"
plane = NVG_PLANE
render_relay_plane = RENDER_PLANE_GAME
blend_mode_override = BLEND_MULTIPLY
//icon = 'icons/mob/hud/screen1.dmi'
//icon_state = "noise"

/atom/movable/screen/plane_master/fullscreen
name = "fullscreen alert plane"
plane = FULLSCREEN_PLANE
Expand Down
12 changes: 6 additions & 6 deletions code/_onclick/hud/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -523,17 +523,17 @@
if(user.observed_xeno == user.tracked_marker)
user.overwatch(user.tracked_marker, TRUE) //passing in an obj/effect into a proc that expects mob/xenomorph B)
else
to_chat(user, SPAN_XENONOTICE("You psychically observe the [user.tracked_marker.mark_meaning.name] resin mark in [get_area_name(user.tracked_marker)]."))
to_chat(user, SPAN_XENONOTICE("We psychically observe the [user.tracked_marker.mark_meaning.name] resin mark in [get_area_name(user.tracked_marker)]."))
user.overwatch(user.tracked_marker) //this is so scuffed, sorry if this causes errors
return
if(mods["alt"] && user.tracked_marker)
user.stop_tracking_resin_mark()
return
if(!user.hive)
to_chat(user, SPAN_WARNING("You don't belong to a hive!"))
to_chat(user, SPAN_WARNING("We don't belong to a hive!"))
return FALSE
if(!user.hive.living_xeno_queen)
to_chat(user, SPAN_WARNING("Without a queen your psychic link is broken!"))
to_chat(user, SPAN_WARNING("Without a queen our psychic link is broken!"))
return FALSE
if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled)
return FALSE
Expand All @@ -551,10 +551,10 @@
return FALSE
if(mods["shift"])
var/area/current_area = get_area(user)
to_chat(user, SPAN_NOTICE("You are currently at: <b>[current_area.name]</b>."))
to_chat(user, SPAN_NOTICE("We are currently at: <b>[current_area.name]</b>."))
return
if(!user.hive)
to_chat(user, SPAN_WARNING("You don't belong to a hive!"))
to_chat(user, SPAN_WARNING("We don't belong to a hive!"))
return FALSE
if(mods["alt"])
var/list/options = list()
Expand All @@ -581,7 +581,7 @@
track_state = options[selected]
return
if(!user.hive.living_xeno_queen)
to_chat(user, SPAN_WARNING("Your hive doesn't have a living queen!"))
to_chat(user, SPAN_WARNING("Our hive doesn't have a living queen!"))
return FALSE
if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled)
return FALSE
Expand Down
Loading

0 comments on commit fbe956e

Please sign in to comment.