mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2026-08-26 14:17:12 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -13,9 +13,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
|
||||
/datum/admin_rank/New(init_name, init_rights, init_exclude_rights, init_edit_rights)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
if (name == "NoRank") //only del if this is a true creation (and not just a New() proc call), other wise trialmins/coders could abuse this to deadmin other admins
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin proc call creation of admin datum")
|
||||
@@ -35,9 +33,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
|
||||
/datum/admin_rank/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
@@ -93,9 +89,7 @@ GLOBAL_PROTECT(protected_ranks)
|
||||
// Adds/removes rights to this admin_rank
|
||||
/datum/admin_rank/proc/process_keyword(word, previous_rights=0)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
var/flag = admin_keyword_to_flag(word, previous_rights)
|
||||
if(flag)
|
||||
|
||||
@@ -40,9 +40,7 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
/datum/admins/New(datum/admin_rank/R, ckey, force_active = FALSE, protected)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
if (!target) //only del if this is a true creation (and not just a New() proc call), other wise trialmins/coders could abuse this to deadmin other admins
|
||||
QDEL_IN(src, 0)
|
||||
CRASH("Admin proc call creation of admin datum")
|
||||
@@ -70,17 +68,13 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
/datum/admins/Destroy()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
. = ..()
|
||||
|
||||
/datum/admins/proc/activate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
GLOB.deadmins -= target
|
||||
GLOB.admin_datums[target] = src
|
||||
@@ -91,9 +85,7 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
/datum/admins/proc/deactivate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
GLOB.deadmins[target] = src
|
||||
GLOB.admin_datums -= target
|
||||
@@ -105,9 +97,7 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
/datum/admins/proc/associate(client/C)
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
|
||||
if(istype(C))
|
||||
@@ -127,9 +117,7 @@ GLOBAL_PROTECT(href_token)
|
||||
|
||||
/datum/admins/proc/disassociate()
|
||||
if(IsAdminAdvancedProcCall())
|
||||
var/msg = " has tried to elevate permissions!"
|
||||
message_admins("[key_name_admin(usr)][msg]")
|
||||
log_admin("[key_name(usr)][msg]")
|
||||
alert_to_permissions_elevation_attempt(usr)
|
||||
return
|
||||
if(owner)
|
||||
GLOB.admins -= owner
|
||||
|
||||
@@ -2118,8 +2118,7 @@
|
||||
if(!ismob(M))
|
||||
to_chat(usr, "This can only be used on instances of type /mob.")
|
||||
return
|
||||
var/datum/language_holder/H = M.get_language_holder()
|
||||
H.open_language_menu(usr)
|
||||
M.get_language_holder().open_language_menu(usr)
|
||||
|
||||
else if(href_list["traitor"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
|
||||
@@ -142,9 +142,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
|
||||
/obj/effect/statclick/ticket_list
|
||||
var/current_state
|
||||
|
||||
/obj/effect/statclick/ticket_list/New(loc, name, state)
|
||||
/obj/effect/statclick/ticket_list/Initialize(mapload, name, state)
|
||||
. = ..()
|
||||
current_state = state
|
||||
..()
|
||||
|
||||
/obj/effect/statclick/ticket_list/Click()
|
||||
GLOB.ahelp_tickets.BrowseTickets(current_state)
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
|
||||
..()
|
||||
owner.faction |= "slime"
|
||||
owner.grant_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
|
||||
owner.grant_language(/datum/language/slime, source = LANGUAGE_GLAND)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/Remove(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
owner.faction -= "slime"
|
||||
owner.remove_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
|
||||
owner.remove_language(/datum/language/slime, source = LANGUAGE_GLAND)
|
||||
|
||||
/obj/item/organ/heart/gland/slime/activate()
|
||||
to_chat(owner, "<span class='warning'>You feel nauseated!</span>")
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
// Physiology
|
||||
CheckVampOrgans() // Heart, Eyes
|
||||
// Language
|
||||
owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_BLOODSUCKER)
|
||||
owner.current.grant_language(/datum/language/vampiric, source = LANGUAGE_BLOODSUCKER)
|
||||
owner.hasSoul = FALSE // If false, renders the character unable to sell their soul.
|
||||
owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles
|
||||
// Disabilities
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
objectives += vassal_objective
|
||||
objectives_given += vassal_objective
|
||||
give_thrall_eyes()
|
||||
owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_VASSAL)
|
||||
owner.current.grant_language(/datum/language/vampiric, source = LANGUAGE_VASSAL)
|
||||
// Add Antag HUD
|
||||
update_vassal_icons_added(owner.current, "vassal")
|
||||
. = ..()
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
create_initial_profile()
|
||||
if(give_objectives)
|
||||
forge_objectives()
|
||||
owner.current.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue. We are able to transform our body after all.
|
||||
owner.current.get_language_holder().omnitongue = TRUE
|
||||
remove_clownmut()
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
current = mob_override
|
||||
GLOB.all_clockwork_mobs += current
|
||||
current.faction |= "ratvar"
|
||||
current.grant_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_CLOCKIE)
|
||||
current.grant_language(/datum/language/ratvar, source = LANGUAGE_CLOCKIE)
|
||||
current.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
|
||||
if(issilicon(current))
|
||||
var/mob/living/silicon/S = current
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
current.faction |= "cult"
|
||||
current.grant_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
|
||||
current.grant_language(/datum/language/narsie, source = LANGUAGE_CULTIST)
|
||||
if(!cult_team?.cult_master)
|
||||
vote.Grant(current)
|
||||
communion.Grant(current)
|
||||
@@ -139,7 +139,7 @@
|
||||
if(mob_override)
|
||||
current = mob_override
|
||||
current.faction -= "cult"
|
||||
current.remove_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
|
||||
current.remove_language(/datum/language/narsie, source = LANGUAGE_CULTIST)
|
||||
vote.Remove(current)
|
||||
communion.Remove(current)
|
||||
magic.Remove(current)
|
||||
|
||||
@@ -182,9 +182,8 @@
|
||||
add_antag_hud(antag_hud_type, antag_hud_name, M)
|
||||
if(M.hud_used)
|
||||
var/datum/hud/H = M.hud_used
|
||||
var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted()
|
||||
var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted(null, H)
|
||||
H.wanted_lvl = giving_wanted_lvl
|
||||
giving_wanted_lvl.hud = H
|
||||
H.infodisplay += giving_wanted_lvl
|
||||
H.mymob.client.screen += giving_wanted_lvl
|
||||
|
||||
|
||||
@@ -113,9 +113,8 @@
|
||||
add_antag_hud(antag_hud_type, antag_hud_name, M)
|
||||
if(M.hud_used)
|
||||
var/datum/hud/H = M.hud_used
|
||||
var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted()
|
||||
var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted(null, H)
|
||||
H.wanted_lvl = giving_wanted_lvl
|
||||
giving_wanted_lvl.hud = H
|
||||
H.infodisplay += giving_wanted_lvl
|
||||
H.mymob.client.screen += giving_wanted_lvl
|
||||
|
||||
|
||||
@@ -65,5 +65,5 @@
|
||||
/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
|
||||
T.add_law_zero()
|
||||
T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
T.owner.current.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MALF)
|
||||
T.owner.current.grant_language(/datum/language/codespeak, source = LANGUAGE_MALF)
|
||||
return FALSE
|
||||
|
||||
@@ -41,13 +41,13 @@
|
||||
var/spawn_amt_left = 20
|
||||
var/spawn_fast = 0
|
||||
|
||||
/obj/effect/rend/New(loc, var/spawn_type, var/spawn_amt, var/desc, var/spawn_fast)
|
||||
/obj/effect/rend/Initialize(mapload, spawn_type, spawn_amt, desc, spawn_fast)
|
||||
. = ..()
|
||||
src.spawn_path = spawn_type
|
||||
src.spawn_amt_left = spawn_amt
|
||||
src.desc = desc
|
||||
src.spawn_fast = spawn_fast
|
||||
START_PROCESSING(SSobj, src)
|
||||
return
|
||||
|
||||
/obj/effect/rend/process()
|
||||
if(!spawn_fast)
|
||||
|
||||
@@ -287,9 +287,7 @@
|
||||
S.real_name = "Shade of [T.real_name]"
|
||||
T.transfer_ckey(S)
|
||||
S.original_mind = T.mind
|
||||
S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
|
||||
S.update_atom_languages()
|
||||
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
|
||||
S.get_language_holder().omnitongue = TRUE //Grants omnitongue
|
||||
if(user)
|
||||
S.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation
|
||||
if(user && iscultist(user))
|
||||
|
||||
@@ -131,10 +131,10 @@
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/item/assembly/mousetrap/hitby(atom/hit_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
/obj/item/assembly/mousetrap/hitby(atom/movable/hit_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
if(!armed)
|
||||
return ..()
|
||||
visible_message("<span class='warning'>[src] is triggered by [hit_atom].</span>")
|
||||
visible_message(span_warning("[src] is triggered by [hit_atom]."))
|
||||
triggered(null)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/datum/asset/simple/namespaced/fonts
|
||||
parents = list("fonts.css" = 'interface/fonts/fonts.css')
|
||||
|
||||
/datum/asset/simple/namespaced/fonts/New()
|
||||
for(var/datum/font/font as anything in subtypesof(/datum/font))
|
||||
var/file = "[initial(font.font_family)]"
|
||||
var/file_name = copytext(file, findlasttext(file, "/") + 1)
|
||||
assets[file_name] = file(file)
|
||||
return ..()
|
||||
@@ -186,6 +186,6 @@ GLOBAL_DATUM_INIT(gas_data, /datum/auxgm, new)
|
||||
appearance_flags = TILE_BOUND
|
||||
vis_flags = NONE
|
||||
|
||||
/obj/effect/overlay/gas/New(state)
|
||||
/obj/effect/overlay/gas/Initialize(mapload, state)
|
||||
. = ..()
|
||||
icon_state = state
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/atom/movable/screen/buildmode
|
||||
icon = 'icons/misc/buildmode.dmi'
|
||||
mouse_over_pointer = MOUSE_HAND_POINTER
|
||||
var/datum/buildmode/bd
|
||||
// If we don't do this, we get occluded by item action buttons
|
||||
layer = ABOVE_HUD_LAYER
|
||||
|
||||
@@ -171,6 +171,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! <a href=\"https://secure.byond.com/membership\">Click Here to find out more</a>.")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/client/proc/is_localhost()
|
||||
var/static/localhost_addresses = list(
|
||||
"127.0.0.1",
|
||||
"::1",
|
||||
null,
|
||||
)
|
||||
return address in localhost_addresses
|
||||
|
||||
/*
|
||||
* Call back proc that should be checked in all paths where a client can send messages
|
||||
*
|
||||
|
||||
@@ -483,11 +483,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
dat += "<HR>"
|
||||
|
||||
dat += "<center>"
|
||||
var/savefile/client_file = new(user.client.Import())
|
||||
var/file = user.client.Import()
|
||||
var/savefile/client_file
|
||||
var/savefile_name
|
||||
if(istype(client_file, /savefile))
|
||||
if(!client_file["deleted"] || savefile_needs_update(client_file) != -2)
|
||||
client_file["real_name"] >> savefile_name
|
||||
if(file)
|
||||
client_file = new(file)
|
||||
if(istype(client_file, /savefile))
|
||||
if(!client_file["deleted"] || savefile_needs_update(client_file) != -2)
|
||||
client_file["real_name"] >> savefile_name
|
||||
dat += "Local storage: [savefile_name ? savefile_name : "Empty"]"
|
||||
dat += "<br />"
|
||||
dat += "<a href='?_src_=prefs;preference=export_slot'>Export current slot</a>"
|
||||
@@ -1462,11 +1465,11 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
if(user.client)
|
||||
if(unlock_content)
|
||||
dat += "<b>BYOND Membership Publicity:</b> <a href='?_src_=prefs;preference=publicity'>[(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]</a><br>"
|
||||
if(unlock_content || check_rights_for(user.client, R_ADMIN))
|
||||
if(unlock_content || is_admin(user.client))
|
||||
dat += "<b>OOC Color:</b> <span style='border: 1px solid #161616; background-color: [ooccolor ? ooccolor : GLOB.normal_ooc_colour];'><font color='[color_hex2num(ooccolor ? ooccolor : GLOB.normal_ooc_colour) < 200 ? "FFFFFF" : "000000"]'>[ooccolor ? ooccolor : GLOB.normal_ooc_colour]</font></span> <a href='?_src_=prefs;preference=ooccolor;task=input'>Change</a><br>"
|
||||
dat += "<b>Antag OOC Color:</b> <span style='border: 1px solid #161616; background-color: [aooccolor ? aooccolor : GLOB.normal_aooc_colour];'><font color='[color_hex2num(aooccolor ? aooccolor : GLOB.normal_aooc_colour) < 200 ? "FFFFFF" : "000000"]'>[aooccolor ? aooccolor : GLOB.normal_aooc_colour]</font></span> <a href='?_src_=prefs;preference=aooccolor;task=input'>Change</a><br>"
|
||||
|
||||
if(user.client.holder)
|
||||
if(is_admin(user.client))
|
||||
dat += "<h2>Admin Settings</h2>"
|
||||
dat += "<b>Adminhelp Sounds:</b> <a href='?_src_=prefs;preference=hear_adminhelps'>[(toggles & SOUND_ADMINHELP)?"Enabled":"Disabled"]</a><br>"
|
||||
dat += "<b>Announce Login:</b> <a href='?_src_=prefs;preference=announce_login'>[(toggles & ANNOUNCE_LOGIN)?"Enabled":"Disabled"]</a><br>"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/obj/item/clothing/head/helmet/space/chronos/dropped(mob/user)
|
||||
if(suit)
|
||||
suit.deactivate(1, 1)
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/space/chronos
|
||||
name = "Chronosuit"
|
||||
@@ -23,23 +23,22 @@
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
mutantrace_variation = STYLE_DIGITIGRADE
|
||||
var/list/chronosafe_items = list(/obj/item/chrono_eraser, /obj/item/gun/energy/chrono_gun)
|
||||
var/obj/item/clothing/head/helmet/space/chronos/helmet = null
|
||||
var/obj/effect/chronos_cam/camera = null
|
||||
var/datum/action/innate/chrono_teleport/teleport_now = new
|
||||
var/obj/item/clothing/head/helmet/space/chronos/helmet
|
||||
var/obj/effect/chronos_cam/camera
|
||||
var/datum/action/innate/chrono_teleport/teleport_now
|
||||
var/activating = 0
|
||||
var/activated = 0
|
||||
var/cooldowntime = 50 //deciseconds
|
||||
var/cooldowntime = 5 SECONDS
|
||||
var/teleporting = 0
|
||||
var/phase_timer_id
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/New()
|
||||
..()
|
||||
/obj/item/clothing/suit/space/chronos/Initialize(mapload)
|
||||
. = ..()
|
||||
teleport_now = new(src)
|
||||
teleport_now.chronosuit = src
|
||||
teleport_now.target = src
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/proc/new_camera(mob/user)
|
||||
if(camera)
|
||||
qdel(camera)
|
||||
QDEL_NULL(camera)
|
||||
camera = new /obj/effect/chronos_cam(user)
|
||||
camera.holder = user
|
||||
camera.chronosuit = src
|
||||
@@ -55,7 +54,7 @@
|
||||
/obj/item/clothing/suit/space/chronos/dropped(mob/user)
|
||||
if(activated)
|
||||
deactivate()
|
||||
..()
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/emp_act(severity)
|
||||
. = ..()
|
||||
@@ -64,8 +63,8 @@
|
||||
var/mob/living/carbon/human/user = src.loc
|
||||
if(severity >= 70)
|
||||
if(activated && user && ishuman(user) && (user.wear_suit == src))
|
||||
to_chat(user, "<span class='danger'>E:FATAL:RAM_READ_FAIL\nE:FATAL:STACK_EMPTY\nE:FATAL:READ_NULL_POINT\nE:FATAL:PWR_BUS_OVERLOAD</span>")
|
||||
to_chat(user, "<span class='userdanger'>An electromagnetic pulse disrupts your [name] and violently tears you out of time-bluespace!</span>")
|
||||
to_chat(user, span_danger("E:FATAL:RAM_READ_FAIL\nE:FATAL:STACK_EMPTY\nE:FATAL:READ_NULL_POINT\nE:FATAL:PWR_BUS_OVERLOAD"))
|
||||
to_chat(user, span_userdanger("An electromagnetic pulse disrupts your [name] and violently tears you out of time-bluespace!"))
|
||||
user.emote("scream")
|
||||
deactivate(1, 1)
|
||||
|
||||
@@ -75,23 +74,24 @@
|
||||
if(phase_timer_id)
|
||||
deltimer(phase_timer_id)
|
||||
phase_timer_id = 0
|
||||
if(istype(user))
|
||||
if(to_turf)
|
||||
user.forceMove(to_turf)
|
||||
user.SetStun(0)
|
||||
user.SetNextAction(0, considered_action = FALSE, immediate = FALSE)
|
||||
user.alpha = 255
|
||||
user.update_atom_colour()
|
||||
user.animate_movement = FORWARD_STEPS
|
||||
user.mob_transforming = 0
|
||||
user.anchored = FALSE
|
||||
teleporting = 0
|
||||
for(var/obj/item/I in user.held_items)
|
||||
REMOVE_TRAIT(I, TRAIT_NODROP, CHRONOSUIT_TRAIT)
|
||||
if(camera)
|
||||
camera.remove_target_ui()
|
||||
camera.forceMove(user)
|
||||
teleport_now.UpdateButtons()
|
||||
if(!istype(user))
|
||||
return
|
||||
if(to_turf)
|
||||
user.forceMove(to_turf)
|
||||
user.SetStun(0)
|
||||
user.SetNextAction(0, considered_action = FALSE, immediate = FALSE)
|
||||
user.alpha = 255
|
||||
user.update_atom_colour()
|
||||
user.animate_movement = FORWARD_STEPS
|
||||
user.mob_transforming = 0
|
||||
user.anchored = FALSE
|
||||
teleporting = 0
|
||||
for(var/obj/item/I in user.held_items)
|
||||
REMOVE_TRAIT(I, TRAIT_NODROP, CHRONOSUIT_TRAIT)
|
||||
if(camera)
|
||||
camera.remove_target_ui()
|
||||
camera.forceMove(user)
|
||||
teleport_now.UpdateButtons()
|
||||
|
||||
/obj/item/clothing/suit/space/chronos/proc/chronowalk(atom/location)
|
||||
var/mob/living/carbon/human/user = src.loc
|
||||
@@ -238,7 +238,7 @@
|
||||
var/mob/holder = null
|
||||
var/phase_time = 0
|
||||
var/phase_time_length = 3
|
||||
var/atom/movable/screen/chronos_target/target_ui = null
|
||||
var/atom/movable/screen/chronos_target/target_ui
|
||||
var/obj/item/clothing/suit/space/chronos/chronosuit
|
||||
|
||||
/obj/effect/chronos_cam/singularity_act()
|
||||
@@ -249,17 +249,14 @@
|
||||
|
||||
/obj/effect/chronos_cam/proc/create_target_ui()
|
||||
if(holder && holder.client && chronosuit)
|
||||
if(target_ui)
|
||||
remove_target_ui()
|
||||
target_ui = new(null, holder)
|
||||
remove_target_ui()
|
||||
target_ui = new(null, holder.hud_used, holder)
|
||||
holder.client.screen += target_ui
|
||||
|
||||
/obj/effect/chronos_cam/proc/remove_target_ui()
|
||||
if(target_ui)
|
||||
qdel(target_ui)
|
||||
target_ui = null
|
||||
QDEL_NULL(target_ui)
|
||||
|
||||
/obj/effect/chronos_cam/relaymove(var/mob/user, direction)
|
||||
/obj/effect/chronos_cam/relaymove(mob/user, direction)
|
||||
if(!holder)
|
||||
qdel(src)
|
||||
return
|
||||
@@ -305,13 +302,13 @@
|
||||
color = "#ff3311"
|
||||
blend_mode = BLEND_SUBTRACT
|
||||
|
||||
/atom/movable/screen/chronos_target/New(loc, var/mob/living/carbon/human/user)
|
||||
if(user)
|
||||
var/icon/user_icon = getFlatIcon(user)
|
||||
icon = user_icon
|
||||
transform = user.transform
|
||||
else
|
||||
qdel(src)
|
||||
/atom/movable/screen/chronos_target/Initialize(mapload, datum/hud/hud_owner, mob/living/carbon/human/user)
|
||||
. = ..()
|
||||
if(!user)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
var/icon/user_icon = getFlatIcon(user)
|
||||
icon = user_icon
|
||||
transform = user.transform
|
||||
|
||||
/datum/action/innate/chrono_teleport
|
||||
name = "Teleport Now"
|
||||
@@ -324,6 +321,7 @@
|
||||
return (chronosuit && chronosuit.activated && chronosuit.camera && !chronosuit.teleporting)
|
||||
|
||||
/datum/action/innate/chrono_teleport/Activate()
|
||||
if(IsAvailable())
|
||||
if(chronosuit.camera)
|
||||
chronosuit.chronowalk(chronosuit.camera)
|
||||
if(!IsAvailable())
|
||||
return
|
||||
if(chronosuit.camera)
|
||||
chronosuit.chronowalk(chronosuit.camera)
|
||||
|
||||
@@ -27,10 +27,11 @@
|
||||
if(ishuman(M) && M.w_uniform)
|
||||
var/obj/item/clothing/under/U = M.w_uniform
|
||||
//SANDSTORM EDIT
|
||||
if(istype(U) && length(U.attached_accessories))
|
||||
for(var/obj/item/clothing/accessory/attached in U.attached_accessories)
|
||||
if(attached.above_suit)
|
||||
. += U.accessory_overlays
|
||||
if(istype(U) && !CHECK_BITFIELD(U.flags_inv, HIDEACCESSORY))
|
||||
for(var/obj/item/clothing/accessory/attached as anything in U.attached_accessories)
|
||||
if(CHECK_BITFIELD(attached.flags_inv, HIDEACCESSORY) || !attached.above_suit)
|
||||
continue
|
||||
. += attached.build_worn_icon()
|
||||
//SANDSTORM EDIT END
|
||||
|
||||
/obj/item/clothing/suit/update_clothes_damaged_state()
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
var/dummy_thick = FALSE // is able to hold accessories on its item
|
||||
//SANDSTORM EDIT - Removed the old attached accessory system. We use a list of accessories instead.
|
||||
var/max_accessories = 3
|
||||
var/list/obj/item/clothing/accessory/attached_accessories = list()
|
||||
var/list/mutable_appearance/accessory_overlays = list()
|
||||
var/list/obj/item/clothing/accessory/attached_accessories
|
||||
//SANDSTORM EDIT END
|
||||
|
||||
/obj/item/clothing/under/worn_overlays(isinhands = FALSE, icon_file, used_state, style_flags = NONE)
|
||||
@@ -36,8 +35,12 @@
|
||||
. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
|
||||
if(blood_DNA)
|
||||
. += mutable_appearance('icons/effects/blood.dmi', "uniformblood", color = blood_DNA_to_color(), blend_mode = blood_DNA_to_blend())
|
||||
if(length(accessory_overlays))
|
||||
. += accessory_overlays
|
||||
if(CHECK_BITFIELD(flags_inv, HIDEACCESSORY))
|
||||
return
|
||||
for(var/obj/item/clothing/accessory/attached_accessory as anything in attached_accessories)
|
||||
if(CHECK_BITFIELD(attached_accessory.flags_inv, HIDEACCESSORY))
|
||||
continue
|
||||
. += attached_accessory.build_worn_icon()
|
||||
|
||||
/obj/item/clothing/under/attackby(obj/item/I, mob/user, params)
|
||||
if((sensordamage || (has_sensor < HAS_SENSORS && has_sensor != NO_SENSORS)) && istype(I, /obj/item/stack/cable_coil))
|
||||
@@ -125,68 +128,60 @@
|
||||
body_parts_covered |= CHEST
|
||||
|
||||
// Sandstorm edit
|
||||
for(var/obj/item/clothing/accessory/attached_accessory in attached_accessories)
|
||||
if(attached_accessory && slot != ITEM_SLOT_HANDS && ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/must_update = FALSE
|
||||
for(var/obj/item/clothing/accessory/attached_accessory as anything in attached_accessories)
|
||||
if(attached_accessory && slot == ITEM_SLOT_ICLOTHING && ishuman(user))
|
||||
attached_accessory.on_uniform_equip(src, user)
|
||||
if(attached_accessory.above_suit)
|
||||
H.update_inv_wear_suit()
|
||||
if(attached_accessory.above_suit)
|
||||
must_update = TRUE
|
||||
if(must_update)
|
||||
user.update_inv_wear_suit()
|
||||
//
|
||||
|
||||
/obj/item/clothing/under/dropped(mob/user)
|
||||
// Sandstorm edit
|
||||
for(var/obj/item/clothing/accessory/attached_accessory in attached_accessories)
|
||||
var/must_update = FALSE
|
||||
for(var/obj/item/clothing/accessory/attached_accessory as anything in attached_accessories)
|
||||
attached_accessory.on_uniform_dropped(src, user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(attached_accessory.above_suit)
|
||||
H.update_inv_wear_suit()
|
||||
if(attached_accessory.above_suit)
|
||||
must_update = TRUE
|
||||
if(must_update)
|
||||
user.update_inv_wear_suit()
|
||||
//
|
||||
..()
|
||||
|
||||
/obj/item/clothing/under/proc/attach_accessory(obj/item/I, mob/user, notifyAttach = 1)
|
||||
/obj/item/clothing/under/proc/attach_accessory(obj/item/clothing/accessory/accessory, mob/user, notifyAttach = 1)
|
||||
. = FALSE
|
||||
if(istype(I, /obj/item/clothing/accessory) && !istype(I, /obj/item/clothing/accessory/ring))
|
||||
var/obj/item/clothing/accessory/A = I
|
||||
if(length(attached_accessories) >= max_accessories)
|
||||
if(user)
|
||||
to_chat(user, "<span class='warning'>[src] already has [length(attached_accessories)] accessories.</span>")
|
||||
return
|
||||
if(dummy_thick)
|
||||
if(user)
|
||||
to_chat(user, "<span class='warning'>[src] is too bulky and cannot have accessories attached to it!</span>")
|
||||
return
|
||||
else
|
||||
if(user && !user.temporarilyRemoveItemFromInventory(I))
|
||||
return
|
||||
if(!A.attach(src, user))
|
||||
return
|
||||
if(!istype(accessory))
|
||||
return
|
||||
if(istype(accessory, /obj/item/clothing/accessory/ring))
|
||||
return
|
||||
if(length(attached_accessories) >= max_accessories)
|
||||
if(user)
|
||||
to_chat(user, span_warning("[src] already has [length(attached_accessories)] accessories."))
|
||||
return
|
||||
if(dummy_thick)
|
||||
if(user)
|
||||
to_chat(user, span_warning("[src] is too bulky and cannot have accessories attached to it!"))
|
||||
return
|
||||
if(user && !user.temporarilyRemoveItemFromInventory(accessory))
|
||||
return
|
||||
if(!accessory.attach(src, user))
|
||||
return
|
||||
|
||||
if(user && notifyAttach)
|
||||
to_chat(user, "<span class='notice'>You attach [I] to [src].</span>")
|
||||
if(user && notifyAttach)
|
||||
to_chat(user, span_notice("You attach [accessory] to [src]."))
|
||||
|
||||
if((flags_inv & HIDEACCESSORY) || (A.flags_inv & HIDEACCESSORY))
|
||||
return TRUE
|
||||
if((flags_inv & HIDEACCESSORY) || (accessory.flags_inv & HIDEACCESSORY))
|
||||
return TRUE
|
||||
|
||||
//SANDSTORM EDIT
|
||||
accessory_overlays = list(mutable_appearance('icons/mob/clothing/accessories.dmi', "blank"))
|
||||
for(var/obj/item/clothing/accessory/attached_accessory in attached_accessories)
|
||||
var/datum/element/polychromic/polychromic = LAZYACCESS(attached_accessory.comp_lookup, "item_worn_overlays")
|
||||
if(!polychromic)
|
||||
var/mutable_appearance/accessory_overlay = mutable_appearance(attached_accessory.mob_overlay_icon, attached_accessory.item_state || attached_accessory.icon_state, ABOVE_HUD_LAYER)
|
||||
accessory_overlay.alpha = attached_accessory.alpha
|
||||
accessory_overlay.color = attached_accessory.color
|
||||
accessory_overlays += accessory_overlay
|
||||
else
|
||||
polychromic.apply_worn_overlays(attached_accessory, FALSE, attached_accessory.mob_overlay_icon, attached_accessory.item_state || attached_accessory.icon_state, NONE, accessory_overlays)
|
||||
//SANDSTORM EDIT END
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.update_inv_w_uniform()
|
||||
if(accessory.above_suit)
|
||||
H.update_inv_wear_suit()
|
||||
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.update_inv_w_uniform()
|
||||
H.update_inv_wear_suit()
|
||||
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/under/proc/remove_accessory(mob/user)
|
||||
if(!isliving(user))
|
||||
@@ -194,22 +189,21 @@
|
||||
if(!can_use(user))
|
||||
return
|
||||
|
||||
//SKYRAT EDIT
|
||||
if(length(attached_accessories))
|
||||
var/obj/item/clothing/accessory/A = attached_accessories[length(attached_accessories)]
|
||||
//SKYRAT EDIT END
|
||||
A.detach(src, user)
|
||||
if(user.put_in_hands(A))
|
||||
to_chat(user, "<span class='notice'>You detach [A] from [src].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You detach [A] from [src] and it falls on the floor.</span>")
|
||||
if(!LAZYLEN(attached_accessories))
|
||||
return
|
||||
var/obj/item/clothing/accessory/accessory = attached_accessories[length(attached_accessories)]
|
||||
accessory.detach(src, user)
|
||||
if(user.put_in_hands(accessory))
|
||||
to_chat(user, span_notice("You detach [accessory] from [src]."))
|
||||
else
|
||||
to_chat(user, span_notice("You detach [accessory] from [src] and it falls on the floor."))
|
||||
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.update_inv_w_uniform()
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/H = loc
|
||||
H.update_inv_w_uniform()
|
||||
if(accessory.above_suit)
|
||||
H.update_inv_wear_suit()
|
||||
|
||||
|
||||
/obj/item/clothing/under/examine(mob/user)
|
||||
. = ..()
|
||||
if(can_adjust)
|
||||
@@ -234,10 +228,9 @@
|
||||
. += "Its vital tracker appears to be enabled."
|
||||
if(SENSOR_COORDS)
|
||||
. += "Its vital tracker and tracking beacon appear to be enabled."
|
||||
if(length(attached_accessories))
|
||||
for(var/obj/item/clothing/accessory/attached_accessory in attached_accessories)
|
||||
. += "\A [attached_accessory] is attached to it."
|
||||
//SKYRAT EDIT END
|
||||
for(var/obj/item/clothing/accessory/attached_accessory as anything in attached_accessories)
|
||||
. += "\A [attached_accessory] is attached to it."
|
||||
//SANDSTORM EDIT END
|
||||
|
||||
/obj/item/clothing/under/verb/toggle()
|
||||
set name = "Adjust Suit Sensors"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name = "Accessory"
|
||||
desc = "Something has gone wrong!"
|
||||
icon = 'icons/obj/clothing/accessories.dmi'
|
||||
//skyrat edit
|
||||
//sandstorm edit
|
||||
mob_overlay_icon = 'icons/mob/clothing/accessories.dmi'
|
||||
//
|
||||
icon_state = "plasma"
|
||||
@@ -13,48 +13,41 @@
|
||||
var/above_suit = FALSE
|
||||
var/minimize_when_attached = TRUE // TRUE if shown as a small icon in corner, FALSE if overlayed
|
||||
var/datum/component/storage/detached_pockets
|
||||
//skyrat edit
|
||||
var/current_uniform = null
|
||||
//
|
||||
|
||||
/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/U, user)
|
||||
/obj/item/clothing/accessory/proc/attach(obj/item/clothing/under/uniform, user)
|
||||
var/datum/component/storage/storage = GetComponent(/datum/component/storage)
|
||||
if(storage)
|
||||
if(SEND_SIGNAL(U, COMSIG_CONTAINS_STORAGE))
|
||||
if(SEND_SIGNAL(uniform, COMSIG_CONTAINS_STORAGE))
|
||||
return FALSE
|
||||
U.TakeComponent(storage)
|
||||
uniform.TakeComponent(storage)
|
||||
detached_pockets = storage
|
||||
//SKYRAT EDIT
|
||||
U.attached_accessories |= src
|
||||
force_unto(U)
|
||||
current_uniform = U
|
||||
//SKYRAT EDIT END
|
||||
forceMove(U)
|
||||
//SANDSTORM EDIT
|
||||
LAZYADD(uniform.attached_accessories, src)
|
||||
force_unto(uniform)
|
||||
//SANDSTORM EDIT END
|
||||
forceMove(uniform)
|
||||
|
||||
if (islist(U.armor) || isnull(U.armor)) // This proc can run before /obj/Initialize has run for U and src,
|
||||
U.armor = getArmor(arglist(U.armor)) // we have to check that the armor list has been transformed into a datum before we try to call a proc on it
|
||||
if (islist(uniform.armor) || isnull(uniform.armor)) // This proc can run before /obj/Initialize has run for uniform and src,
|
||||
uniform.armor = getArmor(arglist(uniform.armor)) // we have to check that the armor list has been transformed into a datum before we try to call a proc on it
|
||||
// This is safe to do as /obj/Initialize only handles setting up the datum if actually needed.
|
||||
if (islist(armor) || isnull(armor))
|
||||
armor = getArmor(arglist(armor))
|
||||
|
||||
U.armor = U.armor.attachArmor(armor)
|
||||
uniform.armor = uniform.armor.attachArmor(armor)
|
||||
|
||||
if(isliving(user))
|
||||
on_uniform_equip(U, user)
|
||||
on_uniform_equip(uniform, user)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/U, user)
|
||||
if(detached_pockets && detached_pockets.parent == U)
|
||||
/obj/item/clothing/accessory/proc/detach(obj/item/clothing/under/uniform, user)
|
||||
if(detached_pockets && detached_pockets.parent == uniform)
|
||||
TakeComponent(detached_pockets)
|
||||
|
||||
U.armor = U.armor.detachArmor(armor)
|
||||
//SANDSTORM EDIT
|
||||
current_uniform = null
|
||||
//SANDSTORM EDIT END
|
||||
uniform.armor = uniform.armor.detachArmor(armor)
|
||||
|
||||
if(isliving(user))
|
||||
on_uniform_dropped(U, user)
|
||||
on_uniform_dropped(uniform, user)
|
||||
|
||||
if(minimize_when_attached)
|
||||
transform *= 2
|
||||
@@ -62,48 +55,36 @@
|
||||
pixel_y = 0
|
||||
layer = initial(layer)
|
||||
plane = initial(plane)
|
||||
U.cut_overlays()
|
||||
U.attached_accessories -= src
|
||||
U.accessory_overlays = list()
|
||||
if(length(U.attached_accessories))
|
||||
U.accessory_overlays = list(mutable_appearance('icons/mob/clothing/accessories.dmi', "blank"))
|
||||
for(var/obj/item/clothing/accessory/attached_accessory in U.attached_accessories)
|
||||
attached_accessory.force_unto(U)
|
||||
var/datum/element/polychromic/polychromic = LAZYACCESS(attached_accessory.comp_lookup, "item_worn_overlays")
|
||||
if(!polychromic)
|
||||
var/mutable_appearance/accessory_overlay = mutable_appearance(attached_accessory.mob_overlay_icon, attached_accessory.item_state || attached_accessory.icon_state, ABOVE_HUD_LAYER)
|
||||
accessory_overlay.alpha = attached_accessory.alpha
|
||||
accessory_overlay.color = attached_accessory.color
|
||||
U.accessory_overlays += accessory_overlay
|
||||
else
|
||||
polychromic.apply_worn_overlays(attached_accessory, FALSE, attached_accessory.mob_overlay_icon, attached_accessory.item_state || attached_accessory.icon_state, NONE, U.accessory_overlays)
|
||||
uniform.cut_overlays()
|
||||
LAZYREMOVE(uniform.attached_accessories, src)
|
||||
for(var/obj/item/clothing/accessory/attached_accessory as anything in uniform.attached_accessories)
|
||||
uniform.add_overlay(attached_accessory)
|
||||
|
||||
//SANDSTORM EDIT
|
||||
/obj/item/clothing/accessory/proc/force_unto(obj/item/clothing/under/U)
|
||||
/obj/item/clothing/accessory/proc/force_unto(obj/item/clothing/under/uniform)
|
||||
layer = FLOAT_LAYER
|
||||
plane = FLOAT_PLANE
|
||||
if(minimize_when_attached)
|
||||
if(current_uniform != U)
|
||||
transform *= 0.5 //halve the size so it doesn't overpower the under
|
||||
pixel_x += 8
|
||||
pixel_y -= 8
|
||||
if(length(U.attached_accessories) > 1)
|
||||
if(length(U.attached_accessories) <= 3 && !current_uniform)
|
||||
pixel_y += 8 * (length(U.attached_accessories) - 1)
|
||||
else if((length(U.attached_accessories) > 3) && (length(U.attached_accessories) <= 6) && !current_uniform)
|
||||
pixel_x -= 8
|
||||
pixel_y += 8 * (length(U.attached_accessories) - 4)
|
||||
else if((length(U.attached_accessories) > 6) && (length(U.attached_accessories) <= 9) && !current_uniform)
|
||||
pixel_x -= 16
|
||||
pixel_y += 8 * (length(U.attached_accessories) - 7)
|
||||
else
|
||||
if(current_uniform != U)
|
||||
transform *= 0.5 //halve the size so it doesn't overpower the under
|
||||
pixel_x += 8
|
||||
pixel_y -= 8
|
||||
if(length(uniform.attached_accessories) > 1)
|
||||
switch(LAZYLEN(uniform.attached_accessories))
|
||||
if(2 to 3)
|
||||
pixel_y += 8 * (length(uniform.attached_accessories) - 1)
|
||||
if(4 to 6)
|
||||
pixel_x -= 8
|
||||
pixel_y += 8 * (length(uniform.attached_accessories) - 4)
|
||||
if(7 to 9)
|
||||
pixel_x -= 16
|
||||
pixel_y += 8 * (length(uniform.attached_accessories) - 7)
|
||||
else
|
||||
//we ran out of space for accessories, so we just throw shit at the wall
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
pixel_x += rand(-16, 16)
|
||||
pixel_y += rand(-16, 16)
|
||||
U.add_overlay(src)
|
||||
uniform.add_overlay(src)
|
||||
//SANDSTORM EDIT END
|
||||
|
||||
/obj/item/clothing/accessory/proc/on_uniform_equip(obj/item/clothing/under/U, user)
|
||||
@@ -122,9 +103,9 @@
|
||||
|
||||
/obj/item/clothing/accessory/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>\The [src] can be attached to [istype(src, /obj/item/clothing/accessory/ring) ? "gloves" : "a uniform"]. Alt-click to remove it once attached.</span>"
|
||||
. += span_notice("\The [src] can be attached to [istype(src, /obj/item/clothing/accessory/ring) ? "gloves" : "a uniform"]. <b>Alt-click</b> to remove it once attached.")
|
||||
if(initial(above_suit))
|
||||
. += "<span class='notice'>\The [src] can be worn above or below your suit. Ctrl-click to toggle.</span>"
|
||||
. += span_notice("\The [src] can be worn above or below your suit. <b>Ctrl-click</b> to toggle.")
|
||||
|
||||
//////////////
|
||||
//Waistcoats//
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
SG.transfer_ckey(SA, FALSE)
|
||||
|
||||
SA.grant_all_languages(TRUE, FALSE, FALSE)
|
||||
SA.grant_all_languages(UNDERSTOOD_LANGUAGE, grant_omnitongue = FALSE, source = LANGUAGE_ATOM)
|
||||
|
||||
SA.sentience_act()
|
||||
|
||||
|
||||
@@ -122,10 +122,10 @@
|
||||
if (isitem(AM) && !istype(AM,/obj/item/projectile))
|
||||
if(prob(50))
|
||||
AM.forceMove(get_turf(src))
|
||||
visible_message("<span class='warning'>Swish! [AM] lands in [src].</span>")
|
||||
visible_message(span_warning("Swish! [AM] lands in [src]."))
|
||||
return
|
||||
else
|
||||
visible_message("<span class='danger'>[AM] bounces off of [src]'s rim!</span>")
|
||||
visible_message(span_danger("[AM] bounces off of [src]'s rim!"))
|
||||
return ..()
|
||||
else
|
||||
return ..()
|
||||
|
||||
@@ -50,4 +50,5 @@
|
||||
if(visualsOnly)
|
||||
return
|
||||
|
||||
H.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_CURATOR)
|
||||
H.grant_all_languages(source = LANGUAGE_CURATOR)
|
||||
H.remove_blocked_language(GLOB.all_languages, source=LANGUAGE_ALL)
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly your mind is filled with codewords and responses.</span>")
|
||||
user.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
|
||||
user.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND)
|
||||
|
||||
use_charge(user)
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='italics'>You hear smacking.</span>")
|
||||
else
|
||||
M.visible_message("<span class='notice'>[user] teaches [M] by beating [M.p_them()] over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], codewords and responses flow through your mind.</span>", "<span class='italics'>You hear smacking.</span>")
|
||||
M.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
|
||||
M.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND)
|
||||
use_charge(user)
|
||||
|
||||
/obj/item/codespeak_manual/proc/use_charge(mob/user)
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
/*!Language holders will either exist in an atom/movable or a mind. Creation of language holders happens
|
||||
/*!Language holders will either exist in an atom/movable. Creation of language holders happens
|
||||
automatically when they are needed, for example when something tries to speak.
|
||||
Where a mind is available, the mind language holder will be the one "in charge". The mind holder
|
||||
will update its languages based on the atom holder, and will get updated as part of
|
||||
transformations and other events that cause new languages to become available.
|
||||
|
||||
Every language holder has three lists of languages (and sources for each of them):
|
||||
- understood_languages
|
||||
- spoken_languages
|
||||
- blocked_languages
|
||||
|
||||
Understood languages let you understand them, spoken languages lets you speak them
|
||||
(if your tongue is compatible), and blocked languages will let you do neither no matter
|
||||
what the source of the language is.
|
||||
|
||||
Language holders are designed to mostly only ever require the use the helpers in atom/movable
|
||||
to achieve your goals, but it is also possible to work on them directly if needed. Any adding
|
||||
and removing of languages and sources should only happen through the procs, as directly changing
|
||||
these will mess something up somewhere down the line.
|
||||
|
||||
All atom movables have the initial_language_holder var which allows you to set the default language
|
||||
holder to create. For example, /datum/language_holder/alien will give you xenocommon and a block for
|
||||
galactic common. Human species also have a default language holder var that will be updated on
|
||||
species change, initial_species_holder.
|
||||
|
||||
Key procs
|
||||
* [grant_language](atom/movable.html#proc/grant_language)
|
||||
* [remove_language](atom/movable.html#proc/remove_language)
|
||||
@@ -28,83 +33,86 @@ Key procs
|
||||
* [has_language](atom/movable.html#proc/has_language)
|
||||
* [can_speak_language](atom/movable.html#proc/can_speak_language)
|
||||
* [get_selected_language](atom/movable.html#proc/get_selected_language)
|
||||
* [update_atom_languages](atom/movable.html#proc/update_atom_languages)
|
||||
*/
|
||||
|
||||
/datum/language_holder
|
||||
/// Understood languages.
|
||||
var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_MIND))
|
||||
/// A list of languages that can be spoken. Tongue organ may also set limits beyond this list.
|
||||
/// Lazyassoclist of all understood languages
|
||||
var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
|
||||
/// Lazyassoclist of languages that can be spoken.
|
||||
/// Tongue organ may also set limits beyond this list.
|
||||
var/list/spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
|
||||
/// A list of blocked languages. Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc.
|
||||
var/list/blocked_languages = list()
|
||||
/// If true, overrides tongue limitations.
|
||||
/// Lazyassoclist of blocked languages.
|
||||
/// Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc.
|
||||
var/list/blocked_languages
|
||||
/// If true, overrides tongue aforementioned limitations.
|
||||
var/omnitongue = FALSE
|
||||
/// Handles displaying the language menu UI.
|
||||
var/datum/language_menu/language_menu
|
||||
/// Currently spoken language
|
||||
var/selected_language
|
||||
/// Tracks the entity that owns the holder.
|
||||
var/owner
|
||||
var/atom/movable/owner
|
||||
|
||||
/// Initializes, and copies in the languages from the current atom if available.
|
||||
/datum/language_holder/New(_owner)
|
||||
owner = _owner
|
||||
if(istype(owner, /datum/mind))
|
||||
var/datum/mind/M = owner
|
||||
if(M.current)
|
||||
update_atom_languages(M.current)
|
||||
get_selected_language()
|
||||
/datum/language_holder/New(atom/new_owner)
|
||||
if(new_owner)
|
||||
if(QDELETED(new_owner))
|
||||
CRASH("Langauge holder added to a qdeleting thing, what the fuck [text_ref(new_owner)]")
|
||||
if(!ismovable(new_owner))
|
||||
CRASH("Language holder being added to a non-movable thing, this is invalid (was: [new_owner] / [new_owner.type])")
|
||||
|
||||
owner = new_owner
|
||||
|
||||
// If we have an owner, we'll set a default selected language
|
||||
if(owner)
|
||||
get_selected_language()
|
||||
|
||||
/datum/language_holder/Destroy()
|
||||
QDEL_NULL(language_menu)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/// Grants the supplied language.
|
||||
/datum/language_holder/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_MIND)
|
||||
if(understood)
|
||||
if(!understood_languages[language])
|
||||
understood_languages[language] = list()
|
||||
understood_languages[language] |= source
|
||||
/datum/language_holder/proc/grant_language(language, language_flags = ALL, source = LANGUAGE_MIND)
|
||||
if(language_flags & UNDERSTOOD_LANGUAGE)
|
||||
LAZYORASSOCLIST(understood_languages, language, source)
|
||||
. = TRUE
|
||||
if(spoken)
|
||||
if(!spoken_languages[language])
|
||||
spoken_languages[language] = list()
|
||||
spoken_languages[language] |= source
|
||||
if(language_flags & SPOKEN_LANGUAGE)
|
||||
LAZYORASSOCLIST(spoken_languages, language, source)
|
||||
. = TRUE
|
||||
|
||||
return .
|
||||
|
||||
/// Grants every language to understood and spoken, and gives omnitongue.
|
||||
/datum/language_holder/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
|
||||
/datum/language_holder/proc/grant_all_languages(language_flags = ALL, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
|
||||
for(var/language in GLOB.all_languages)
|
||||
grant_language(language, understood, spoken, source)
|
||||
if(grant_omnitongue) // Overrides tongue limitations.
|
||||
grant_language(language, language_flags, source)
|
||||
if(grant_omnitongue) // Overrides tongue limitations.
|
||||
omnitongue = TRUE
|
||||
return TRUE
|
||||
|
||||
/// Removes a single language or source, removing all sources returns the pre-removal state of the language.
|
||||
/datum/language_holder/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL)
|
||||
if(understood && understood_languages[language])
|
||||
/datum/language_holder/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL)
|
||||
if(language_flags & UNDERSTOOD_LANGUAGE)
|
||||
if(source == LANGUAGE_ALL)
|
||||
understood_languages -= language
|
||||
LAZYREMOVE(understood_languages, language)
|
||||
else
|
||||
understood_languages[language] -= source
|
||||
if(!length(understood_languages[language]))
|
||||
understood_languages -= language
|
||||
LAZYREMOVEASSOC(understood_languages, language, source)
|
||||
. = TRUE
|
||||
|
||||
if(spoken && spoken_languages[language])
|
||||
if(language_flags & SPOKEN_LANGUAGE)
|
||||
if(source == LANGUAGE_ALL)
|
||||
spoken_languages -= language
|
||||
LAZYREMOVE(spoken_languages, language)
|
||||
else
|
||||
spoken_languages[language] -= source
|
||||
if(!length(spoken_languages[language]))
|
||||
spoken_languages -= language
|
||||
LAZYREMOVEASSOC(spoken_languages, language, source)
|
||||
. = TRUE
|
||||
|
||||
return .
|
||||
|
||||
/// Removes every language and optionally sets omnitongue false. If a non default source is supplied, only removes that source.
|
||||
/datum/language_holder/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE)
|
||||
for(var/language in GLOB.all_languages)
|
||||
remove_language(language, TRUE, TRUE, source)
|
||||
remove_language(language, ALL, source)
|
||||
if(remove_omnitongue)
|
||||
omnitongue = FALSE
|
||||
return TRUE
|
||||
@@ -113,41 +121,41 @@ Key procs
|
||||
/datum/language_holder/proc/add_blocked_language(languages, source = LANGUAGE_MIND)
|
||||
if(!islist(languages))
|
||||
languages = list(languages)
|
||||
|
||||
for(var/language in languages)
|
||||
if(!blocked_languages[language])
|
||||
blocked_languages[language] = list()
|
||||
blocked_languages[language] |= source
|
||||
LAZYORASSOCLIST(blocked_languages, language, source)
|
||||
return TRUE
|
||||
|
||||
/// Removes a single language or list of languages from the blocked language list.
|
||||
/datum/language_holder/proc/remove_blocked_language(languages, source = LANGUAGE_MIND)
|
||||
if(!islist(languages))
|
||||
languages = list(languages)
|
||||
|
||||
for(var/language in languages)
|
||||
if(blocked_languages[language])
|
||||
if(source == LANGUAGE_ALL)
|
||||
blocked_languages -= language
|
||||
else
|
||||
blocked_languages[language] -= source
|
||||
if(!length(blocked_languages[language]))
|
||||
blocked_languages -= language
|
||||
if(source == LANGUAGE_ALL)
|
||||
LAZYREMOVE(blocked_languages, language)
|
||||
else
|
||||
LAZYREMOVEASSOC(blocked_languages, language, source)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Checks if you have the language. If spoken is true, only checks if you can speak the language.
|
||||
/datum/language_holder/proc/has_language(language, spoken = FALSE)
|
||||
/// Checks if you have the language passed.
|
||||
/datum/language_holder/proc/has_language(language, flag_to_check = UNDERSTOOD_LANGUAGE)
|
||||
if(language in blocked_languages)
|
||||
return FALSE
|
||||
if(spoken)
|
||||
return language in spoken_languages
|
||||
return language in understood_languages
|
||||
|
||||
var/list/langs_to_check = list()
|
||||
if(flag_to_check & SPOKEN_LANGUAGE)
|
||||
langs_to_check |= spoken_languages
|
||||
if(flag_to_check & UNDERSTOOD_LANGUAGE)
|
||||
langs_to_check |= understood_languages
|
||||
|
||||
return language in langs_to_check
|
||||
|
||||
/// Checks if you can speak the language. Tongue limitations should be supplied as an argument.
|
||||
/datum/language_holder/proc/can_speak_language(language)
|
||||
var/atom/movable/ouratom = get_atom()
|
||||
var/tongue = ouratom.could_speak_language(language)
|
||||
if((omnitongue || tongue) && has_language(language, TRUE))
|
||||
return TRUE
|
||||
return FALSE
|
||||
var/can_speak_language_path = omnitongue || owner.could_speak_language(language)
|
||||
return (can_speak_language_path && has_language(language, SPOKEN_LANGUAGE))
|
||||
|
||||
/// Returns selected language if it can be spoken, or decides, sets and returns a new selected language if possible.
|
||||
/datum/language_holder/proc/get_selected_language()
|
||||
@@ -172,59 +180,79 @@ Key procs
|
||||
/datum/language_holder/proc/get_random_spoken_language()
|
||||
return pick(spoken_languages)
|
||||
|
||||
/// Gets a random spoken language, trying to get a non-common language.
|
||||
/datum/language_holder/proc/get_random_spoken_uncommon_language()
|
||||
var/list/languages_minus_common = assoc_to_keys(spoken_languages) - /datum/language/common
|
||||
|
||||
// They have a language other than common
|
||||
if(length(languages_minus_common))
|
||||
return pick(languages_minus_common)
|
||||
|
||||
// They can only speak common, oh well.
|
||||
else
|
||||
return /datum/language/common
|
||||
|
||||
/// Opens a language menu reading from the language holder.
|
||||
/datum/language_holder/proc/open_language_menu(mob/user)
|
||||
if(!language_menu)
|
||||
language_menu = new (src)
|
||||
language_menu.ui_interact(user)
|
||||
|
||||
/// Gets the atom, since we some times need to check if the tongue has limitations.
|
||||
/datum/language_holder/proc/get_atom()
|
||||
if(owner)
|
||||
if(istype(owner, /datum/mind))
|
||||
var/datum/mind/M = owner
|
||||
return M.current
|
||||
return owner
|
||||
return FALSE
|
||||
|
||||
/// Empties out the atom specific languages and updates them according to the supplied atoms language holder.
|
||||
/datum/language_holder/proc/update_atom_languages(atom/movable/thing)
|
||||
var/datum/language_holder/from_atom = thing.get_language_holder(FALSE) //Gets the atoms language holder
|
||||
if(from_atom == src) //This could happen if called on an atom without a mind.
|
||||
return FALSE
|
||||
for(var/language in understood_languages)
|
||||
remove_language(language, TRUE, FALSE, LANGUAGE_ATOM)
|
||||
for(var/language in spoken_languages)
|
||||
remove_language(language, FALSE, TRUE, LANGUAGE_ATOM)
|
||||
for(var/language in blocked_languages)
|
||||
remove_blocked_language(language, LANGUAGE_ATOM)
|
||||
|
||||
copy_languages(from_atom)
|
||||
get_selected_language()
|
||||
return TRUE
|
||||
|
||||
/// Copies all languages from the supplied atom/language holder. Source should be overridden when you
|
||||
/// do not want the language overwritten by later atom updates or want to avoid blocked languages.
|
||||
/datum/language_holder/proc/copy_languages(var/datum/language_holder/from_holder, source_override)
|
||||
if(source_override) //No blocked languages here, for now only used by ling absorb.
|
||||
/datum/language_holder/proc/copy_languages(datum/language_holder/from_holder, source_override)
|
||||
if(source_override) //No blocked languages here, for now only used by ling absorb.
|
||||
for(var/language in from_holder.understood_languages)
|
||||
grant_language(language, TRUE, FALSE, source_override)
|
||||
grant_language(language, UNDERSTOOD_LANGUAGE, source_override)
|
||||
for(var/language in from_holder.spoken_languages)
|
||||
grant_language(language, FALSE, TRUE, source_override)
|
||||
grant_language(language, SPOKEN_LANGUAGE, source_override)
|
||||
else
|
||||
for(var/language in from_holder.understood_languages)
|
||||
grant_language(language, TRUE, FALSE, from_holder.understood_languages[language])
|
||||
grant_language(language, UNDERSTOOD_LANGUAGE, from_holder.understood_languages[language])
|
||||
for(var/language in from_holder.spoken_languages)
|
||||
grant_language(language, FALSE, TRUE, from_holder.spoken_languages[language])
|
||||
grant_language(language, SPOKEN_LANGUAGE, from_holder.spoken_languages[language])
|
||||
for(var/language in from_holder.blocked_languages)
|
||||
add_blocked_language(language, from_holder.blocked_languages[language])
|
||||
return TRUE
|
||||
|
||||
/// Transfers all mind languages to the supplied language holder.
|
||||
/datum/language_holder/proc/transfer_mind_languages(datum/language_holder/to_holder)
|
||||
for(var/language in understood_languages)
|
||||
if(LANGUAGE_MIND in understood_languages[language])
|
||||
remove_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_MIND)
|
||||
to_holder.grant_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_MIND)
|
||||
for(var/language in spoken_languages)
|
||||
if(LANGUAGE_MIND in spoken_languages[language])
|
||||
remove_language(language, SPOKEN_LANGUAGE, LANGUAGE_MIND)
|
||||
to_holder.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_MIND)
|
||||
for(var/language in blocked_languages)
|
||||
if(LANGUAGE_MIND in blocked_languages[language])
|
||||
remove_blocked_language(language, LANGUAGE_MIND)
|
||||
to_holder.add_blocked_language(language, LANGUAGE_MIND)
|
||||
|
||||
//************************************************
|
||||
//* Specific language holders *
|
||||
//* Use atom language sources only. *
|
||||
//************************************************/
|
||||
if(owner)
|
||||
get_selected_language()
|
||||
if(to_holder.owner)
|
||||
to_holder.get_selected_language()
|
||||
|
||||
/// A global assoc list containing prototypes of all language holders
|
||||
/// [Language holder typepath] to [language holder instance]
|
||||
/// Used for easy reference of what can speak what without needing to constantly recreate language holders.
|
||||
GLOBAL_LIST_INIT(prototype_language_holders, init_language_holder_prototypes())
|
||||
|
||||
/// Inits the global list of language holder prototypes.
|
||||
/proc/init_language_holder_prototypes()
|
||||
var/list/prototypes = list()
|
||||
for(var/holdertype in typesof(/datum/language_holder))
|
||||
prototypes[holdertype] = new holdertype()
|
||||
|
||||
return prototypes
|
||||
|
||||
/*
|
||||
* Specific language holders presets
|
||||
*
|
||||
* Prefer to use [LANGUGAE_ATOM]. Atom languages will stick through species changes but not mindswaps.
|
||||
*/
|
||||
|
||||
|
||||
/datum/language_holder/alien
|
||||
@@ -252,6 +280,10 @@ Key procs
|
||||
/datum/language_holder/drone/syndicate
|
||||
blocked_languages = null
|
||||
|
||||
/datum/language_holder/human_basic
|
||||
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
|
||||
spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
|
||||
|
||||
/datum/language_holder/dwarf
|
||||
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
|
||||
/datum/language/dwarf = list(LANGUAGE_ATOM))
|
||||
@@ -353,8 +385,12 @@ Key procs
|
||||
/datum/language/arachnid = list(LANGUAGE_ATOM))
|
||||
|
||||
/datum/language_holder/empty
|
||||
understood_languages = list()
|
||||
spoken_languages = list()
|
||||
understood_languages = null
|
||||
spoken_languages = null
|
||||
|
||||
/datum/language_holder/universal
|
||||
understood_languages = null
|
||||
spoken_languages = null
|
||||
|
||||
/datum/language_holder/universal/New()
|
||||
..()
|
||||
|
||||
@@ -20,109 +20,108 @@
|
||||
/datum/language_menu/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
var/atom/movable/AM = language_holder.get_atom()
|
||||
if(isliving(AM))
|
||||
data["is_living"] = TRUE
|
||||
else
|
||||
data["is_living"] = FALSE
|
||||
|
||||
var/atom/movable/speaker = language_holder.owner
|
||||
data["is_living"] = isliving(speaker)
|
||||
data["languages"] = list()
|
||||
for(var/lang in GLOB.all_languages)
|
||||
var/result = language_holder.has_language(lang) || language_holder.has_language(lang, TRUE)
|
||||
for(var/datum/language/language as anything in GLOB.all_languages)
|
||||
var/result = language_holder.has_language(language) || language_holder.has_language(language, SPOKEN_LANGUAGE)
|
||||
if(!result)
|
||||
continue
|
||||
var/datum/language/language = lang
|
||||
var/list/L = list()
|
||||
var/list/lang_data = list()
|
||||
|
||||
L["name"] = initial(language.name)
|
||||
L["desc"] = initial(language.desc)
|
||||
L["key"] = initial(language.key)
|
||||
L["is_default"] = (language == language_holder.selected_language)
|
||||
if(AM)
|
||||
L["can_speak"] = AM.can_speak_language(language)
|
||||
L["can_understand"] = AM.has_language(language)
|
||||
lang_data["name"] = initial(language.name)
|
||||
lang_data["desc"] = initial(language.desc)
|
||||
lang_data["key"] = initial(language.key)
|
||||
lang_data["is_default"] = (language == language_holder.selected_language)
|
||||
if(speaker)
|
||||
lang_data["can_speak"] = speaker.can_speak_language(language)
|
||||
lang_data["can_understand"] = speaker.has_language(language)
|
||||
|
||||
data["languages"] += list(L)
|
||||
UNTYPED_LIST_ADD(data["languages"], lang_data)
|
||||
|
||||
if(check_rights_for(user.client, R_ADMIN) || isobserver(AM))
|
||||
if(check_rights_for(user.client, R_ADMIN) || isobserver(speaker))
|
||||
data["admin_mode"] = TRUE
|
||||
data["omnitongue"] = language_holder.omnitongue
|
||||
|
||||
data["unknown_languages"] = list()
|
||||
for(var/lang in GLOB.all_languages)
|
||||
if(language_holder.has_language(lang) || language_holder.has_language(lang, TRUE))
|
||||
for(var/datum/language/language as anything in GLOB.all_languages)
|
||||
if(language_holder.has_language(language) || language_holder.has_language(language, SPOKEN_LANGUAGE))
|
||||
continue
|
||||
var/datum/language/language = lang
|
||||
var/list/L = list()
|
||||
var/list/lang_data = list()
|
||||
|
||||
L["name"] = initial(language.name)
|
||||
L["desc"] = initial(language.desc)
|
||||
L["key"] = initial(language.key)
|
||||
lang_data["name"] = initial(language.name)
|
||||
lang_data["desc"] = initial(language.desc)
|
||||
lang_data["key"] = initial(language.key)
|
||||
|
||||
UNTYPED_LIST_ADD(data["unknown_languages"], lang_data)
|
||||
|
||||
data["unknown_languages"] += list(L)
|
||||
return data
|
||||
|
||||
/datum/language_menu/ui_act(action, params)
|
||||
if(..())
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
var/mob/user = usr
|
||||
var/atom/movable/AM = language_holder.get_atom()
|
||||
|
||||
var/atom/movable/speaker = language_holder.owner
|
||||
var/is_admin = check_rights_for(user.client, R_ADMIN)
|
||||
var/language_name = params["language_name"]
|
||||
var/datum/language/language_datum
|
||||
for(var/lang in GLOB.all_languages)
|
||||
var/datum/language/language = lang
|
||||
for(var/datum/language/language as anything in GLOB.all_languages)
|
||||
if(language_name == initial(language.name))
|
||||
language_datum = language
|
||||
var/is_admin = check_rights_for(user.client, R_ADMIN)
|
||||
|
||||
switch(action)
|
||||
if("select_default")
|
||||
if(language_datum && AM.can_speak_language(language_datum))
|
||||
if(language_datum && speaker.can_speak_language(language_datum))
|
||||
language_holder.selected_language = language_datum
|
||||
. = TRUE
|
||||
if("grant_language")
|
||||
if((is_admin || isobserver(AM)) && language_datum)
|
||||
if((is_admin || isobserver(speaker)) && language_datum)
|
||||
var/list/choices = list("Only Spoken", "Only Understood", "Both")
|
||||
var/choice = input(user,"How do you want to add this language?","[language_datum]",null) as null|anything in choices
|
||||
var/spoken = FALSE
|
||||
var/understood = FALSE
|
||||
var/choice = tgui_input_list(user, "How do you want to add this language?", "[language_datum]", choices)
|
||||
if(isnull(choice))
|
||||
return
|
||||
var/adding_flags = NONE
|
||||
switch(choice)
|
||||
if("Only Spoken")
|
||||
spoken = TRUE
|
||||
adding_flags |= SPOKEN_LANGUAGE
|
||||
if("Only Understood")
|
||||
understood = TRUE
|
||||
adding_flags |= UNDERSTOOD_LANGUAGE
|
||||
if("Both")
|
||||
spoken = TRUE
|
||||
understood = TRUE
|
||||
language_holder.grant_language(language_datum, understood, spoken)
|
||||
adding_flags |= ALL
|
||||
|
||||
if(LAZYACCESS(language_holder.blocked_languages, language_datum))
|
||||
choice = tgui_alert(user, "Do you want to lift the blockage that's also preventing the language to be spoken or understood?", "[language_datum]", list("Yes", "No"))
|
||||
if(choice == "Yes")
|
||||
language_holder.remove_blocked_language(language_datum, LANGUAGE_ALL)
|
||||
language_holder.grant_language(language_datum, adding_flags)
|
||||
if(is_admin)
|
||||
message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(AM)].")
|
||||
log_admin("[key_name(user)] granted the language [language_name] to [key_name(AM)].")
|
||||
message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(speaker)].")
|
||||
log_admin("[key_name(user)] granted the language [language_name] to [key_name(speaker)].")
|
||||
. = TRUE
|
||||
if("remove_language")
|
||||
if((is_admin || isobserver(AM)) && language_datum)
|
||||
if((is_admin || isobserver(speaker)) && language_datum)
|
||||
var/list/choices = list("Only Spoken", "Only Understood", "Both")
|
||||
var/choice = input(user,"Which part do you wish to remove?","[language_datum]",null) as null|anything in choices
|
||||
var/spoken = FALSE
|
||||
var/understood = FALSE
|
||||
var/choice = tgui_input_list(user, "Which part do you wish to remove?", "[language_datum]", choices)
|
||||
if(isnull(choice))
|
||||
return
|
||||
var/removing_flags = NONE
|
||||
switch(choice)
|
||||
if("Only Spoken")
|
||||
spoken = TRUE
|
||||
removing_flags |= SPOKEN_LANGUAGE
|
||||
if("Only Understood")
|
||||
understood = TRUE
|
||||
removing_flags |= UNDERSTOOD_LANGUAGE
|
||||
if("Both")
|
||||
spoken = TRUE
|
||||
understood = TRUE
|
||||
language_holder.remove_language(language_datum, understood, spoken)
|
||||
removing_flags |= ALL
|
||||
|
||||
language_holder.remove_language(language_datum, removing_flags)
|
||||
if(is_admin)
|
||||
message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(AM)].")
|
||||
log_admin("[key_name(user)] removed the language [language_name] to [key_name(AM)].")
|
||||
message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(speaker)].")
|
||||
log_admin("[key_name(user)] removed the language [language_name] to [key_name(speaker)].")
|
||||
. = TRUE
|
||||
if("toggle_omnitongue")
|
||||
if(is_admin || isobserver(AM))
|
||||
if(is_admin || isobserver(speaker))
|
||||
language_holder.omnitongue = !language_holder.omnitongue
|
||||
if(is_admin)
|
||||
message_admins("[key_name_admin(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that they know) of [key_name_admin(AM)].")
|
||||
log_admin("[key_name(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that_they know) of [key_name(AM)].")
|
||||
message_admins("[key_name_admin(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that they know) of [key_name_admin(speaker)].")
|
||||
log_admin("[key_name(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that_they know) of [key_name(speaker)].")
|
||||
. = TRUE
|
||||
|
||||
@@ -678,6 +678,7 @@
|
||||
/obj/item/book_of_babel/attack_self(mob/user)
|
||||
to_chat(user, "You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops.")
|
||||
user.grant_all_languages()
|
||||
user.remove_blocked_language(GLOB.all_languages, source = LANGUAGE_ALL)
|
||||
new /obj/effect/decal/cleanable/ash(get_turf(user))
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -89,20 +89,20 @@ INITIALIZE_IMMEDIATE(/mob/dead)
|
||||
if(alert(src, "Jump to server [pick] ([addr])?", "Server Hop", "Yes", "No") != "Yes")
|
||||
return
|
||||
|
||||
var/client/C = client
|
||||
to_chat(C, "<span class='notice'>Sending you to [pick].</span>")
|
||||
new /atom/movable/screen/splash(C)
|
||||
var/client/hopper = client
|
||||
to_chat(hopper, "<span class='notice'>Sending you to [pick].</span>")
|
||||
new /atom/movable/screen/splash(null, src, hopper, FALSE)
|
||||
|
||||
mob_transforming = TRUE
|
||||
sleep(29) //let the animation play
|
||||
sleep(2.9 SECONDS) //let the animation play
|
||||
mob_transforming = FALSE
|
||||
|
||||
if(!C)
|
||||
if(!hopper)
|
||||
return
|
||||
|
||||
winset(src, null, "command=.options") //other wise the user never knows if byond is downloading resources
|
||||
|
||||
C << link("[addr]")
|
||||
hopper << link("[addr]")
|
||||
|
||||
/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister
|
||||
if (registered_z != new_z)
|
||||
|
||||
@@ -41,7 +41,3 @@
|
||||
else
|
||||
postfix = "soon"
|
||||
to_chat(src, "Please set up your character and select \"Ready\". The game will start [postfix].")
|
||||
|
||||
var/datum/hud/new_player/NH = hud_used
|
||||
if(istype(NH))
|
||||
NH.populate_buttons(src)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
/mob/dead/new_player/Initialize(mapload)
|
||||
if(client && SSticker.state == GAME_STATE_STARTUP)
|
||||
var/atom/movable/screen/splash/S = new(client, TRUE, TRUE)
|
||||
var/atom/movable/screen/splash/S = new(null, null, client, TRUE)
|
||||
S.Fade(TRUE)
|
||||
|
||||
if(length(GLOB.newplayer_start))
|
||||
@@ -496,7 +496,7 @@
|
||||
if(job && !job.override_latejoin_spawn(character))
|
||||
SSjob.SendToLateJoin(character)
|
||||
if(!arrivals_docked)
|
||||
var/atom/movable/screen/splash/Spl = new(character.client, TRUE)
|
||||
var/atom/movable/screen/splash/Spl = new(null, character, character.client, TRUE)
|
||||
Spl.Fade(TRUE)
|
||||
character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
|
||||
|
||||
|
||||
@@ -794,10 +794,6 @@
|
||||
else
|
||||
hud_used.healths.icon_state = "health7"
|
||||
|
||||
/mob/living/carbon/proc/update_internals_hud_icon(internal_state = 0)
|
||||
if(hud_used && hud_used.internals)
|
||||
hud_used.internals.icon_state = "internal[internal_state]"
|
||||
|
||||
/mob/living/carbon/update_stat()
|
||||
if(status_flags & GODMODE)
|
||||
return
|
||||
|
||||
@@ -50,22 +50,15 @@
|
||||
//accessory
|
||||
var/accessory_msg
|
||||
if(istype(w_uniform, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = w_uniform
|
||||
if(length(U.attached_accessories) && !(U.flags_inv & HIDEACCESSORY))
|
||||
var/list/weehoo = list()
|
||||
var/dumb_icons = ""
|
||||
for(var/obj/item/clothing/accessory/attached_accessory in U.attached_accessories)
|
||||
if(!(attached_accessory.flags_inv & HIDEACCESSORY))
|
||||
weehoo += "\a [attached_accessory]"
|
||||
dumb_icons = "[dumb_icons][icon2html(attached_accessory, user)]"
|
||||
if(length(weehoo))
|
||||
accessory_msg += " with [dumb_icons]"
|
||||
if(length(U.attached_accessories) >= 2)
|
||||
accessory_msg += jointext(weehoo, ", ", 1, length(weehoo) - 1)
|
||||
accessory_msg += " and [weehoo[length(weehoo)]]"
|
||||
else
|
||||
accessory_msg += weehoo[1]
|
||||
|
||||
var/obj/item/clothing/under/worn_thing = w_uniform
|
||||
if(!CHECK_BITFIELD(worn_thing.flags_inv, HIDEACCESSORY))
|
||||
var/list/accessory_preparation
|
||||
for(var/obj/item/clothing/accessory/attached_accessory as anything in worn_thing.attached_accessories)
|
||||
if(CHECK_BITFIELD(attached_accessory.flags_inv, HIDEACCESSORY))
|
||||
continue
|
||||
LAZYADD(accessory_preparation, "[icon2html(attached_accessory, user)] [attached_accessory]")
|
||||
if(length(accessory_preparation))
|
||||
accessory_msg = " with [english_list(accessory_preparation)]"
|
||||
|
||||
. += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]."
|
||||
//head
|
||||
@@ -88,7 +81,20 @@
|
||||
|
||||
//gloves
|
||||
if(gloves && !(ITEM_SLOT_GLOVES in obscured))
|
||||
. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
|
||||
//accessory
|
||||
var/accessory_msg
|
||||
if(istype(gloves, /obj/item/clothing/gloves))
|
||||
var/obj/item/clothing/gloves/worn_thing = gloves
|
||||
if(!CHECK_BITFIELD(worn_thing.flags_inv, HIDEACCESSORY))
|
||||
var/list/accessory_preparation
|
||||
for(var/obj/item/clothing/accessory/ring/attached_accessory as anything in worn_thing.attached_accessories)
|
||||
if(CHECK_BITFIELD(attached_accessory.flags_inv, HIDEACCESSORY))
|
||||
continue
|
||||
LAZYADD(accessory_preparation, "[icon2html(attached_accessory, user)] [attached_accessory]")
|
||||
if(length(accessory_preparation))
|
||||
accessory_msg = " with [english_list(accessory_preparation)] on [t_his] fingers"
|
||||
|
||||
. += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands[accessory_msg]."
|
||||
else if(length(blood_DNA))
|
||||
var/hand_number = get_num_arms(FALSE)
|
||||
if(hand_number)
|
||||
|
||||
@@ -678,11 +678,11 @@
|
||||
if(hal_screwyhud == SCREWYHUD_HEALTHY)
|
||||
icon_num = 0
|
||||
if(icon_num)
|
||||
hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[BP.body_zone][icon_num]"))
|
||||
hud_used.healthdoll.add_overlay(mutable_appearance(ui_style_modular(hud_used.ui_style, "health"), "[BP.body_zone][icon_num]"))
|
||||
for(var/t in get_missing_limbs()) //Missing limbs
|
||||
hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]6"))
|
||||
hud_used.healthdoll.add_overlay(mutable_appearance(ui_style_modular(hud_used.ui_style, "health"), "[t]6"))
|
||||
for(var/t in get_disabled_limbs()) //Disabled limbs
|
||||
hud_used.healthdoll.add_overlay(mutable_appearance('icons/mob/screen_gen.dmi', "[t]7"))
|
||||
hud_used.healthdoll.add_overlay(mutable_appearance(ui_style_modular(hud_used.ui_style, "health"), "[t]7"))
|
||||
else
|
||||
hud_used.healthdoll.icon_state = "healthdoll_DEAD"
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
can_buckle = TRUE
|
||||
buckle_lying = FALSE
|
||||
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
|
||||
initial_language_holder = /datum/language_holder/empty // We get stuff from our species
|
||||
/// Enable stamina combat
|
||||
combat_flags = COMBAT_FLAGS_STAMINA_COMBAT | COMBAT_FLAG_UNARMED_PARRY
|
||||
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
|
||||
|
||||
@@ -292,12 +292,9 @@ GLOBAL_LIST_INIT(strippable_human_items, create_strippable_list(list(
|
||||
if(carbon_source.internal)
|
||||
carbon_source.internal = null
|
||||
|
||||
// This isn't meant to be FALSE, it correlates to the icon's name.
|
||||
carbon_source.update_internals_hud_icon(0)
|
||||
else if (!QDELETED(item))
|
||||
if(internals || carbon_source.getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
carbon_source.internal = item
|
||||
carbon_source.update_internals_hud_icon(1)
|
||||
|
||||
carbon_source.visible_message(
|
||||
span_danger("[user] [isnull(carbon_source.internal) ? "closes": "opens"] the valve on [source]'s [item.name]."),
|
||||
|
||||
@@ -319,7 +319,6 @@
|
||||
if((C.flags_inv & (HIDEHAIR|HIDEFACIALHAIR)) || (initial(C.flags_inv) & (HIDEHAIR|HIDEFACIALHAIR)))
|
||||
update_hair()
|
||||
if(toggle_off && internal && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
update_internals_hud_icon(0)
|
||||
internal = null
|
||||
if(C.flags_inv & HIDEEYES)
|
||||
update_inv_glasses()
|
||||
|
||||
@@ -90,8 +90,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
var/dangerous_existence //A flag for transformation spells that tells them "hey if you turn a person into one of these without preperation, they'll probably die!"
|
||||
///Affects the speech message, for example: Motharula flutters, "My speech message is flutters!"
|
||||
var/say_mod = "says"
|
||||
///What languages this species can understand and say. Use a [language holder datum][/datum/language_holder] in this var.
|
||||
var/species_language_holder = /datum/language_holder
|
||||
/// What languages this species can understand and say.
|
||||
/// Use a [language holder datum][/datum/language_holder] typepath in this var.
|
||||
/// Should never be null.
|
||||
var/datum/language_holder/species_language_holder = /datum/language_holder/human_basic
|
||||
/**
|
||||
* Visible CURRENT bodyparts that are unique to a species.
|
||||
* DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK
|
||||
@@ -558,6 +560,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
for(var/obj/item/bodypart/B in C.bodyparts)
|
||||
B.change_bodypart_status(BODYPART_HYBRID, FALSE, TRUE) // Makes all Bodyparts 'robotic'.
|
||||
|
||||
// All languages associated with this language holder are added with source [LANGUAGE_SPECIES]
|
||||
// rather than source [LANGUAGE_ATOM], so we can track what to remove if our species changes again
|
||||
var/datum/language_holder/gaining_holder = GLOB.prototype_language_holders[species_language_holder]
|
||||
for(var/language in gaining_holder.understood_languages)
|
||||
C.grant_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_SPECIES)
|
||||
for(var/language in gaining_holder.spoken_languages)
|
||||
C.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_SPECIES)
|
||||
for(var/language in gaining_holder.blocked_languages)
|
||||
C.add_blocked_language(language, LANGUAGE_SPECIES)
|
||||
|
||||
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
|
||||
|
||||
/datum/species/proc/update_species_slowdown(mob/living/carbon/human/H)
|
||||
@@ -1650,15 +1662,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
|
||||
H.Jitter(5)
|
||||
hunger_rate = 3 * HUNGER_FACTOR
|
||||
hunger_rate *= H.physiology.hunger_mod
|
||||
|
||||
// SANDSTORM EDIT
|
||||
if (H.client)
|
||||
H.adjust_nutrition(-hunger_rate)
|
||||
else
|
||||
// Do not allow SSD players to get too hungry.
|
||||
if (H.nutrition >= NUTRITION_LEVEL_FED)
|
||||
H.adjust_nutrition(-hunger_rate)
|
||||
// End of sandstorm edit
|
||||
H.adjust_nutrition(-hunger_rate)
|
||||
|
||||
|
||||
if (H.nutrition > NUTRITION_LEVEL_FULL)
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
|
||||
H.equipOutfit(O, visualsOnly)
|
||||
H.internal = H.get_item_for_held_index(2)
|
||||
H.update_internals_hud_icon(1)
|
||||
return FALSE
|
||||
|
||||
/datum/species/plasmaman/random_name(gender,unique,lastname)
|
||||
|
||||
@@ -34,11 +34,11 @@
|
||||
/mob/living/carbon/human/set_drugginess(amount)
|
||||
..()
|
||||
if(!amount)
|
||||
remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
|
||||
remove_language(/datum/language/beachbum, source = LANGUAGE_HIGH)
|
||||
|
||||
/mob/living/carbon/human/adjust_drugginess(amount)
|
||||
..()
|
||||
if(druggy)
|
||||
grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
|
||||
grant_language(/datum/language/beachbum, source = LANGUAGE_HIGH)
|
||||
else
|
||||
remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
|
||||
remove_language(/datum/language/beachbum, source = LANGUAGE_HIGH)
|
||||
|
||||
@@ -340,12 +340,9 @@
|
||||
if(internal)
|
||||
if(internal.loc != src)
|
||||
internal = null
|
||||
update_internals_hud_icon(0)
|
||||
else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
|
||||
internal = null
|
||||
update_internals_hud_icon(0)
|
||||
else
|
||||
update_internals_hud_icon(1)
|
||||
. = internal.remove_air_volume(volume_needed)
|
||||
if(!.)
|
||||
return FALSE //to differentiate between no internals and active, but empty internals
|
||||
|
||||
@@ -397,7 +397,7 @@
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/monkey/hitby(atom/movable/hitting_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(hitting_atom, /obj/item))
|
||||
if(isitem(hitting_atom))
|
||||
var/obj/item/item_hitby = hitting_atom
|
||||
var/mob/thrown_by = item_hitby.thrownby?.resolve()
|
||||
if(item_hitby.throwforce < src.health && thrown_by && ishuman(thrown_by))
|
||||
|
||||
@@ -107,14 +107,17 @@
|
||||
return FALSE
|
||||
|
||||
/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
|
||||
if(!isitem(AM))
|
||||
// Filled with made up numbers for non-items.
|
||||
if(mob_run_block(AM, 30, "\the [AM.name]", ATTACK_TYPE_THROWN, 0, throwingdatum?.thrower, throwingdatum?.thrower?.zone_selected, list()))
|
||||
if(mob_run_block(AM, 30, "\the [AM.name]", ATTACK_TYPE_THROWN, 0, throwingdatum?.thrower, throwingdatum?.thrower?.zone_selected, list()) & BLOCK_SUCCESS)
|
||||
hitpush = FALSE
|
||||
skipcatch = TRUE
|
||||
blocked = TRUE
|
||||
return TRUE
|
||||
else
|
||||
playsound(loc, 'sound/weapons/genhit.ogg', 50, TRUE, -1) //Item sounds are handled in the item itself
|
||||
log_combat(AM, src, "hit ")
|
||||
return ..()
|
||||
|
||||
var/obj/item/thrown_item = AM
|
||||
@@ -126,18 +129,20 @@
|
||||
skipcatch = TRUE
|
||||
blocked = TRUE
|
||||
|
||||
var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
|
||||
// zone moved up because things need it early while checking it from the thrower is unnecessary
|
||||
var/nosell_hit = SEND_SIGNAL(thrown_item, COMSIG_MOVABLE_IMPACT_ZONE, src, zone, throwingdatum, blocked, FALSE)
|
||||
if(nosell_hit)
|
||||
skipcatch = TRUE
|
||||
hitpush = FALSE
|
||||
|
||||
if(blocked)
|
||||
return TRUE
|
||||
return BLOCK_SUCCESS
|
||||
|
||||
var/mob/thrown_by = thrown_item.thrownby?.resolve()
|
||||
if(thrown_by)
|
||||
log_combat(thrown_by, src, "threw and hit", thrown_item)
|
||||
else
|
||||
log_combat(thrown_item, src, "hit ")
|
||||
if(nosell_hit)
|
||||
return ..()
|
||||
visible_message(span_danger("[src] is hit by [thrown_item]!"), \
|
||||
|
||||
@@ -501,8 +501,3 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
|
||||
// End of Skyrat edits
|
||||
/mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
|
||||
say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced)
|
||||
|
||||
/mob/living/get_language_holder(get_minds = TRUE)
|
||||
if(get_minds && mind)
|
||||
return mind.get_language_holder()
|
||||
. = ..()
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
var/highlighted = FALSE
|
||||
var/mob/camera/aiEye/pic_in_pic/aiEye
|
||||
|
||||
/atom/movable/screen/movable/pic_in_pic/ai/Initialize(mapload)
|
||||
/atom/movable/screen/movable/pic_in_pic/ai/Initialize(mapload, datum/hud/hud_owner)
|
||||
. = ..()
|
||||
aiEye = new /mob/camera/aiEye/pic_in_pic()
|
||||
aiEye.screen = src
|
||||
|
||||
@@ -138,13 +138,11 @@
|
||||
var/datum/action/innate/pai/light/AL = new /datum/action/innate/pai/light
|
||||
var/datum/action/innate/custom_holoform/custom_holoform = new /datum/action/innate/custom_holoform
|
||||
|
||||
var/datum/action/language_menu/ALM = new
|
||||
SW.Grant(src)
|
||||
AS.Grant(src)
|
||||
AC.Grant(src)
|
||||
AR.Grant(src)
|
||||
AL.Grant(src)
|
||||
ALM.Grant(src)
|
||||
custom_holoform.Grant(src)
|
||||
emitter_next_use = world.time + 10 SECONDS
|
||||
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
encryptmod = TRUE
|
||||
if("translator")
|
||||
if(href_list["toggle"]) //This is permanent.
|
||||
grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_SOFTWARE)
|
||||
grant_all_languages(source = LANGUAGE_SOFTWARE)
|
||||
if("doorjack")
|
||||
if(href_list["jack"])
|
||||
if(cable && cable.machine)
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it.
|
||||
robot_modules_background.plane = HUD_PLANE
|
||||
|
||||
inv1 = new /atom/movable/screen/robot/module1()
|
||||
inv2 = new /atom/movable/screen/robot/module2()
|
||||
inv3 = new /atom/movable/screen/robot/module3()
|
||||
inv1 = new /atom/movable/screen/robot/module1(null, src)
|
||||
inv2 = new /atom/movable/screen/robot/module2(null, src)
|
||||
inv3 = new /atom/movable/screen/robot/module3(null, src)
|
||||
|
||||
ident = rand(1, 999)
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/honkbot/hitby(atom/movable/hitting_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(hitting_atom, /obj/item))
|
||||
if(isitem(hitting_atom))
|
||||
playsound(src, honksound, 50, TRUE, -1)
|
||||
var/obj/item/item_hitby = hitting_atom
|
||||
var/mob/thrown_by = item_hitby.thrownby?.resolve()
|
||||
|
||||
@@ -352,7 +352,7 @@
|
||||
|
||||
|
||||
/mob/living/simple_animal/bot/secbot/hitby(atom/movable/hitting_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
if(istype(hitting_atom, /obj/item))
|
||||
if(isitem(hitting_atom))
|
||||
var/obj/item/item_hitby = hitting_atom
|
||||
var/mob/thrown_by = item_hitby.thrownby?.resolve()
|
||||
if(item_hitby.throwforce < src.health && thrown_by && ishuman(thrown_by))
|
||||
|
||||
@@ -44,13 +44,13 @@
|
||||
visible_message("<span class='danger'>[P] has a reduced effect on [src]!</span>")
|
||||
return ..()
|
||||
|
||||
/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)//No floor tiling them to death, wiseguy
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/T = AM
|
||||
/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/hitting_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)//No floor tiling them to death, wiseguy
|
||||
if(isitem(hitting_atom))
|
||||
var/obj/item/item_hitby = hitting_atom
|
||||
if(!stat)
|
||||
Aggro()
|
||||
if(T.throwforce <= 20)
|
||||
visible_message(span_notice("The [T.name] [throw_message] [src.name]!"))
|
||||
if(item_hitby.throwforce <= 20)
|
||||
visible_message(span_notice("\The [item_hitby] [throw_message] [src]!"))
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
@@ -180,11 +180,11 @@
|
||||
if(M.a_intent == INTENT_HARM)
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
/mob/living/simple_animal/hostile/mushroom/hitby(atom/movable/hitting_atom, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
|
||||
..()
|
||||
if(istype(AM, /obj/item))
|
||||
var/obj/item/T = AM
|
||||
if(T.throwforce)
|
||||
if(isitem(hitting_atom))
|
||||
var/obj/item/item_hitby = hitting_atom
|
||||
if(item_hitby.throwforce)
|
||||
Bruise()
|
||||
|
||||
/mob/living/simple_animal/hostile/mushroom/bullet_act(obj/item/projectile/P)
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
dispose_rendering()
|
||||
qdel(hud_used)
|
||||
QDEL_LIST(client_colours)
|
||||
ghostize(can_reenter_corpse = FALSE) //False, since we're deleting it currently
|
||||
ghostize()
|
||||
if(mind?.current == src) //Let's just be safe yeah? This will occasionally be cleared, but not always. Can't do it with ghostize without changing behavior
|
||||
mind.set_current(null)
|
||||
// if(mock_client)
|
||||
@@ -1051,12 +1051,11 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
|
||||
//Do not do parent's actions, as we *usually* do this differently.
|
||||
fully_replace_character_name(real_name, new_name)
|
||||
|
||||
/mob/verb/open_language_menu()
|
||||
/mob/verb/open_language_menu_verb()
|
||||
set name = "Open Language Menu"
|
||||
set category = "IC"
|
||||
|
||||
var/datum/language_holder/H = get_language_holder()
|
||||
H.open_language_menu(usr)
|
||||
get_language_holder().open_language_menu(usr)
|
||||
|
||||
///Adjust the nutrition of a mob
|
||||
/mob/proc/adjust_nutrition(change, max = INFINITY) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
|
||||
|
||||
@@ -308,7 +308,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
|
||||
a_intent = possible_a_intents[current_intent]
|
||||
|
||||
if(hud_used && hud_used.action_intent)
|
||||
hud_used.action_intent.icon_state = "[a_intent]"
|
||||
hud_used.action_intent.update_icon()
|
||||
|
||||
|
||||
/proc/is_blind(A)
|
||||
|
||||
@@ -438,7 +438,6 @@
|
||||
mind.transfer_to(new_xeno)
|
||||
else
|
||||
transfer_ckey(new_xeno)
|
||||
update_atom_languages()
|
||||
|
||||
to_chat(new_xeno, "<B>You are now an alien.</B>")
|
||||
. = new_xeno
|
||||
|
||||
@@ -58,9 +58,9 @@
|
||||
build_path = /obj/item/construction/rcd
|
||||
category = list("hacked", "Construction")
|
||||
|
||||
/datum/design/rpd
|
||||
/datum/design/rpd_autolathe
|
||||
name = "Rapid Pipe Dispenser (RPD)"
|
||||
id = "rpd"
|
||||
id = "rpd_autolathe"
|
||||
build_type = AUTOLATHE | NO_PUBLIC_LATHE
|
||||
materials = list(/datum/material/iron = 75000, /datum/material/glass = 37500)
|
||||
build_path = /obj/item/pipe_dispenser
|
||||
|
||||
@@ -552,7 +552,7 @@
|
||||
if(S.amount < S.max_amount)
|
||||
sheets += S
|
||||
|
||||
if(sheets.len > 0)
|
||||
if(length(sheets))
|
||||
var/obj/item/stack/sheet/S = pick(sheets)
|
||||
S.add(1) // Dare var edit directly again and i'll strangle you.
|
||||
to_chat(owner, "<span class='notice'>[linked_extract] adds a layer of slime to [S], which metamorphosizes into another sheet of material!</span>")
|
||||
@@ -587,6 +587,7 @@
|
||||
/obj/item/hothands
|
||||
name = "burning fingertips"
|
||||
desc = "You shouldn't see this."
|
||||
item_flags = ABSTRACT
|
||||
|
||||
/obj/item/hothands/get_temperature()
|
||||
return 290 //Below what's required to ignite plasma.
|
||||
@@ -595,11 +596,11 @@
|
||||
id = "stabilizeddarkpurple"
|
||||
colour = "dark purple"
|
||||
var/obj/item/hothands/fire
|
||||
examine_text = "<span class='notice'>Their fingertips burn brightly!</span>"
|
||||
examine_text = span_notice("Their fingertips burn brightly!")
|
||||
|
||||
/datum/status_effect/stabilized/darkpurple/on_apply()
|
||||
ADD_TRAIT(owner, TRAIT_RESISTHEATHANDS, "slimestatus")
|
||||
fire = new(owner)
|
||||
fire = new()
|
||||
return ..()
|
||||
|
||||
/datum/status_effect/stabilized/darkpurple/tick()
|
||||
@@ -607,7 +608,7 @@
|
||||
if(item)
|
||||
var/obj/item/reagent_containers/food/snacks/F = item
|
||||
if(istype(F) && F.cooked_type)
|
||||
to_chat(owner, "<span class='warning'>[linked_extract] flares up brightly, and your hands alone are enough cook [F]!</span>")
|
||||
to_chat(owner, span_warning("[linked_extract] flares up brightly, and your hands alone are enough cook [F]!"))
|
||||
F.microwave_act()
|
||||
else
|
||||
item.attackby(fire, owner)
|
||||
@@ -980,7 +981,6 @@
|
||||
familiar.copy_languages(owner, LANGUAGE_MASTER)
|
||||
if(linked.saved_mind)
|
||||
linked.saved_mind.transfer_to(familiar)
|
||||
familiar.update_atom_languages()
|
||||
familiar.ckey = linked.saved_mind.key
|
||||
else
|
||||
if(familiar.mind)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
icon_state = "wasteland"
|
||||
environment_type = "wasteland"
|
||||
baseturfs = /turf/open/floor/plating/asteroid/basalt/wasteland
|
||||
digResult = /obj/item/stack/ore/glass/basalt
|
||||
dig_result = /obj/item/stack/ore/glass/basalt
|
||||
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
|
||||
slowdown = 0.5
|
||||
floor_variance = 30
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
to_chat(user, "<span class='boldannounce'>You start skimming through [src], but you already know dronespeak.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='boldannounce'>You start skimming through [src], and suddenly the drone chittering makes sense.</span>")
|
||||
user.grant_language(/datum/language/drone, TRUE, TRUE)//, LANGUAGE_MIND)
|
||||
user.grant_language(/datum/language/drone, source = LANGUAGE_MIND)
|
||||
return
|
||||
|
||||
if(user.has_language(/datum/language/drone))
|
||||
@@ -180,7 +180,7 @@
|
||||
M.visible_message("<span class='danger'>[user] beats [M] over the head with [src]!</span>", "<span class='userdanger'>[user] beats you over the head with [src]!</span>", "<span class='hear'>You hear smacking.</span>")
|
||||
else
|
||||
M.visible_message("<span class='notice'>[user] teaches [M] by beating [M.p_them()] over the head with [src]!</span>", "<span class='boldnotice'>As [user] hits you with [src], chitters resonate in your mind.</span>", "<span class='hear'>You hear smacking.</span>")
|
||||
M.grant_language(/datum/language/drone, TRUE, TRUE) //, LANGUAGE_MIND)
|
||||
M.grant_language(/datum/language/drone, source = LANGUAGE_MIND)
|
||||
return
|
||||
|
||||
/obj/structure/fluff/oldturret
|
||||
|
||||
@@ -69,6 +69,7 @@ All ShuttleMove procs go here
|
||||
/turf/proc/afterShuttleMove(turf/oldT, rotation)
|
||||
//Dealing with the turf we left behind
|
||||
oldT.TransferComponents(src)
|
||||
SEND_SIGNAL(oldT, COMSIG_TURF_AFTER_SHUTTLE_MOVE, src) //Mostly for decals
|
||||
var/shuttle_boundary = baseturfs.Find(/turf/baseturf_skipover/shuttle)
|
||||
if(shuttle_boundary)
|
||||
oldT.ScrapeAway(baseturfs.len - shuttle_boundary + 1)
|
||||
|
||||
@@ -14,6 +14,6 @@ GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new)
|
||||
if(check_rights_for(user.client, R_ADMIN))
|
||||
. = UI_INTERACTIVE
|
||||
else if(istype(src_object, /datum/language_menu))
|
||||
var/datum/language_menu/LM = src_object
|
||||
if(LM.language_holder.get_atom() == user)
|
||||
var/datum/language_menu/my_languages = src_object
|
||||
if(my_languages.language_holder.owner == user)
|
||||
. = UI_INTERACTIVE
|
||||
|
||||
@@ -44,7 +44,13 @@ Notes:
|
||||
owner = C
|
||||
var/datum/asset/stuff = get_asset_datum(/datum/asset/simple/jquery)
|
||||
stuff.send(owner)
|
||||
owner << browse(file2text('code/modules/tooltip/tooltip.html'), "window=[control]")
|
||||
var/datum/asset/simple/namespaced/fonts/fonts = get_asset_datum(/datum/asset/simple/namespaced/fonts)
|
||||
fonts.send(owner)
|
||||
var/static/file2send
|
||||
if(!file2send)
|
||||
file2send = replacetext(file2text('code/modules/tooltip/tooltip.html'), "THE_FONT_GOES_HERE!!!!!!!!!!!!!!!", SSassets.transport.get_asset_url("fonts.css"))
|
||||
|
||||
owner << browse(file2send, "window=[control]")
|
||||
|
||||
..()
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<title>Tooltip</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<link rel='stylesheet' href='THE_FONT_GOES_HERE!!!!!!!!!!!!!!!' >
|
||||
<style type="text/css">
|
||||
body, html {
|
||||
margin: 0;
|
||||
@@ -104,6 +105,13 @@
|
||||
#1b1d1a 4px
|
||||
); background-size: 100% 4px;}
|
||||
|
||||
.corru .wrap {border: 2px dashed #FFFF00; background-color: #000000;}
|
||||
.corru .content {color: #FFFFFF; border-color: #000000; background-color: #000000; font-family: "Space Mono";}
|
||||
.corru .content h1::before {content: "NOTE::'"; display: inline;}
|
||||
.corru .content h1::after {content: "'"; display: inline;}
|
||||
.corru .content p::before {content: "INHERITED CONTEXT::'"; display: inline;}
|
||||
.corru .content p::after {content: "'"; display: inline;}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
// #include "holidays.dm"
|
||||
// #include "hydroponics_harvest.dm"
|
||||
// #include "keybinding_init.dm"
|
||||
// #include "language_transfer.dm"
|
||||
#include "machine_disassembly.dm"
|
||||
#include "medical_wounds.dm"
|
||||
#include "merge_type.dm"
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
// Dedicated to testing language holders
|
||||
|
||||
/// Simply tests that swapping to a new species gives you the languages of that species and removes the languages of the old species
|
||||
/datum/unit_test/language_species_swap_simple
|
||||
|
||||
/datum/unit_test/language_species_swap_simple/Run()
|
||||
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
|
||||
|
||||
var/datum/language_holder/holder = dummy.get_language_holder()
|
||||
|
||||
var/list/initial_spoken = holder.spoken_languages.Copy()
|
||||
var/list/initial_understood = holder.understood_languages.Copy()
|
||||
|
||||
TEST_ASSERT(length(initial_spoken) == 1, \
|
||||
"Dummy should only speak one language! Instead, it knew the following: [print_language_list(initial_spoken)]")
|
||||
TEST_ASSERT(length(initial_understood) == 1, \
|
||||
"Dummy should only understand one language! Instead, it knew the following: [print_language_list(initial_understood)]")
|
||||
|
||||
dummy.set_species(/datum/species/lizard)
|
||||
|
||||
TEST_ASSERT(length(holder.spoken_languages) == 2, \
|
||||
"Dummy should speak two languages - Common and Draconic! Instead, it knew the following: [print_language_list(holder.spoken_languages)]")
|
||||
|
||||
TEST_ASSERT(length(holder.understood_languages) == 2, \
|
||||
"Dummy should understand two languages - Common and Draconic! Instead, it knew the following: [print_language_list(holder.understood_languages)]")
|
||||
|
||||
dummy.set_species(/datum/species/human)
|
||||
|
||||
TEST_ASSERT(length(initial_spoken & holder.spoken_languages) == 1, \
|
||||
"Dummy did not speak Common after returning to human! Instead, it knew the following: [print_language_list(holder.spoken_languages)]")
|
||||
|
||||
TEST_ASSERT(length(initial_understood & holder.understood_languages) == 1, \
|
||||
"Dummy did not understand Common after returning to human! Instead, it knew the following: [print_language_list(holder.understood_languages)]")
|
||||
|
||||
/// Tests species changes which are more complex are functional (e.g. from a species which speaks common to one which does not)
|
||||
/datum/unit_test/language_species_swap_complex
|
||||
|
||||
/datum/unit_test/language_species_swap_complex/Run()
|
||||
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
|
||||
|
||||
var/datum/language_holder/holder = dummy.get_language_holder()
|
||||
|
||||
dummy.set_species(/datum/species/lizard/silverscale)
|
||||
|
||||
TEST_ASSERT(!dummy.has_language(/datum/language/common, SPOKEN_LANGUAGE), \
|
||||
"Changing a mob's species from one which speaks common to one which does not should remove the language!")
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/common, UNDERSTOOD_LANGUAGE), \
|
||||
"Changing a mob's species from one which understands common another which does should not remove the language!")
|
||||
|
||||
TEST_ASSERT(length(holder.spoken_languages) == 2, \
|
||||
"Dummy should speak two languages - Uncommon and Draconic! Instead, it knew the following: [print_language_list(holder.spoken_languages)]")
|
||||
|
||||
TEST_ASSERT(length(holder.understood_languages) == 3, \
|
||||
"Dummy should understand two languages - Common, Uncommon and Draconic! Instead, it knew the following: [print_language_list(holder.understood_languages)]")
|
||||
|
||||
/// Test that other random languages known are not lost on species change
|
||||
/datum/unit_test/language_species_change_other_known
|
||||
|
||||
/datum/unit_test/language_species_change_other_known/Run()
|
||||
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
|
||||
dummy.grant_language(/datum/language/piratespeak, source = LANGUAGE_MIND)
|
||||
dummy.grant_language(/datum/language/draconic, source = LANGUAGE_ATOM)
|
||||
dummy.set_species(/datum/species/lizard)
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/piratespeak, SPOKEN_LANGUAGE), \
|
||||
"Dummy should still speak Pirate after changing species, as it's a mind language!")
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/piratespeak, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy should still understand Pirate after changing species, as it's a mind language!")
|
||||
|
||||
dummy.set_species(/datum/species/human)
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/draconic, SPOKEN_LANGUAGE), \
|
||||
"Dummy should still speak Draconic after changing species, as it's an atom language!")
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/draconic, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy should still understand Draconic after changing species, as it's an atom language!")
|
||||
|
||||
/// Tests that mind bound languages are not lost swapping into a new mob, but other languages are
|
||||
/datum/unit_test/language_mind_transfer
|
||||
|
||||
/datum/unit_test/language_mind_transfer/Run()
|
||||
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
|
||||
var/mob/living/basic/pet/dog/corgi/transfer_target = allocate(/mob/living/basic/pet/dog/corgi)
|
||||
dummy.mind_initialize()
|
||||
dummy.grant_language(/datum/language/piratespeak, source = LANGUAGE_MIND)
|
||||
dummy.grant_language(/datum/language/draconic, source = LANGUAGE_ATOM)
|
||||
dummy.set_species(/datum/species/lizard/silverscale)
|
||||
|
||||
dummy.mind.transfer_to(transfer_target)
|
||||
|
||||
// transfer_target should speak and understand pirate
|
||||
TEST_ASSERT(!dummy.has_language(/datum/language/piratespeak, SPOKEN_LANGUAGE), \
|
||||
"Dummy should no longer be speaking Pirate after losing their mind!")
|
||||
TEST_ASSERT(transfer_target.has_language(/datum/language/piratespeak, SPOKEN_LANGUAGE), \
|
||||
"Dummy's new mob should be capable of speaking Pirate!")
|
||||
|
||||
TEST_ASSERT(!dummy.has_language(/datum/language/piratespeak, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy should no longer be understanding Pirate after losing their mind!")
|
||||
TEST_ASSERT(transfer_target.has_language(/datum/language/piratespeak, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy's new mob should be capable of understanding Pirate!")
|
||||
|
||||
// transfer_target should NOT speak and understand draconic
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/draconic, SPOKEN_LANGUAGE), \
|
||||
"Dummy should still understand Draconic after losing their mind - it's an atom language!")
|
||||
TEST_ASSERT(!transfer_target.has_language(/datum/language/draconic, SPOKEN_LANGUAGE), \
|
||||
"Dummy's new mob should not understand Draconic - it's an atom language!")
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/draconic, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy should still understand Draconic after losing their mind - it's an atom language!")
|
||||
TEST_ASSERT(!transfer_target.has_language(/datum/language/draconic, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy's new mob should not understand Draconic - it's an atom language!")
|
||||
|
||||
// transfer_target should NOT speak and understand uncommon
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/uncommon, SPOKEN_LANGUAGE), \
|
||||
"Dummy should still understand Uncommon after losing their mind - it's a species language!")
|
||||
TEST_ASSERT(!transfer_target.has_language(/datum/language/uncommon, SPOKEN_LANGUAGE), \
|
||||
"Dummy's new mob should not understand Uncommon - it's a species language!")
|
||||
|
||||
TEST_ASSERT(dummy.has_language(/datum/language/uncommon, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy should still understand Uncommon after losing their mind - it's a species language!")
|
||||
TEST_ASSERT(!transfer_target.has_language(/datum/language/uncommon, UNDERSTOOD_LANGUAGE), \
|
||||
"Dummy's new mob should not understand Uncommon - it's a species language!")
|
||||
|
||||
/// Tests that mind bound languages are not lost when swapping with another person (wiz mindswap)
|
||||
/datum/unit_test/language_mind_swap
|
||||
|
||||
/datum/unit_test/language_mind_swap/Run()
|
||||
var/mob/living/carbon/human/dummy_A = allocate(/mob/living/carbon/human/consistent)
|
||||
var/mob/living/carbon/human/dummy_B = allocate(/mob/living/carbon/human/consistent)
|
||||
|
||||
dummy_A.mind_initialize()
|
||||
dummy_B.mind_initialize()
|
||||
|
||||
var/datum/mind/dummy_A_mind = dummy_A.mind
|
||||
var/datum/mind/dummy_B_mind = dummy_B.mind
|
||||
|
||||
dummy_A.set_species(/datum/species/lizard)
|
||||
dummy_B.grant_language(/datum/language/piratespeak, source = LANGUAGE_MIND)
|
||||
|
||||
dummy_A_mind.transfer_to(dummy_B)
|
||||
dummy_B_mind.transfer_to(dummy_A)
|
||||
|
||||
var/datum/language_holder/holder_A = dummy_A.get_language_holder()
|
||||
var/datum/language_holder/holder_B = dummy_B.get_language_holder()
|
||||
|
||||
// Holder A is a lizard: starts with 2 languages (common, draconic)
|
||||
// Holder B is a human with a mind language: starts with 2 language (common, pirate)
|
||||
// Swap occurs
|
||||
// Holder A is a lizard with 2 languages, but should now also have pirate: 3 languages (common, draconic, pirate)
|
||||
// Holder B is a human with just 1 language left over (common)
|
||||
|
||||
TEST_ASSERT_EQUAL(length(holder_A.spoken_languages), 3, \
|
||||
"Holder A / Dummy A / Dummy B mind should speak Common, Draconic, and Pirate! \
|
||||
Instead, it knew the following: [print_language_list(holder_A.spoken_languages)]")
|
||||
|
||||
TEST_ASSERT_EQUAL(length(holder_A.understood_languages), 3, \
|
||||
"Holder A / Dummy A / Dummy B mind should only understand Common, Draconic, and Pirate! \
|
||||
Instead, it knew the following: [print_language_list(holder_A.understood_languages)]")
|
||||
|
||||
TEST_ASSERT_EQUAL(length(holder_B.spoken_languages), 1, \
|
||||
"Holder B / Dummy B / Dummy A mind should only speak 1 language - Common! \
|
||||
Instead, it knew the following: [print_language_list(holder_B.spoken_languages)]")
|
||||
|
||||
TEST_ASSERT_EQUAL(length(holder_B.understood_languages), 1, \
|
||||
"Holder B / Dummy B / Dummy A mind only understand 1 language - Common! \
|
||||
Instead, it knew the following: [print_language_list(holder_B.understood_languages)]")
|
||||
|
||||
/// Tests that the book of babel, and by extension grant_all_languages, works as intended
|
||||
/datum/unit_test/book_of_babel
|
||||
|
||||
/datum/unit_test/book_of_babel/Run()
|
||||
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
|
||||
var/obj/item/book_of_babel/book = allocate(/obj/item/book_of_babel)
|
||||
var/datum/language_holder/holder = dummy.get_language_holder()
|
||||
var/expected_amount = length(GLOB.all_languages)
|
||||
|
||||
book.attack_self(dummy)
|
||||
TEST_ASSERT_EQUAL(length(holder.spoken_languages), expected_amount, "Book of Babel failed to give all languages out!")
|
||||
dummy.set_species(/datum/species/lizard)
|
||||
TEST_ASSERT_EQUAL(length(holder.spoken_languages), expected_amount, "Changing species after using the Book of Bable should not remove languages!")
|
||||
|
||||
/// Helper proc to print a list of languages in a human readable format
|
||||
/proc/print_language_list(list/languages_to_print)
|
||||
var/list/printed_languages = list()
|
||||
|
||||
for(var/datum/language/language as anything in languages_to_print)
|
||||
printed_languages += initial(language.name)
|
||||
|
||||
return english_list(printed_languages)
|
||||
@@ -1027,13 +1027,13 @@ GLOBAL_LIST_EMPTY(vending_products)
|
||||
/obj/machinery/vending/proc/canLoadItem(obj/item/I, mob/user)
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/vending/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
/obj/machinery/vending/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
||||
. = ..()
|
||||
var/mob/living/L = AM
|
||||
if(tilted || !istype(L) || !prob(20 * (throwingdatum.speed - L.throw_speed))) // hulk throw = +20%, neckgrab throw = +20%
|
||||
var/mob/living/living_mob = hitting_atom
|
||||
if(tilted || !istype(living_mob) || !prob(20 * (throwingdatum.speed - living_mob.throw_speed))) // hulk throw = +20%, neckgrab throw = +20%
|
||||
return
|
||||
|
||||
tilt(L)
|
||||
tilt(living_mob)
|
||||
|
||||
/obj/machinery/vending/attack_tk_grab(mob/user)
|
||||
to_chat(user, span_warning("[src] seems to resist your mental grasp!"))
|
||||
|
||||
@@ -369,10 +369,7 @@
|
||||
|
||||
switch(intent)
|
||||
if("Examine") //Examine a mob inside another mob
|
||||
var/list/results = target.examine(host)
|
||||
if(!results || !results.len)
|
||||
results = list("You were unable to examine that. Tell a developer!")
|
||||
to_chat(user, jointext(results, "<br>"))
|
||||
host.examinate(target)
|
||||
return TRUE
|
||||
|
||||
if("Use Hand")
|
||||
@@ -469,10 +466,7 @@
|
||||
intent = tgui_alert(user, "What would you like to do with [target]?", "Vore Pick", available_options)
|
||||
switch(intent)
|
||||
if("Examine")
|
||||
var/list/results = target.examine(host)
|
||||
if(!results || !results.len)
|
||||
results = list("You were unable to examine that. Tell a developer!")
|
||||
to_chat(user, jointext(results, "<br>"))
|
||||
host.examinate(target)
|
||||
return TRUE
|
||||
|
||||
if("Eject")
|
||||
|
||||
Reference in New Issue
Block a user