diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm index dc2ac19e6579..d5fa67406a53 100644 --- a/code/__DEFINES/language.dm +++ b/code/__DEFINES/language.dm @@ -3,5 +3,21 @@ #define LANGUAGE_HIDE_ICON_IF_UNDERSTOOD 4 #define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8 -#define LANGUAGE_KNOWN "language_known" -#define LANGUAGE_SHADOWED "language_shadowed" +// LANGUAGE SOURCE DEFINES +#define LANGUAGE_ALL "all" // For use in full removal only. +#define LANGUAGE_ATOM "atom" +#define LANGUAGE_MIND "mind" + +#define LANGUAGE_ABSORB "absorb" +#define LANGUAGE_APHASIA "aphasia" +#define LANGUAGE_CULTIST "cultist" +#define LANGUAGE_CURATOR "curator" +#define LANGUAGE_DEVIL "devil" +#define LANGUAGE_GLAND "gland" +#define LANGUAGE_HAT "hat" +#define LANGUAGE_HIGH "high" +#define LANGUAGE_MALF "malf" +#define LANGUAGE_MASTER "master" +#define LANGUAGE_SOFTWARE "software" +#define LANGUAGE_STONER "stoner" +#define LANGUAGE_VOICECHANGE "voicechange" diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm index 186a67d1d089..522bb59e0a33 100644 --- a/code/datums/brain_damage/imaginary_friend.dm +++ b/code/datums/brain_damage/imaginary_friend.dm @@ -89,7 +89,6 @@ trauma = _trauma owner = trauma.owner - copy_known_languages_from(owner, TRUE) setup_friend() diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 2ba242c67e8b..f5a0d1134e8b 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -26,21 +26,15 @@ scan_desc = "extensive damage to the brain's language center" gain_text = "You have trouble forming words in your head..." lose_text = "You suddenly remember how languages work." - var/datum/language_holder/prev_language - var/datum/language_holder/mob_language /datum/brain_trauma/severe/aphasia/on_gain() - mob_language = owner.get_language_holder() - prev_language = mob_language.copy() - mob_language.remove_all_languages() - mob_language.grant_language(/datum/language/aphasia) + owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA) + owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA) ..() /datum/brain_trauma/severe/aphasia/on_lose() - mob_language.remove_language(/datum/language/aphasia) - mob_language.copy_known_languages_from(prev_language) //this will also preserve languages learned during the trauma - QDEL_NULL(prev_language) - mob_language = null + owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA) + owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA) ..() /datum/brain_trauma/severe/blindness diff --git a/code/datums/diseases/advance/symptoms/choking.dm b/code/datums/diseases/advance/symptoms/choking.dm index 559d8f475414..ea20048221a5 100644 --- a/code/datums/diseases/advance/symptoms/choking.dm +++ b/code/datums/diseases/advance/symptoms/choking.dm @@ -28,8 +28,10 @@ Bonus base_message_chance = 15 symptom_delay_min = 10 symptom_delay_max = 30 - threshold_desc = "Stage Speed 8: Causes choking more frequently.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Stage Speed 8" = "Causes choking more frequently.", + "Stealth 4" = "The symptom remains hidden until active." + ) /datum/symptom/choking/Start(datum/disease/advance/A) if(!..()) @@ -99,8 +101,10 @@ Bonus symptom_delay_min = 14 symptom_delay_max = 30 var/paralysis = FALSE - threshold_desc = "Stage Speed 8: Additionally synthesizes pancuronium and sodium thiopental inside the host.
\ - Transmission 8: Doubles the damage caused by the symptom." + threshold_descs = list( + "Stage Speed 8" = "Additionally synthesizes pancuronium and sodium thiopental inside the host.", + "Transmission 8" = "Doubles the damage caused by the symptom." + ) /datum/symptom/asphyxiation/Start(datum/disease/advance/A) diff --git a/code/datums/diseases/advance/symptoms/confusion.dm b/code/datums/diseases/advance/symptoms/confusion.dm index c5daf8b5866b..5c1c18f38a9a 100644 --- a/code/datums/diseases/advance/symptoms/confusion.dm +++ b/code/datums/diseases/advance/symptoms/confusion.dm @@ -29,9 +29,11 @@ Bonus symptom_delay_min = 10 symptom_delay_max = 30 var/brain_damage = FALSE - threshold_desc = "Resistance 6: Causes brain damage over time.
\ - Transmission 6: Increases confusion duration.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Resistance 6" = "Causes brain damage over time.", + "Transmission 6" = "Increases confusion duration and strength.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/confusion/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm index 9d7aed5056a4..e79276ce3eb9 100644 --- a/code/datums/diseases/advance/symptoms/cough.dm +++ b/code/datums/diseases/advance/symptoms/cough.dm @@ -29,11 +29,13 @@ BONUS symptom_delay_min = 2 symptom_delay_max = 15 var/infective = FALSE - threshold_desc = "Resistance 3: Host will drop small items when coughing.
\ - Resistance 10: Occasionally causes coughing fits that stun the host.
\ - Stage Speed 6: Increases cough frequency.
\ - If Airborne: Coughing will infect bystanders.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Resistance 11" = "The host will drop small items when coughing.", + "Resistance 15" = "Occasionally causes coughing fits that stun the host. The extra coughs do not spread the virus.", + "Stage Speed 6" = "Increases cough frequency.", + "Transmission 7" = "Coughing will now infect bystanders up to 2 tiles away.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/cough/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/deafness.dm b/code/datums/diseases/advance/symptoms/deafness.dm index 8031b60e8e15..d09d44b6eb6b 100644 --- a/code/datums/diseases/advance/symptoms/deafness.dm +++ b/code/datums/diseases/advance/symptoms/deafness.dm @@ -28,9 +28,10 @@ Bonus base_message_chance = 100 symptom_delay_min = 25 symptom_delay_max = 80 - threshold_desc = "Resistance 9: Causes permanent deafness, instead of intermittent.
\ - Stealth 4: The symptom remains hidden until active." - + threshold_descs = list( + "Resistance 9" = "Causes permanent deafness, instead of intermittent.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/deafness/Start(datum/disease/advance/A) if(!..()) return diff --git a/code/datums/diseases/advance/symptoms/dizzy.dm b/code/datums/diseases/advance/symptoms/dizzy.dm index b4b06be5acf3..ed5126a84882 100644 --- a/code/datums/diseases/advance/symptoms/dizzy.dm +++ b/code/datums/diseases/advance/symptoms/dizzy.dm @@ -27,8 +27,10 @@ Bonus base_message_chance = 50 symptom_delay_min = 15 symptom_delay_max = 40 - threshold_desc = "Transmission 6: Also causes druggy vision.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Transmission 6" = "Also causes druggy vision.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/dizzy/Start(datum/disease/advance/A) if(!..()) @@ -50,4 +52,4 @@ Bonus to_chat(M, "A wave of dizziness washes over you!") M.Dizzy(5) if(power >= 2) - M.set_drugginess(5) \ No newline at end of file + M.set_drugginess(5) diff --git a/code/datums/diseases/advance/symptoms/fever.dm b/code/datums/diseases/advance/symptoms/fever.dm index a178cba196e0..d2d1c9844d40 100644 --- a/code/datums/diseases/advance/symptoms/fever.dm +++ b/code/datums/diseases/advance/symptoms/fever.dm @@ -28,8 +28,10 @@ Bonus symptom_delay_min = 10 symptom_delay_max = 30 var/unsafe = FALSE //over the heat threshold - threshold_desc = "Resistance 5: Increases fever intensity, fever can overheat and harm the host.
\ - Resistance 10: Further increases fever intensity." + threshold_descs = list( + "Resistance 5" = "Increases fever intensity, fever can overheat and harm the host.", + "Resistance 10" = "Further increases fever intensity.", + ) /datum/symptom/fever/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/fire.dm b/code/datums/diseases/advance/symptoms/fire.dm index b7a482a0f702..c9a637bd659d 100644 --- a/code/datums/diseases/advance/symptoms/fire.dm +++ b/code/datums/diseases/advance/symptoms/fire.dm @@ -29,10 +29,12 @@ Bonus symptom_delay_min = 20 symptom_delay_max = 75 var/infective = FALSE - threshold_desc = "Stage Speed 4: Increases the intensity of the flames.
\ - Stage Speed 8: Further increases flame intensity.
\ - Transmission 8: Host will spread the virus through skin flakes when bursting into flame.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Stage Speed 4" = "Increases the intensity of the flames.", + "Stage Speed 8" = "Further increases flame intensity.", + "Transmission 8" = "Host will spread the virus through skin flakes when bursting into flame.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/fire/Start(datum/disease/advance/A) if(!..()) @@ -112,9 +114,11 @@ Bonus symptom_delay_max = 90 var/chems = FALSE var/explosion_power = 1 - threshold_desc = "Resistance 9: Doubles the intensity of the effect, but reduces its frequency.
\ - Stage Speed 8: Increases explosion radius when the host is wet.
\ - Transmission 8: Additionally synthesizes chlorine trifluoride and napalm inside the host." + threshold_descs = list( + "Resistance 9" = "Doubles the intensity of the immolation effect, but reduces the frequency of all of this symptom's effects.", + "Stage Speed 8" = "Increases explosion radius and explosion damage to the host when the host is wet.", + "Transmission 8" = "Additionally synthesizes chlorine trifluoride and napalm inside the host. More chemicals are synthesized if the resistance 9 threshold has been met." + ) /datum/symptom/alkali/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/flesh_eating.dm b/code/datums/diseases/advance/symptoms/flesh_eating.dm index b8037a594473..08b82bb23b9d 100644 --- a/code/datums/diseases/advance/symptoms/flesh_eating.dm +++ b/code/datums/diseases/advance/symptoms/flesh_eating.dm @@ -26,8 +26,10 @@ Bonus symptom_delay_max = 60 var/bleed = FALSE var/pain = FALSE - threshold_desc = "Resistance 7: Host will bleed profusely during necrosis.
\ - Transmission 8: Causes extreme pain to the host, weakening it." + threshold_descs = list( + "Resistance 7" = "Host will bleed profusely during necrosis.", + "Transmission 8" = "Causes extreme pain to the host, weakening it.", + ) /datum/symptom/flesh_eating/Start(datum/disease/advance/A) if(!..()) @@ -88,8 +90,10 @@ Bonus symptom_delay_max = 6 var/chems = FALSE var/zombie = FALSE - threshold_desc = "Stage Speed 7: Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.
\ - Stealth 5: The symptom remains hidden until active." + threshold_descs = list( + "Stage Speed 7" = "Synthesizes Heparin and Lipolicide inside the host, causing increased bleeding and hunger.", + "Stealth 5" = "The symptom remains hidden until active.", + ) /datum/symptom/flesh_death/Start(datum/disease/advance/A) if(!..()) @@ -119,4 +123,4 @@ Bonus M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2)) if(zombie) M.reagents.add_reagent(/datum/reagent/romerol, 1) - return 1 \ No newline at end of file + return 1 diff --git a/code/datums/diseases/advance/symptoms/genetics.dm b/code/datums/diseases/advance/symptoms/genetics.dm index 49b229e5032d..2f1d6a6530f8 100644 --- a/code/datums/diseases/advance/symptoms/genetics.dm +++ b/code/datums/diseases/advance/symptoms/genetics.dm @@ -30,9 +30,12 @@ Bonus symptom_delay_min = 60 symptom_delay_max = 120 var/no_reset = FALSE - threshold_desc = "Resistance 8: Causes two harmful mutations at once.
\ - Stage Speed 10: Increases mutation frequency.
\ - Stealth 5: The mutations persist even if the virus is cured." + threshold_descs = list( + "Resistance 8" = "The negative and mildly negative mutations caused by the virus are mutadone-proof (but will still be undone when the virus is cured if the resistance 14 threshold is not met).", + "Resistance 14" = "The host's genetic alterations are not undone when the virus is cured.", + "Stage Speed 10" = "The virus activates dormant mutations at a much faster rate.", + "Stealth 5" = "Only activates negative mutations in hosts." + ) /datum/symptom/genetic_mutation/Activate(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/hallucigen.dm b/code/datums/diseases/advance/symptoms/hallucigen.dm index 873d96052459..0f6594b379aa 100644 --- a/code/datums/diseases/advance/symptoms/hallucigen.dm +++ b/code/datums/diseases/advance/symptoms/hallucigen.dm @@ -28,8 +28,10 @@ Bonus symptom_delay_min = 25 symptom_delay_max = 90 var/fake_healthy = FALSE - threshold_desc = "Stage Speed 7: Increases the amount of hallucinations.
\ - Stealth 4: The virus mimics positive symptoms.." + threshold_descs = list( + "Stage Speed 7" = "Increases the amount of hallucinations.", + "Stealth 4" = "The virus mimics positive symptoms.", + ) /datum/symptom/hallucigen/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/headache.dm b/code/datums/diseases/advance/symptoms/headache.dm index 72b03000ed42..5082e8aff315 100644 --- a/code/datums/diseases/advance/symptoms/headache.dm +++ b/code/datums/diseases/advance/symptoms/headache.dm @@ -29,9 +29,11 @@ BONUS base_message_chance = 100 symptom_delay_min = 15 symptom_delay_max = 30 - threshold_desc = "Stage Speed 6: Headaches will cause severe pain, that weakens the host.
\ - Stage Speed 9: Headaches become less frequent but far more intense, preventing any action from the host.
\ - Stealth 4: Reduces headache frequency until later stages." + threshold_descs = list( + "Stage Speed 6" = "Headaches will cause severe pain, that weakens the host.", + "Stage Speed 9" = "Headaches become less frequent but far more intense, preventing any action from the host.", + "Stealth 4" = "Reduces headache frequency until later stages.", + ) /datum/symptom/headache/Start(datum/disease/advance/A) if(!..()) @@ -57,4 +59,4 @@ BONUS M.adjustStaminaLoss(25) if(power >= 3 && A.stage >= 5) to_chat(M, "[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]") - M.Stun(35) \ No newline at end of file + M.Stun(35) diff --git a/code/datums/diseases/advance/symptoms/heal.dm b/code/datums/diseases/advance/symptoms/heal.dm index 2d807c3c589d..d6d81c5fb990 100644 --- a/code/datums/diseases/advance/symptoms/heal.dm +++ b/code/datums/diseases/advance/symptoms/heal.dm @@ -10,8 +10,10 @@ symptom_delay_min = 1 symptom_delay_max = 1 var/passive_message = "" //random message to infected but not actively healing people - threshold_desc = "Stage Speed 6: Doubles healing speed.
\ - Stealth 4: Healing will no longer be visible to onlookers." + threshold_descs = list( + "Stage Speed 6" = "Doubles healing speed.", + "Stealth 4" = "Healing will no longer be visible to onlookers.", + ) /datum/symptom/heal/Start(datum/disease/advance/A) if(!..()) @@ -54,8 +56,10 @@ level = 6 passive_message = "You miss the feeling of starlight on your skin." var/nearspace_penalty = 0.3 - threshold_desc = "Stage Speed 6: Increases healing speed.
\ - Transmission 6: Removes penalty for only being close to space." + threshold_descs = list( + "Stage Speed 6" = "Increases healing speed.", + "Transmission 6" = "Removes penalty for only being close to space.", + ) /datum/symptom/heal/starlight/Start(datum/disease/advance/A) if(!..()) @@ -105,8 +109,10 @@ level = 7 var/food_conversion = FALSE desc = "The virus rapidly breaks down any foreign chemicals in the bloodstream." - threshold_desc = "Resistance 7: Increases chem removal speed.
\ - Stage Speed 6: Consumed chemicals nourish the host." + threshold_descs = list( + "Resistance 7" = "Increases chem removal speed.", + "Stage Speed 6" = "Consumed chemicals nourish the host.", + ) /datum/symptom/heal/chem/Start(datum/disease/advance/A) if(!..()) @@ -138,8 +144,10 @@ var/reduced_hunger = FALSE desc = "The virus causes the host's metabolism to accelerate rapidly, making them process chemicals twice as fast,\ but also causing increased hunger." - threshold_desc = "Stealth 3: Reduces hunger rate.
\ - Stage Speed 10: Chemical metabolization is tripled instead of doubled." + threshold_descs = list( + "Stealth 3" = "Reduces hunger rate.", + "Stage Speed 10" = "Chemical metabolization is tripled instead of doubled.", + ) /datum/symptom/heal/metabolism/Start(datum/disease/advance/A) if(!..()) @@ -171,7 +179,9 @@ transmittable = -1 level = 6 passive_message = "You feel tingling on your skin as light passes over it." - threshold_desc = "Stage Speed 8: Doubles healing speed." + threshold_descs = list( + "Stage Speed 8" = "Doubles healing speed.", + ) /datum/symptom/heal/darkness/Start(datum/disease/advance/A) if(!..()) @@ -220,8 +230,11 @@ passive_message = "The pain from your wounds makes you feel oddly sleepy..." var/deathgasp = FALSE var/active_coma = FALSE //to prevent multiple coma procs - threshold_desc = "Stealth 2: Host appears to die when falling into a coma.
\ - Stage Speed 7: Increases healing speed." + threshold_descs = list( + "Stealth 2" = "Host appears to die when falling into a coma.", + "Resistance 4" = "The virus also stabilizes the host while they are in critical condition.", + "Stage Speed 7" = "Increases healing speed.", + ) /datum/symptom/heal/coma/Start(datum/disease/advance/A) if(!..()) @@ -294,8 +307,10 @@ level = 6 passive_message = "Your skin feels oddly dry..." var/absorption_coeff = 1 - threshold_desc = "Resistance 5: Water is consumed at a much slower rate.
\ - Stage Speed 7: Increases healing speed." + threshold_descs = list( + "Resistance 5" = "Water is consumed at a much slower rate.", + "Stage Speed 7" = "Increases healing speed.", + ) /datum/symptom/heal/water/Start(datum/disease/advance/A) if(!..()) @@ -350,8 +365,10 @@ level = 8 passive_message = "You feel an odd attraction to plasma." var/temp_rate = 1 - threshold_desc = "Transmission 6: Increases temperature adjustment rate.
\ - Stage Speed 7: Increases healing speed." + threshold_descs = list( + "Transmission 6" = "Increases temperature adjustment rate.", + "Stage Speed 7" = "Increases healing speed.", + ) /datum/symptom/heal/plasma/Start(datum/disease/advance/A) if(!..()) @@ -417,8 +434,10 @@ symptom_delay_max = 1 passive_message = "Your skin glows faintly for a moment." var/cellular_damage = FALSE - threshold_desc = "Transmission 6: Additionally heals cellular damage.
\ - Resistance 7: Increases healing speed." + threshold_descs = list( + "Transmission 6" = "Additionally heals cellular damage.", + "Resistance 7" = "Increases healing speed.", + ) /datum/symptom/heal/radiation/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/itching.dm b/code/datums/diseases/advance/symptoms/itching.dm index b0812e023533..174dafa18fe6 100644 --- a/code/datums/diseases/advance/symptoms/itching.dm +++ b/code/datums/diseases/advance/symptoms/itching.dm @@ -29,8 +29,10 @@ BONUS symptom_delay_min = 5 symptom_delay_max = 25 var/scratch = FALSE - threshold_desc = "Transmission 6: Increases frequency of itching.
\ - Stage Speed 7: The host will scrath itself when itching, causing superficial damage." + threshold_descs = list( + "Transmission 6" = "Increases frequency of itching.", + "Stage Speed 7" = "The host will scrath itself when itching, causing superficial damage.", + ) /datum/symptom/itching/Start(datum/disease/advance/A) if(!..()) @@ -51,4 +53,4 @@ BONUS var/can_scratch = scratch && !M.incapacitated() && get_location_accessible(M, picked_bodypart) M.visible_message("[can_scratch ? "[M] scratches [M.p_their()] [bodypart.name]." : ""]", "Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]") if(can_scratch) - bodypart.receive_damage(0.5) \ No newline at end of file + bodypart.receive_damage(0.5) diff --git a/code/datums/diseases/advance/symptoms/nanites.dm b/code/datums/diseases/advance/symptoms/nanites.dm index e2d1229eac7a..f15616edb153 100644 --- a/code/datums/diseases/advance/symptoms/nanites.dm +++ b/code/datums/diseases/advance/symptoms/nanites.dm @@ -10,8 +10,10 @@ symptom_delay_min = 1 symptom_delay_max = 1 var/reverse_boost = FALSE - threshold_desc = "Transmission 5: Increases the virus' growth rate while nanites are present.
\ - Stage Speed 7: Increases the replication boost." + threshold_descs = list( + "Transmission 5" = "Increases the virus' growth rate while nanites are present.", + "Stage Speed 7" = "Increases the replication boost." + ) /datum/symptom/nano_boost/Start(datum/disease/advance/A) if(!..()) @@ -42,8 +44,10 @@ symptom_delay_min = 1 symptom_delay_max = 1 var/reverse_boost = FALSE - threshold_desc = "Stage Speed 5: Increases the virus' growth rate while nanites are present.
\ - Resistance 7: Severely increases the rate at which the nanites are destroyed." + threshold_descs = list( + "Stage Speed 5" = "Increases the virus' growth rate while nanites are present.", + "Resistance 7" = "Severely increases the rate at which the nanites are destroyed." + ) /datum/symptom/nano_destroy/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/narcolepsy.dm b/code/datums/diseases/advance/symptoms/narcolepsy.dm index 24ba024aa6fa..356d5bc1e47d 100644 --- a/code/datums/diseases/advance/symptoms/narcolepsy.dm +++ b/code/datums/diseases/advance/symptoms/narcolepsy.dm @@ -26,8 +26,10 @@ Bonus var/sleep_level = 0 var/sleepy_ticks = 0 var/stamina = FALSE - threshold_desc = "Transmission 7: Also relaxes the muscles, weakening and slowing the host.
\ - Resistance 10: Causes narcolepsy more often, increasing the chance of the host falling asleep." + threshold_descs = list( + "Transmission 7" = "Also relaxes the muscles, weakening and slowing the host.", + "Resistance 10" = "Causes narcolepsy more often, increasing the chance of the host falling asleep", + ) /datum/symptom/narcolepsy/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/oxygen.dm b/code/datums/diseases/advance/symptoms/oxygen.dm index 5b6d53c7195f..fd8efaee7717 100644 --- a/code/datums/diseases/advance/symptoms/oxygen.dm +++ b/code/datums/diseases/advance/symptoms/oxygen.dm @@ -28,7 +28,9 @@ Bonus symptom_delay_min = 1 symptom_delay_max = 1 var/regenerate_blood = FALSE - threshold_desc = "Resistance 8:Additionally regenerates lost blood.
" + threshold_descs = list( + "Resistance 8" = "Additionally regenerates lost blood." + ) /datum/symptom/oxygen/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/radiation.dm b/code/datums/diseases/advance/symptoms/radiation.dm index 2cc2af78a01a..71614e8454db 100644 --- a/code/datums/diseases/advance/symptoms/radiation.dm +++ b/code/datums/diseases/advance/symptoms/radiation.dm @@ -11,8 +11,10 @@ symptom_delay_max = 30 var/fastrads = FALSE var/radothers = FALSE - threshold_desc = "Transmission 12: Makes the host irradiate others around them as well.
\ - Speed 8: Host takes radiation damage faster." + threshold_descs = list( + "Transmission 12" = "Makes the host irradiate others around them as well.", + "Speed 8" = "Host takes radiation damage faster." + ) /datum/symptom/radiation/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index 58b64ae4903c..4c1e1d4543af 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -11,9 +11,11 @@ var/purge_alcohol = FALSE var/trauma_heal_mild = FALSE var/trauma_heal_severe = FALSE - threshold_desc = "Resistance 6: Heals minor brain traumas.
\ - Resistance 9: Heals severe brain traumas.
\ - Transmission 8: Purges alcohol in the bloodstream." + threshold_descs = list( + "Resistance 6" = "Heals minor brain traumas.", + "Resistance 9" = "Heals severe brain traumas.", + "Transmission 8" = "Purges alcohol in the bloodstream.", + ) /datum/symptom/mind_restoration/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/shivering.dm b/code/datums/diseases/advance/symptoms/shivering.dm index 741e2a1e16c7..ab9aa0e9e57b 100644 --- a/code/datums/diseases/advance/symptoms/shivering.dm +++ b/code/datums/diseases/advance/symptoms/shivering.dm @@ -27,8 +27,10 @@ Bonus symptom_delay_min = 10 symptom_delay_max = 30 var/unsafe = FALSE //over the cold threshold - threshold_desc = "Stage Speed 5: Increases cooling speed; the host can fall below safe temperature levels.
\ - Stage Speed 10: Further increases cooling speed." + threshold_descs = list( + "Stage Speed 5" = "Increases cooling speed,; the host can fall below safe temperature levels.", + "Stage Speed 10" = "Further increases cooling speed." + ) /datum/symptom/fever/Start(datum/disease/advance/A) if(!..()) @@ -56,4 +58,4 @@ Bonus if(unsafe) limit = 0 M.adjust_bodytemperature(-get_cold * A.stage, limit) - return 1 \ No newline at end of file + return 1 diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm index b4108cd27b46..274a81b57c15 100644 --- a/code/datums/diseases/advance/symptoms/sneeze.dm +++ b/code/datums/diseases/advance/symptoms/sneeze.dm @@ -27,8 +27,10 @@ Bonus severity = 1 symptom_delay_min = 5 symptom_delay_max = 35 - threshold_desc = "Transmission 9: Increases sneezing range, spreading the virus over a larger area.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Transmission 9" = "Increases sneezing range, spreading the virus over 6 meter cone instead of over a 4 meter cone.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/sneeze/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/symptoms.dm b/code/datums/diseases/advance/symptoms/symptoms.dm index 92f6f1d9ba2d..ed93d05fd92e 100644 --- a/code/datums/diseases/advance/symptoms/symptoms.dm +++ b/code/datums/diseases/advance/symptoms/symptoms.dm @@ -4,7 +4,7 @@ // Buffs/Debuffs the symptom has to the overall engineered disease. var/name = "" var/desc = "If you see this something went very wrong." //Basic symptom description - var/threshold_desc = "" //Description of threshold effects + var/threshold_descs = list() //Descriptions of threshold effects var/stealth = 0 var/resistance = 0 var/stage_speed = 0 diff --git a/code/datums/diseases/advance/symptoms/vision.dm b/code/datums/diseases/advance/symptoms/vision.dm index b4759117d3f2..87a784e7ded9 100644 --- a/code/datums/diseases/advance/symptoms/vision.dm +++ b/code/datums/diseases/advance/symptoms/vision.dm @@ -29,8 +29,10 @@ Bonus symptom_delay_min = 25 symptom_delay_max = 80 var/remove_eyes = FALSE - threshold_desc = "Resistance 12: Weakens extraocular muscles, eventually leading to complete detachment of the eyes.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Resistance 12" = "Weakens extraocular muscles, eventually leading to complete detachment of the eyes.", + "Stealth 4" = "The symptom remains hidden until active.", + ) /datum/symptom/visionloss/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm index 4403bb07d0b7..20c0a6df40d0 100644 --- a/code/datums/diseases/advance/symptoms/voice_change.dm +++ b/code/datums/diseases/advance/symptoms/voice_change.dm @@ -30,11 +30,11 @@ Bonus symptom_delay_max = 120 var/scramble_language = FALSE var/datum/language/current_language - var/datum/language_holder/original_language - var/datum/language_holder/mob_language - threshold_desc = "Transmission 14: The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.
\ - Stage Speed 7: Changes voice more often.
\ - Stealth 3: The symptom remains hidden until active." + threshold_descs = list( + "Transmission 14" = "The host's language center of the brain is damaged, leading to complete inability to speak or understand any language.", + "Stage Speed 7" = "Changes voice more often.", + "Stealth 3" = "The symptom remains hidden until active." + ) /datum/symptom/voice_change/Start(datum/disease/advance/A) if(!..()) @@ -47,9 +47,6 @@ Bonus symptom_delay_max = 85 if(A.properties["transmittable"] >= 14) //random language scramble_language = TRUE - var/mob/living/M = A.affected_mob - mob_language = M.get_language_holder() - original_language = mob_language.copy() /datum/symptom/voice_change/Activate(datum/disease/advance/A) if(!..()) @@ -63,12 +60,10 @@ Bonus if(ishuman(M)) var/mob/living/carbon/human/H = M H.SetSpecialVoice(H.dna.species.random_name(H.gender)) - if(scramble_language) - H.remove_language(current_language) + if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure. current_language = pick(subtypesof(/datum/language) - /datum/language/common) - H.grant_language(current_language) - mob_language = H.get_language_holder() - mob_language.only_speaks_language = current_language + H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE) + H.grant_language(current_language, TRUE, TRUE, LANGUAGE_VOICECHANGE) /datum/symptom/voice_change/End(datum/disease/advance/A) ..() @@ -76,10 +71,5 @@ Bonus var/mob/living/carbon/human/H = A.affected_mob H.UnsetSpecialVoice() if(scramble_language) - var/mob/living/M = A.affected_mob - M.copy_known_languages_from(original_language, TRUE) - mob_language = M.get_language_holder() - mob_language.only_speaks_language = null - M.selected_default_language = original_language - current_language = null - QDEL_NULL(original_language) + A.affected_mob.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_VOICECHANGE) + A.affected_mob.remove_all_languages(LANGUAGE_VOICECHANGE) // In case someone managed to get more than one anyway. diff --git a/code/datums/diseases/advance/symptoms/vomit.dm b/code/datums/diseases/advance/symptoms/vomit.dm index f53638bc1294..d823df53c29c 100644 --- a/code/datums/diseases/advance/symptoms/vomit.dm +++ b/code/datums/diseases/advance/symptoms/vomit.dm @@ -34,9 +34,11 @@ Bonus symptom_delay_max = 80 var/vomit_blood = FALSE var/proj_vomit = 0 - threshold_desc = "Resistance 7: Host will vomit blood, causing internal damage.
\ - Transmission 7: Host will projectile vomit, increasing vomiting range.
\ - Stealth 4: The symptom remains hidden until active." + threshold_descs = list( + "Resistance 7" = "Host will vomit blood, causing internal damage.", + "Transmission 7" = "Host will projectile vomit, increasing vomiting range.", + "Stealth 4" = "The symptom remains hidden until active." + ) /datum/symptom/vomit/Start(datum/disease/advance/A) if(!..()) diff --git a/code/datums/diseases/advance/symptoms/weight.dm b/code/datums/diseases/advance/symptoms/weight.dm index 13472a5308dc..4f42a597e2f6 100644 --- a/code/datums/diseases/advance/symptoms/weight.dm +++ b/code/datums/diseases/advance/symptoms/weight.dm @@ -29,7 +29,9 @@ Bonus base_message_chance = 100 symptom_delay_min = 15 symptom_delay_max = 45 - threshold_desc = "Stealth 4: The symptom is less noticeable." + threshold_descs = list( + "Stealth 4" = "The symptom is less noticeable." + ) /datum/symptom/weight_loss/Start(datum/disease/advance/A) if(!..()) @@ -48,4 +50,4 @@ Bonus else to_chat(M, "[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]") M.overeatduration = max(M.overeatduration - 100, 0) - M.adjust_nutrition(-100) \ No newline at end of file + M.adjust_nutrition(-100) diff --git a/code/datums/dna.dm b/code/datums/dna.dm index 17c9ed64fa56..4245e120ecd5 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -305,6 +305,11 @@ var/datum/species/old_species = dna.species dna.species = new_race dna.species.on_species_gain(src, old_species, pref_load) + if(ishuman(src)) + qdel(language_holder) + var/species_holder = initial(mrace.species_language_holder) + language_holder = new species_holder(src) + update_atom_languages() /mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE) ..() diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 192fc3c5b7c4..6273d46f04c7 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -81,8 +81,7 @@ /datum/mind/proc/get_language_holder() if(!language_holder) - var/datum/language_holder/L = current.get_language_holder(shadow=FALSE) - language_holder = L.copy(src) + language_holder = new (src) return language_holder @@ -103,9 +102,6 @@ current.mind = null UnregisterSignal(current, COMSIG_MOB_DEATH) SStgui.on_transfer(current, new_character) - if(!language_holder) - var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE) - language_holder = mob_holder.copy(src) if(key) if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours @@ -139,6 +135,7 @@ RegisterSignal(new_character, COMSIG_MOB_DEATH, .proc/set_death_time) if(active || force_key_move) new_character.key = key //now transfer the key to link the client to our new body + current.update_atom_languages() /datum/mind/proc/set_death_time() last_death = world.time diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm index 398116456f4b..b35b2f97d9b7 100644 --- a/code/datums/mutations/speech.dm +++ b/code/datums/mutations/speech.dm @@ -266,10 +266,10 @@ /datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner) ..() - owner.grant_language(/datum/language/beachbum) - owner.remove_language(/datum/language/common) + owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER) + owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER) /datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner) ..() - owner.grant_language(/datum/language/common) - owner.remove_language(/datum/language/beachbum) \ No newline at end of file + owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER) + owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER) diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 709ca14092de..0dc8fbb90a21 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -574,5 +574,5 @@ /datum/quirk/sheltered/on_spawn() var/mob/living/carbon/human/H = quirk_holder H.remove_language(/datum/language/common) - if(!H.can_speak_in_language(/datum/language/draconic) && !H.can_speak_in_language(/datum/language/machine)) + if(!H.can_speak_language(/datum/language/draconic) && !H.can_speak_language(/datum/language/machine)) H.grant_language(/datum/language/japanese) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index d5a198e12c9d..504342b4014a 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -788,88 +788,92 @@ animate(src, pixel_y = initial(pixel_y), time = 10) setMovetype(movement_type & ~FLOATING) -/* Language procs */ -/atom/movable/proc/get_language_holder(shadow=TRUE) - if(language_holder) - return language_holder - else - language_holder = new initial_language_holder(src) - return language_holder +/* Language procs +* Unless you are doing something very specific, these are the ones you want to use. +*/ -/atom/movable/proc/grant_language(datum/language/dt, body = FALSE) - var/datum/language_holder/H = get_language_holder(!body) - H.grant_language(dt, body) +/// Gets or creates the relevant language holder. For mindless atoms, gets the local one. For atom with mind, gets the mind one. +/atom/movable/proc/get_language_holder(get_minds = TRUE) + if(!language_holder) + language_holder = new initial_language_holder(src) + return language_holder + +/// Grants the supplied language and sets omnitongue true. +/atom/movable/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ATOM) + var/datum/language_holder/LH = get_language_holder() + return LH.grant_language(language, understood, spoken, source) + +/// Grants every language. +/atom/movable/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND) + var/datum/language_holder/LH = get_language_holder() + return LH.grant_all_languages(understood, spoken, grant_omnitongue, source) + +/// Removes a single language. +/atom/movable/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL) + var/datum/language_holder/LH = get_language_holder() + return LH.remove_language(language, understood, spoken, source) + +/// Removes every language and sets omnitongue false. +/atom/movable/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE) + var/datum/language_holder/LH = get_language_holder() + return LH.remove_all_languages(source, remove_omnitongue) + +/// Adds a language to the blocked language list. Use this over remove_language in cases where you will give languages back later. +/atom/movable/proc/add_blocked_language(language, source = LANGUAGE_ATOM) + var/datum/language_holder/LH = get_language_holder() + return LH.add_blocked_language(language, source) + +/// Removes a language from the blocked language list. +/atom/movable/proc/remove_blocked_language(language, source = LANGUAGE_ATOM) + var/datum/language_holder/LH = get_language_holder() + return LH.remove_blocked_language(language, source) + +/// Checks if atom has the language. If spoken is true, only checks if atom can speak the language. +/atom/movable/proc/has_language(language, spoken = FALSE) + var/datum/language_holder/LH = get_language_holder() + return LH.has_language(language, spoken) + +/// Checks if atom can speak the language. +/atom/movable/proc/can_speak_language(language) + var/datum/language_holder/LH = get_language_holder() + return LH.can_speak_language(language) + +/// Returns the result of tongue specific limitations on spoken languages. +/atom/movable/proc/could_speak_language(language) + return TRUE -/atom/movable/proc/grant_all_languages(omnitongue=FALSE) - var/datum/language_holder/H = get_language_holder() - H.grant_all_languages(omnitongue) +/// Returns selected language, if it can be spoken, or finds, sets and returns a new selected language if possible. +/atom/movable/proc/get_selected_language() + var/datum/language_holder/LH = get_language_holder() + return LH.get_selected_language() +/// Gets a random understood language, useful for hallucinations and such. /atom/movable/proc/get_random_understood_language() - var/datum/language_holder/H = get_language_holder() - . = H.get_random_understood_language() - -/atom/movable/proc/remove_language(datum/language/dt, body = FALSE) - var/datum/language_holder/H = get_language_holder(!body) - H.remove_language(dt, body) - -/atom/movable/proc/remove_all_languages() - var/datum/language_holder/H = get_language_holder() - H.remove_all_languages() - -/atom/movable/proc/has_language(datum/language/dt) - var/datum/language_holder/H = get_language_holder() - . = H.has_language(dt) - -/atom/movable/proc/copy_known_languages_from(thing, replace=FALSE) - var/datum/language_holder/H = get_language_holder() - . = H.copy_known_languages_from(thing, replace) - -// Whether an AM can speak in a language or not, independent of whether -// it KNOWS the language -/atom/movable/proc/could_speak_in_language(datum/language/dt) - . = TRUE - -/atom/movable/proc/can_speak_in_language(datum/language/dt) - var/datum/language_holder/H = get_language_holder() - - if(!H.has_language(dt)) - return FALSE - else if(H.omnitongue) - return TRUE - else if(could_speak_in_language(dt) && (!H.only_speaks_language || H.only_speaks_language == dt)) - return TRUE - else - return FALSE - -/atom/movable/proc/get_default_language() - // if no language is specified, and we want to say() something, which - // language do we use? - var/datum/language_holder/H = get_language_holder() - - if(H.selected_default_language) - if(can_speak_in_language(H.selected_default_language)) - return H.selected_default_language - else - H.selected_default_language = null - - - var/datum/language/chosen_langtype - var/highest_priority - - for(var/lt in H.languages) - var/datum/language/langtype = lt - if(!can_speak_in_language(langtype)) - continue - - var/pri = initial(langtype.default_priority) - if(!highest_priority || (pri > highest_priority)) - chosen_langtype = langtype - highest_priority = pri - - H.selected_default_language = . - . = chosen_langtype + var/datum/language_holder/LH = get_language_holder() + return LH.get_random_understood_language() + +/// Gets a random spoken language, useful for forced speech and such. +/atom/movable/proc/get_random_spoken_language() + var/datum/language_holder/LH = get_language_holder() + return LH.get_random_spoken_language() + +/// Copies all languages into 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. +/atom/movable/proc/copy_languages(from_holder, source_override) + if(isatom(from_holder)) + var/atom/movable/thing = from_holder + from_holder = thing.get_language_holder() + var/datum/language_holder/LH = get_language_holder() + return LH.copy_languages(from_holder, source_override) + +/// Empties out the atom specific languages and updates them according to the current atoms language holder. +/// As a side effect, it also creates missing language holders in the process. +/atom/movable/proc/update_atom_languages() + var/datum/language_holder/LH = get_language_holder() + return LH.update_atom_languages(src) /* End language procs */ + /atom/movable/proc/ConveyorMove(movedir) set waitfor = FALSE if(!anchored && has_gravity()) diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm index 841c0648a07b..9482d903a476 100644 --- a/code/game/machinery/bank_machine.dm +++ b/code/game/machinery/bank_machine.dm @@ -38,7 +38,6 @@ return return ..() - /obj/machinery/computer/bank_machine/process() ..() if(siphoning) @@ -60,34 +59,39 @@ radio.talk_into(src, message, radio_channel) next_warning = world.time + minimum_time_between_warnings -/obj/machinery/computer/bank_machine/ui_interact(mob/user) - . = ..() +/obj/machinery/computer/bank_machine/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \ + datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "bank_machine", name, 320, 165, master_ui, state) + ui.open() - var/dat = "[station_name()] secure vault. Authorized personnel only.
" +/obj/machinery/computer/bank_machine/ui_data(mob/user) + var/list/data = list() var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) + if(D) - dat += "Current Balance: $[D.account_balance]
" - if(!siphoning) - dat += "Siphon Credits
" + data["current_balance"] = D.account_balance else - dat += "Halt Credit Siphon
" + data["current_balance"] = 0 + data["siphoning"] = siphoning + data["station_name"] = station_name() - dat += "Close" + return data - var/datum/browser/popup = new(user, "computer", "Bank Vault", 300, 200) - popup.set_content("
[dat]
") - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() - -/obj/machinery/computer/bank_machine/Topic(href, href_list) +/obj/machinery/computer/bank_machine/ui_act(action, params) if(..()) return - if(href_list["siphon"]) - say("Siphon of station credits has begun!") - siphoning = TRUE - if(href_list["halt"]) - say("Station credit withdrawal halted.") - end_syphon() + + switch(action) + if("siphon") + say("Siphon of station credits has begun!") + siphoning = TRUE + . = TRUE + if("halt") + say("Station credit withdrawal halted.") + end_syphon() + . = TRUE /obj/machinery/computer/bank_machine/proc/end_syphon() siphoning = FALSE diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm index d4b5aaa44172..60d5fd22d9b4 100644 --- a/code/game/machinery/gulag_item_reclaimer.dm +++ b/code/game/machinery/gulag_item_reclaimer.dm @@ -80,29 +80,18 @@ return data -/obj/machinery/gulag_item_reclaimer/ui_act(action, list/params) - switch(action) - if("handle_id") - if(inserted_id) - usr.put_in_hands(inserted_id) - inserted_id = null - else - var/obj/item/I = usr.is_holding_item_of_type(/obj/item/card/id/prisoner) - if(I) - if(!usr.transferItemToLoc(I, src)) - return - inserted_id = I +/obj/machinery/gulag_item_reclaimer/ui_act(action, params) + if(..()) + return + switch(action) if("release_items") - var/mob/M = locate(params["mobref"]) in stored_items - if(M == usr || allowed(usr)) - if(inserted_id) - var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_SEC) - if(D) - D.adjust_money(inserted_id.points * 1.5) - drop_items(M) - else - to_chat(usr, "Access denied.") + var/mob/living/carbon/human/H = locate(params["mobref"]) in stored_items + if(H != usr && !allowed(usr)) + to_chat(usr, "Access denied.") + return + drop_items(H) + . = TRUE /obj/machinery/gulag_item_reclaimer/proc/drop_items(mob/user) if(!stored_items[user]) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index edda579b7ec7..96894f0592e8 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -395,7 +395,6 @@ Possible to do for anyone motivated enough: Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) Hologram.Impersonation = user - Hologram.copy_known_languages_from(user,replace = TRUE) Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. Hologram.setAnchored(TRUE)//So space wind cannot drag it. @@ -552,9 +551,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ Hologram.alpha = 170 Hologram.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) Hologram.dir = SOUTH //for now - Hologram.grant_all_languages(omnitongue=TRUE) var/datum/language_holder/holder = Hologram.get_language_holder() - holder.selected_default_language = record.language + holder.selected_language = record.language Hologram.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it. Hologram.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them. Hologram.setAnchored(TRUE)//So space wind cannot drag it. @@ -646,7 +644,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ return if(HOLORECORD_LANGUAGE) var/datum/language_holder/holder = replay_holo.get_language_holder() - holder.selected_default_language = entry[2] + holder.selected_language = entry[2] if(HOLORECORD_PRESET) var/preset_type = entry[2] var/datum/preset_holoimage/H = new preset_type @@ -669,6 +667,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ updateDialog() /obj/effect/overlay/holo_pad_hologram + initial_language_holder = /datum/language_holder/universal var/mob/living/Impersonation var/datum/holocall/HC diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm index 7fe97e942946..bf493ebe15c5 100644 --- a/code/game/machinery/telecomms/broadcasting.dm +++ b/code/game/machinery/telecomms/broadcasting.dm @@ -100,7 +100,7 @@ obj/source, // the originating radio frequency, // the frequency the signal is taking place on atom/movable/virtualspeaker/speaker, // representation of the method's speaker - datum/language/language, // the langauge of the message + datum/language/language, // the language of the message message, // the text content of the message spans, // the list of spans applied to the message lvls = null //Yogs -- For NTSL. It's the list of Z-levels that should hear this message. diff --git a/code/game/machinery/telecomms/computers/message.dm b/code/game/machinery/telecomms/computers/message.dm index f9c8ac2c9815..1eed5fa3549d 100644 --- a/code/game/machinery/telecomms/computers/message.dm +++ b/code/game/machinery/telecomms/computers/message.dm @@ -425,7 +425,7 @@ "name" = "[customsender]", "job" = "[customjob]", "message" = custommessage, - "language" = usr.get_default_language(), // PDAs now use the language system! + "language" = usr.get_selected_language(), // PDAs now use the language system! "targets" = list("[customrecepient.owner] ([customrecepient.ownjob])") )) // this will log the signal and transmit it to the target diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 056df171d172..a83340388ff1 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -642,7 +642,7 @@ GLOBAL_LIST_EMPTY(PDAs) "name" = "[owner]", "job" = "[ownjob]", "message" = message, - "language" = user.get_default_language(), + "language" = user.get_selected_language(), "targets" = string_targets )) if (picture) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 333cf2b45737..22864081e7a3 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -198,7 +198,7 @@ if(!spans) spans = list(M.speech_span) if(!language) - language = M.get_default_language() + language = M.get_selected_language() INVOKE_ASYNC(src, .proc/talk_into_impl, M, message, channel, spans.Copy(), language) return ITALICS | REDUCE_RANGE diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm index 0108c65ecab8..633c4d819a69 100644 --- a/code/game/objects/items/holy_weapons.dm +++ b/code/game/objects/items/holy_weapons.dm @@ -438,7 +438,9 @@ S.ckey = C.ckey S.fully_replace_character_name(null, "The spirit of [name]") S.status_flags |= GODMODE - S.language_holder = user.language_holder.copy(S) + S.copy_languages(user, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the user. + S.update_atom_languages() + grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue var/input = stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN) if(src && input) diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm index 08efeb6ca72a..48b25c17a562 100644 --- a/code/game/objects/structures/ghost_role_spawners.dm +++ b/code/game/objects/structures/ghost_role_spawners.dm @@ -55,10 +55,6 @@ new_spawn.fully_replace_character_name(null,random_unique_lizard_name(gender)) to_chat(new_spawn, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Glory to the Necropolis!") //yogs - removed a sentence - new_spawn.grant_language(/datum/language/draconic) - var/datum/language_holder/holder = new_spawn.get_language_holder() - holder.selected_default_language = /datum/language/draconic - new_spawn.mind.add_antag_datum(/datum/antagonist/ashwalker, team) if(ishuman(new_spawn)) diff --git a/code/game/say.dm b/code/game/say.dm index 93d3faf536d5..635d24984fb9 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -28,7 +28,7 @@ GLOBAL_LIST_INIT(freqtospan, list( return spans |= speech_span if(!language) - language = get_default_language() + language = get_selected_language() send_speech(message, 7, src, , spans, message_language=language) /atom/movable/proc/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode) diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 6dee8174de05..5e5e839676eb 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -89,6 +89,7 @@ forge_team_objectives() forge_objectives() remove_clownmut() + owner.current.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue. We are able to transform our body after all. . = ..() /datum/antagonist/changeling/on_removal() diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm index 2d528367d106..976cbefb97eb 100644 --- a/code/modules/antagonists/changeling/powers/absorb.dm +++ b/code/modules/antagonists/changeling/powers/absorb.dm @@ -59,9 +59,10 @@ if(user.nutrition < NUTRITION_LEVEL_WELL_FED) user.set_nutrition(min((user.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED)) + // Absorb a lizard, speak Draconic. + owner.copy_languages(target, LANGUAGE_ABSORB) + if(target.mind && user.mind)//if the victim and user have minds - // Absorb a lizard, speak Draconic. - user.copy_known_languages_from(target) var/datum/mind/suckedbrain = target.mind user.mind.memory += "
We've absorbed [target]'s memories into our own...
[suckedbrain.memory]
" diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index 2fc08e4369f2..f21389261f62 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -104,7 +104,7 @@ if(mob_override) current = mob_override current.faction |= "cult" - current.grant_language(/datum/language/narsie) + current.grant_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST) if(!cult_team.cult_master) vote.Grant(current) communion.Grant(current) @@ -122,7 +122,7 @@ if(mob_override) current = mob_override current.faction -= "cult" - current.remove_language(/datum/language/narsie) + current.remove_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST) vote.Remove(current) communion.Remove(current) magic.Remove(current) diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm index 43183dfe4084..760de3236d4e 100644 --- a/code/modules/antagonists/devil/devil.dm +++ b/code/modules/antagonists/devil/devil.dm @@ -522,7 +522,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", /datum/antagonist/devil/apply_innate_effects(mob/living/mob_override) give_appropriate_spells() - owner.current.grant_all_languages(TRUE) + owner.current.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_DEVIL) update_hud() .=..() @@ -531,6 +531,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", var/obj/effect/proc_holder/spell/S = X if(is_type_in_typecache(S, devil_spells)) owner.RemoveSpell(S) + owner.current.remove_all_languages(LANGUAGE_DEVIL) .=..() /datum/antagonist/devil/proc/printdevilinfo() diff --git a/code/modules/antagonists/devil/true_devil/_true_devil.dm b/code/modules/antagonists/devil/true_devil/_true_devil.dm index 768ad7940a4a..74f67c8c2d58 100644 --- a/code/modules/antagonists/devil/true_devil/_true_devil.dm +++ b/code/modules/antagonists/devil/true_devil/_true_devil.dm @@ -29,7 +29,7 @@ /mob/living/carbon/true_devil/Initialize() create_bodyparts() //initialize bodyparts create_internal_organs() - grant_all_languages(omnitongue=TRUE) + grant_all_languages() ..() /mob/living/carbon/true_devil/create_internal_organs() diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm index 05d31a327cb6..07b379e8a6dc 100644 --- a/code/modules/antagonists/disease/disease_abilities.dm +++ b/code/modules/antagonists/disease/disease_abilities.dm @@ -59,7 +59,7 @@ new /datum/disease_ability/symptom/powerful/heal/youth var/short_desc = "" var/long_desc = "" var/stat_block = "" - var/threshold_block = "" + var/threshold_block = list() var/category = "" var/list/symptoms @@ -78,7 +78,7 @@ new /datum/disease_ability/symptom/powerful/heal/youth resistance += initial(S.resistance) stage_speed += initial(S.stage_speed) transmittable += initial(S.transmittable) - threshold_block += "

[initial(S.threshold_desc)]" + threshold_block += initial(S.threshold_descs) stat_block = "Resistance: [resistance]
Stealth: [stealth]
Stage Speed: [stage_speed]
Transmissibility: [transmittable]

" if(symptoms.len == 1) //lazy boy's dream name = initial(S.name) diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm index 371e52632992..2ea2915d3bbc 100644 --- a/code/modules/antagonists/disease/disease_mob.dm +++ b/code/modules/antagonists/disease/disease_mob.dm @@ -314,7 +314,11 @@ the new instance inside the host to be updated to the template's stats. var/list/dat = list() if(examining_ability) - dat += "Back

[examining_ability.name]

[examining_ability.stat_block][examining_ability.long_desc][examining_ability.threshold_block]" + dat += "Back
" + dat += "

[examining_ability.name]

" + dat += "[examining_ability.stat_block][examining_ability.long_desc][examining_ability.threshold_block]" + for(var/entry in examining_ability.threshold_block) + dat += "[entry]: [examining_ability.threshold_block[entry]]
" else dat += "

Disease Statistics


\ Resistance: [DT.totalResistance()]
\ diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 91be0d5526da..252f5e62bafc 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -271,7 +271,7 @@ if(TRAITOR_AI) add_law_zero() owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE) - owner.current.grant_language(/datum/language/codespeak) + owner.current.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MALF) if(TRAITOR_HUMAN) if(should_equip) equip(silent) diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 60e037edfb27..f31b0d2591df 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -280,7 +280,10 @@ S.name = "Shade of [T.real_name]" S.real_name = "Shade of [T.real_name]" S.key = T.key - S.language_holder = U.language_holder.copy(S) + S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder. + S.copy_languages(U, LANGUAGE_MASTER) + S.update_atom_languages() + grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue if(U) S.faction |= "[REF(U)]" //Add the master as a faction, allowing inter-mob cooperation if(U && iscultist(U)) diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm index b9017a78492e..7887fc07d619 100644 --- a/code/modules/atmospherics/machinery/portable/pump.dm +++ b/code/modules/atmospherics/machinery/portable/pump.dm @@ -84,14 +84,14 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "portable_pump", name, 420, 415, master_ui, state) + ui = new(user, src, ui_key, "portable_pump", name, 300, 315, master_ui, state) ui.open() /obj/machinery/portable_atmospherics/pump/ui_data() var/data = list() data["on"] = on - data["direction"] = direction - data["connected"] = connected_port ? 1 : 0 + data["direction"] = direction == PUMP_IN ? TRUE : FALSE + data["connected"] = connected_port ? TRUE : FALSE data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0) data["target_pressure"] = round(pump.target_pressure ? pump.target_pressure : 0) data["default_pressure"] = round(PUMP_DEFAULT_PRESSURE) @@ -102,6 +102,8 @@ data["holding"] = list() data["holding"]["name"] = holding.name data["holding"]["pressure"] = round(holding.air_contents.return_pressure()) + else + data["holding"] = null return data /obj/machinery/portable_atmospherics/pump/ui_act(action, params) diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index c3a90744fddc..6e3c5104db03 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -72,7 +72,7 @@ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "portable_scrubber", name, 420, 435, master_ui, state) + ui = new(user, src, ui_key, "portable_scrubber", name, 320, 335, master_ui, state) ui.open() /obj/machinery/portable_atmospherics/scrubber/ui_data() @@ -91,6 +91,8 @@ data["holding"] = list() data["holding"]["name"] = holding.name data["holding"]["pressure"] = round(holding.air_contents.return_pressure()) + else + data["holding"] = null return data /obj/machinery/portable_atmospherics/scrubber/replace_tank(mob/living/user, close_valve) diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index 65a16dcc342a..cc7ae5b8774f 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -135,7 +135,7 @@ if(!ishuman(user)) return if(slot == SLOT_HEAD) - user.grant_language(/datum/language/piratespeak/) + user.grant_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT) to_chat(user, "You suddenly know how to speak like a pirate!") /obj/item/clothing/head/pirate/dropped(mob/user) @@ -143,7 +143,7 @@ return var/mob/living/carbon/human/H = user if(H.get_item_by_slot(SLOT_HEAD) == src) - user.remove_language(/datum/language/piratespeak/) + user.remove_language(/datum/language/piratespeak/, TRUE, TRUE, LANGUAGE_HAT) to_chat(user, "You can no longer speak like a pirate.") /obj/item/clothing/head/pirate/captain diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm index def155802f31..fb9b2b5053b3 100644 --- a/code/modules/events/sentience.dm +++ b/code/modules/events/sentience.dm @@ -84,7 +84,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list( SA.key = SG.key - SA.grant_all_languages(TRUE) + SA.grant_all_languages(TRUE, FALSE, FALSE) SA.sentience_act() diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm index 622be38de011..57f52803c2bb 100644 --- a/code/modules/jobs/job_types/curator.dm +++ b/code/modules/jobs/job_types/curator.dm @@ -41,4 +41,4 @@ if(visualsOnly) return - H.grant_all_languages(omnitongue=TRUE) + H.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_CURATOR) diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm index a7f8c7284d07..4a6006691549 100644 --- a/code/modules/language/codespeak.dm +++ b/code/modules/language/codespeak.dm @@ -46,7 +46,7 @@ return to_chat(user, "You start skimming through [src], and suddenly your mind is filled with codewords and responses.") - user.grant_language(/datum/language/codespeak) + user.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) use_charge(user) @@ -65,7 +65,7 @@ M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.") else M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], codewords and responses flow through your mind.", "You hear smacking.") - M.grant_language(/datum/language/codespeak) + M.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) use_charge(user) /obj/item/codespeak_manual/proc/use_charge(mob/user) diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index c1a336eb69c1..2c876cd9a3e6 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -1,145 +1,315 @@ -/datum/language_holder - var/list/languages = list(/datum/language/common) - var/list/shadow_languages = list() - var/only_speaks_language = null - var/selected_default_language = null - var/datum/language_menu/language_menu +/*!Language holders will either exist in an atom/movable or a mind. 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) +* [add_blocked_language](atom/movable.html#proc/add_blocked_language) +* [remove_blocked_language](atom/movable.html#proc/remove_blocked_language) +* [grant_all_languages](atom/movable.html#proc/grant_all_languages) +* [remove_all_languages](atom/movable.html#proc/remove_all_languages) +* [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. + 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. 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 -/datum/language_holder/New(owner) - src.owner = owner - - languages = typecacheof(languages) - shadow_languages = typecacheof(shadow_languages) +/// 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/Destroy() - owner = null QDEL_NULL(language_menu) - languages.Cut() - shadow_languages.Cut() return ..() -/datum/language_holder/proc/copy(newowner) - var/datum/language_holder/copy = new(newowner) - copy.languages = src.languages.Copy() - // shadow languages are not copied. - copy.only_speaks_language = src.only_speaks_language - copy.selected_default_language = src.selected_default_language - // language menu is not copied, that's tied to the holder. - copy.omnitongue = src.omnitongue - return copy - -/datum/language_holder/proc/grant_language(datum/language/dt, shadow = FALSE) - if(shadow) - shadow_languages[dt] = TRUE - else - languages[dt] = TRUE +/// 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 + . = TRUE + if(spoken) + if(!spoken_languages[language]) + spoken_languages[language] = list() + spoken_languages[language] |= source + . = TRUE -/datum/language_holder/proc/grant_all_languages(omnitongue=FALSE) - for(var/la in GLOB.all_languages) - grant_language(la) +/// 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) + for(var/language in GLOB.all_languages) + grant_language(language, understood, spoken, source) + if(grant_omnitongue) // Overrides tongue limitations. + omnitongue = TRUE + return TRUE - if(omnitongue) - src.omnitongue = 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]) + if(source == LANGUAGE_ALL) + understood_languages -= language + else + understood_languages[language] -= source + if(!length(understood_languages[language])) + understood_languages -= language + . = TRUE -/datum/language_holder/proc/get_random_understood_language() - var/list/possible = list() - for(var/dt in languages) - possible += dt - . = safepick(possible) - -/datum/language_holder/proc/remove_language(datum/language/dt, shadow = FALSE) - if(shadow) - shadow_languages -= dt - else - languages -= dt + if(spoken && spoken_languages[language]) + if(source == LANGUAGE_ALL) + spoken_languages -= language + else + spoken_languages[language] -= source + if(!length(spoken_languages[language])) + spoken_languages -= language + . = TRUE -/datum/language_holder/proc/remove_all_languages() - languages.Cut() +/// 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) + if(remove_omnitongue) + omnitongue = FALSE + return TRUE -/datum/language_holder/proc/has_language(datum/language/dt) - if(is_type_in_typecache(dt, languages)) - return LANGUAGE_KNOWN - else - var/atom/movable/AM = get_atom() - var/datum/language_holder/L = AM.get_language_holder(shadow=FALSE) - if(L != src) - if(is_type_in_typecache(dt, L.shadow_languages)) - return LANGUAGE_SHADOWED - return FALSE +/// Adds a single language or list of languages to the blocked language list. +/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 + return TRUE -/datum/language_holder/proc/copy_known_languages_from(thing, replace=FALSE) - var/datum/language_holder/other - if(istype(thing, /datum/language_holder)) - other = thing - else if(ismovableatom(thing)) - var/atom/movable/AM = thing - other = AM.get_language_holder() - else if(istype(thing, /datum/mind)) - var/datum/mind/M = thing - other = M.get_language_holder() +/// 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 + return TRUE - if(replace) - src.remove_all_languages() +/// 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) + if(language in blocked_languages) + return FALSE + if(spoken) + return language in spoken_languages + return language in understood_languages - for(var/l in other.languages) - src.grant_language(l) +/// 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 + +/// 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() + if(selected_language && can_speak_language(selected_language)) + return selected_language + selected_language = null + var/highest_priority + for(var/lang in spoken_languages) + var/datum/language/language = lang + var/priority = initial(language.default_priority) + if((!highest_priority || (priority > highest_priority)) && !(language in blocked_languages)) + if(can_speak_language(language)) + selected_language = language + highest_priority = priority + return selected_language +/// Gets a random understood language, useful for hallucinations and such. +/datum/language_holder/proc/get_random_understood_language() + return pick(understood_languages) +/// Gets a random spoken language, useful for forced speech and such. +/datum/language_holder/proc/get_random_spoken_language() + return pick(spoken_languages) + +/// 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 = 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(ismovableatom(owner)) - . = owner - else if(istype(owner, /datum/mind)) - var/datum/mind/M = owner - if(M.current) - . = M.current + if(owner) + if(istype(owner, /datum/mind)) + var/datum/mind/M = owner + return M.current + return owner + return FALSE -/datum/language_holder/alien - languages = list(/datum/language/xenocommon) +/// 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) -/datum/language_holder/monkey - languages = list(/datum/language/monkey) + copy_languages(from_atom) + get_selected_language() + return TRUE -/datum/language_holder/swarmer - languages = list(/datum/language/swarmer) +/// 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. + for(var/language in from_holder.understood_languages) + grant_language(language, TRUE, FALSE, source_override) + for(var/language in from_holder.spoken_languages) + grant_language(language, FALSE, TRUE, source_override) + else + for(var/language in from_holder.understood_languages) + grant_language(language, TRUE, FALSE, from_holder.understood_languages[language]) + for(var/language in from_holder.spoken_languages) + grant_language(language, FALSE, TRUE, from_holder.spoken_languages[language]) + for(var/language in from_holder.blocked_languages) + add_blocked_language(language, from_holder.blocked_languages[language]) + return TRUE + + +//************************************************ +//* Specific language holders * +//* Use atom language sources only. * +//************************************************/ + + +/datum/language_holder/alien + understood_languages = list(/datum/language/xenocommon = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/xenocommon = list(LANGUAGE_ATOM)) + blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/clockmob - languages = list(/datum/language/common, /datum/language/ratvar) - only_speaks_language = /datum/language/ratvar + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/ratvar = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/ratvar = list(LANGUAGE_ATOM)) /datum/language_holder/construct - languages = list(/datum/language/common, /datum/language/narsie) + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/narsie = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/narsie = list(LANGUAGE_ATOM)) /datum/language_holder/drone - languages = list(/datum/language/common, /datum/language/drone, /datum/language/machine) - only_speaks_language = /datum/language/drone + understood_languages = list(/datum/language/drone = list(LANGUAGE_ATOM), + /datum/language/machine = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/drone = list(LANGUAGE_ATOM)) + blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/drone/syndicate - only_speaks_language = null + blocked_languages = list() -/datum/language_holder/slime - languages = list(/datum/language/common, /datum/language/slime) - only_speaks_language = /datum/language/slime +/datum/language_holder/jelly + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/slime = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/slime = list(LANGUAGE_ATOM)) /datum/language_holder/lightbringer - // TODO change to a lightbringer specific sign language - languages = list(/datum/language/slime) + understood_languages = list(/datum/language/slime = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/slime = list(LANGUAGE_ATOM)) + blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) + +/datum/language_holder/lizard + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM)) + +/datum/language_holder/lizard/ash + selected_language = /datum/language/draconic + +/datum/language_holder/monkey + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/monkey = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/monkey = list(LANGUAGE_ATOM)) + +/datum/language_holder/mushroom + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/mushroom = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/mushroom = list(LANGUAGE_ATOM)) + +/datum/language_holder/slime + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/slime = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/slime = list(LANGUAGE_ATOM)) + +/datum/language_holder/swarmer + understood_languages = list(/datum/language/swarmer = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/swarmer = list(LANGUAGE_ATOM)) + blocked_languages = list(/datum/language/common = list(LANGUAGE_ATOM)) /datum/language_holder/synthetic - languages = list(/datum/language/common) - shadow_languages = list(/datum/language/common, /datum/language/machine, /datum/language/draconic) + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/machine = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/machine = list(LANGUAGE_ATOM), + /datum/language/draconic = list(LANGUAGE_ATOM)) /datum/language_holder/empty - languages = list() - shadow_languages = list() + understood_languages = list() + spoken_languages = list() /datum/language_holder/universal/New() ..() - grant_all_languages(omnitongue=TRUE) + grant_all_languages() diff --git a/code/modules/language/language_menu.dm b/code/modules/language/language_menu.dm index eea87f1d808b..a7ce211a1875 100644 --- a/code/modules/language/language_menu.dm +++ b/code/modules/language/language_menu.dm @@ -1,8 +1,8 @@ /datum/language_menu var/datum/language_holder/language_holder -/datum/language_menu/New(language_holder) - src.language_holder = language_holder +/datum/language_menu/New(_language_holder) + language_holder = _language_holder /datum/language_menu/Destroy() language_holder = null @@ -24,21 +24,20 @@ data["is_living"] = FALSE data["languages"] = list() - for(var/ld in GLOB.all_languages) - var/result = language_holder.has_language(ld) + for(var/lang in GLOB.all_languages) + var/result = language_holder.has_language(lang) || language_holder.has_language(lang, TRUE) if(!result) continue - var/shadow = result == LANGUAGE_SHADOWED - var/datum/language/LD = ld + var/datum/language/language = lang var/list/L = list() - L["name"] = initial(LD.name) - L["desc"] = initial(LD.desc) - L["key"] = initial(LD.key) - L["is_default"] = (LD == language_holder.selected_default_language) - L["shadow"] = shadow + 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_in_language(LD) + L["can_speak"] = AM.can_speak_language(language) + L["can_understand"] = AM.has_language(language) data["languages"] += list(L) @@ -47,15 +46,15 @@ data["omnitongue"] = language_holder.omnitongue data["unknown_languages"] = list() - for(var/ld in GLOB.all_languages) - if(language_holder.has_language(ld)) + for(var/lang in GLOB.all_languages) + if(language_holder.has_language(lang) || language_holder.has_language(lang, TRUE)) continue - var/datum/language/LD = ld + var/datum/language/language = lang var/list/L = list() - L["name"] = initial(LD.name) - L["desc"] = initial(LD.desc) - L["key"] = initial(LD.key) + L["name"] = initial(language.name) + L["desc"] = initial(language.desc) + L["key"] = initial(language.key) data["unknown_languages"] += list(L) return data @@ -68,27 +67,51 @@ var/language_name = params["language_name"] var/datum/language/language_datum - for(var/ld in GLOB.all_languages) - var/datum/language/LD = ld - if(language_name == initial(LD.name)) - language_datum = LD + for(var/lang in GLOB.all_languages) + var/datum/language/language = lang + 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_in_language(language_datum)) - language_holder.selected_default_language = language_datum + if(language_datum && AM.can_speak_language(language_datum)) + language_holder.selected_language = language_datum . = TRUE if("grant_language") if((is_admin || isobserver(AM)) && language_datum) - language_holder.grant_language(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 + switch(choice) + if("Only Spoken") + spoken = TRUE + if("Only Understood") + understood = TRUE + if("Both") + spoken = TRUE + understood = TRUE + language_holder.grant_language(language_datum, understood, spoken) 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)].") . = TRUE if("remove_language") if((is_admin || isobserver(AM)) && language_datum) - language_holder.remove_language(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 + switch(choice) + if("Only Spoken") + spoken = TRUE + if("Only Understood") + understood = TRUE + if("Both") + spoken = TRUE + understood = TRUE + language_holder.remove_language(language_datum, understood, spoken) 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)].") diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 5624732beb4f..4d64c909d89a 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -569,8 +569,8 @@ /obj/item/book_of_babel/attack_self(mob/user) if(!user.can_read(src)) return FALSE - 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(omnitongue=TRUE) + 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() new /obj/effect/decal/cleanable/ash(get_turf(user)) qdel(src) diff --git a/code/modules/mob/living/brain/say.dm b/code/modules/mob/living/brain/say.dm index b7d7e1d7fca9..ed8857886ad7 100644 --- a/code/modules/mob/living/brain/say.dm +++ b/code/modules/mob/living/brain/say.dm @@ -26,7 +26,7 @@ message = capitalize(message) return message -/mob/living/brain/could_speak_in_language(datum/language/dt) +/mob/living/brain/could_speak_language(datum/language/dt) if(istype(container, /obj/item/mmi/posibrain/soul_vessel)) // soul vessels can only speak ratvarian. . = ispath(dt, /datum/language/ratvar) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 727c08b38296..4d0fe216c0bc 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -26,6 +26,7 @@ GLOBAL_LIST_EMPTY(roundstart_races) var/list/no_equip = list() // slots the race can't equip stuff to var/nojumpsuit = 0 // this is sorta... weird. it basically lets you equip stuff that usually needs jumpsuits without one, like belts and pockets and ids var/say_mod = "says" // affects the speech message + var/species_language_holder = /datum/language_holder var/list/default_features = list() // Default mutant bodyparts for this species. Don't forget to set one for every mutant bodypart you allow this species to have. var/list/mutant_bodyparts = list() // Visible CURRENT bodyparts that are unique to a species. DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK SHIT UP! Changes to this list for non-species specific bodyparts (ie cat ears and tails) should be assigned at organ level if possible. Layer hiding is handled by handle_mutant_bodyparts() below. var/list/mutant_organs = list() //Internal organs that are unique to this race. diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 227f83064187..4058825ea88f 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -8,6 +8,7 @@ meat = null damage_overlay_type = "synth" mutanttongue = /obj/item/organ/tongue/robot + species_language_holder = /datum/language_holder/synthetic limbs_id = "synth" changesource_flags = MIRROR_BADMIN | WABBAJACK | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT diff --git a/code/modules/mob/living/carbon/human/species_types/eggpeople.dm b/code/modules/mob/living/carbon/human/species_types/eggpeople.dm index 17502dab2c58..3d7af287ea01 100644 --- a/code/modules/mob/living/carbon/human/species_types/eggpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/eggpeople.dm @@ -24,9 +24,7 @@ disliked_food = GROSS | DAIRY | EGG liked_food = MEAT // Eggpeople are carnivores. screamsound = 'yogstation/sound/voice/eggperson/egg_scream.ogg' // (Hopefully) the sound of an egg cracking - -/datum/species/egg/after_equip_job(datum/job/J, mob/living/carbon/human/H) - H.grant_language(/datum/language/egg) + species_language_holder = /datum/language/egg /datum/species/egg/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H) if(damagetype == BRUTE) // Dynamic brute resist based on burn damage. The more fried the egg, the harder the shell!! diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index f91233a47c68..84d6f684f5e4 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -16,18 +16,17 @@ heatmod = 0.5 // = 1/4x heat damage burnmod = 0.5 // = 1/2x generic burn damage changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT + species_language_holder = /datum/language_holder/jelly /datum/species/jelly/on_species_loss(mob/living/carbon/C) if(regenerate_limbs) regenerate_limbs.Remove(C) - C.remove_language(/datum/language/slime) C.faction -= "slime" ..() C.faction -= "slime" /datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species) ..() - C.grant_language(/datum/language/slime) if(ishuman(C)) regenerate_limbs = new regenerate_limbs.Grant(C) @@ -734,4 +733,4 @@ to_chat(H, "You connect [target]'s mind to your slime link!") else to_chat(H, "You can't seem to link [target]'s mind...") - to_chat(target, "The foreign presence leaves your mind.") \ No newline at end of file + to_chat(target, "The foreign presence leaves your mind.") diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index ac9d78a7cf13..4a6fb1e28d02 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -25,9 +25,7 @@ deathsound = 'sound/voice/lizard/deathsound.ogg' screamsound = 'yogstation/sound/voice/lizardperson/lizard_scream.ogg' //yogs - lizard scream wings_icon = "Dragon" - -/datum/species/lizard/after_equip_job(datum/job/J, mob/living/carbon/human/H) - H.grant_language(/datum/language/draconic) + species_language_holder = /datum/language_holder/lizard /datum/species/lizard/random_name(gender,unique,lastname) if(unique) @@ -83,6 +81,7 @@ inherent_traits = list(TRAIT_NOGUNS) //yogs start - ashwalkers have special lungs and actually breathe mutantlungs = /obj/item/organ/lungs/ashwalker breathid = "n2" // yogs end + species_language_holder = /datum/language_holder/lizard/ash // yogs start - Ashwalkers now have ash immunity /datum/species/lizard/ashwalker/on_species_gain(mob/living/carbon/C, datum/species/old_species) diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index ed6650085768..d80d479fd929 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -26,13 +26,11 @@ mutanteyes = /obj/item/organ/eyes/night_vision/mushroom use_skintones = FALSE var/datum/martial_art/mushpunch/mush + species_language_holder = /datum/language_holder/mushroom /datum/species/mush/check_roundstart_eligible() return FALSE //hard locked out of roundstart on the order of design lead kor, this can be removed in the future when planetstation is here OR SOMETHING but right now we have a problem with races. -/datum/species/mush/after_equip_job(datum/job/J, mob/living/carbon/human/H) - H.grant_language(/datum/language/mushroom) //pomf pomf - /datum/species/mush/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() if(ishuman(C)) diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm index 9521ca1f9226..4f9e779dd378 100644 --- a/code/modules/mob/living/carbon/human/species_types/synths.dm +++ b/code/modules/mob/living/carbon/human/species_types/synths.dm @@ -14,6 +14,8 @@ var/list/initial_species_traits //for getting these values back for assume_disguise() var/list/initial_inherent_traits changesource_flags = MIRROR_BADMIN | WABBAJACK | SLIME_EXTRACT//Yogs -- Slime_extract + species_language_holder = /datum/language_holder/synthetic + /datum/species/synth/New() initial_species_traits = species_traits.Copy() diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 577ac28a473c..96c48b4695e9 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -42,13 +42,11 @@ /mob/living/carbon/human/set_drugginess(amount) ..() if(!amount) - remove_language(/datum/language/beachbum) + remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH) /mob/living/carbon/human/adjust_drugginess(amount) ..() - if(!dna.check_mutation(STONER)) - if(druggy) - grant_language(/datum/language/beachbum) - else - remove_language(/datum/language/beachbum) - + if(druggy) + grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH) + else + remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH) diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm index ea02fce6ad78..27d0e9cbaf3d 100644 --- a/code/modules/mob/living/carbon/say.dm +++ b/code/modules/mob/living/carbon/say.dm @@ -12,9 +12,9 @@ return 0 return ..() -/mob/living/carbon/could_speak_in_language(datum/language/dt) +/mob/living/carbon/could_speak_language(datum/language/language) var/obj/item/organ/tongue/T = getorganslot(ORGAN_SLOT_TONGUE) if(T) - . = T.could_speak_in_language(dt) + return T.could_speak_language(language) else - . = initial(dt.flags) & TONGUELESS_SPEECH + return initial(language.flags) & TONGUELESS_SPEECH diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index fdb5d8d23732..4ccac7a893ad 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -101,8 +101,6 @@ var/datum/riding/riding_datum - var/datum/language/selected_default_language - var/last_words //used for database logging var/list/obj/effect/proc_holder/abilities = list() diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index f5b287d9eb8d..32cf5592adee 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -133,7 +133,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( var/datum/language/message_language = get_message_language(message) if(message_language) // No, you cannot speak in xenocommon just because you know the key - if(can_speak_in_language(message_language)) + if(can_speak_language(message_language)) language = message_language message = copytext(message, 3) @@ -142,7 +142,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( message = copytext(message, 2) if(!language) - language = get_default_language() + language = get_selected_language() // Detection of language needs to be before inherent channels, because // AIs use inherent channels for the holopad. Most inherent channels @@ -395,11 +395,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( /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(shadow=TRUE) - if(mind && shadow) - // Mind language holders shadow mob holders. - . = mind.get_language_holder() - if(.) - return . - +/mob/living/get_language_holder(get_minds = TRUE) + if(get_minds && mind) + return mind.get_language_holder() . = ..() diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index f59d76b959ac..dad222b7ba3a 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -173,7 +173,7 @@ #undef VOX_DELAY #endif -/mob/living/silicon/ai/could_speak_in_language(datum/language/dt) +/mob/living/silicon/ai/could_speak_language(datum/language/dt) if(is_servant_of_ratvar(src)) // Ratvarian AIs can only speak Ratvarian . = ispath(dt, /datum/language/ratvar) diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index 4ebbf01a3779..5471f405026b 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -12,6 +12,20 @@ if(holoform) fold_in(force = TRUE) //Need more effects that aren't instadeath or permanent law corruption. + //Ask and you shall receive + switch(rand(1, 3)) + if(1) + stuttering = 1 + to_chat(src, "Warning: Feedback loop detected in speech module.") + if(2) + slurring = 1 + to_chat(src, "Warning: Audio synthesizer CPU stuck.") + if(3) + derpspeech = 1 + to_chat(src, "Warning: Vocabulary databank corrupted.") + if(prob(40)) + mind.language_holder.selected_language = get_random_spoken_language() + /mob/living/silicon/pai/ex_act(severity, target) take_holo_damage(severity * 50) diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index afc75ff89f29..7160fab7f3b0 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -277,9 +277,8 @@ encryptmod = TRUE if("translator") - if(href_list["toggle"]) - grant_all_languages(TRUE) - // this is PERMAMENT. + if(href_list["toggle"]) //This is permanent. + grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_SOFTWARE) if("doorjack") if(href_list["jack"]) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 144d1139934e..2df203021327 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -902,7 +902,6 @@ Pass a positive integer as an argument to override a bot's default speed. bot_name = name name = paicard.pai.name faction = user.faction.Copy() - language_holder = paicard.pai.language_holder.copy(src) log_combat(user, paicard.pai, "uploaded to [bot_name],") return TRUE else diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 084b13c8023f..3640c9675ad0 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -455,6 +455,7 @@ new_xeno.a_intent = INTENT_HARM new_xeno.key = key + update_atom_languages() to_chat(new_xeno, "You are now an alien.") . = new_xeno diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index bd873b198f08..8c542345d516 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -247,7 +247,7 @@ if(text == PAPER_FIELD) templist += text else - var/datum/langtext/L = new(text,usr.get_default_language()) + var/datum/langtext/L = new(text,usr.get_selected_language()) templist += L var/id = href_list["write"] if(id == "end") diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index b21f37c3bdad..688cb7b03d26 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -224,7 +224,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "gravity_generator", name, 400, 200, master_ui, state) + ui = new(user, src, ui_key, "gravity_generator", name, 400, 165, master_ui, state) ui.open() /obj/machinery/gravity_generator/main/ui_data(mob/user) @@ -247,7 +247,8 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne breaker = !breaker investigate_log("was toggled [breaker ? "ON" : "OFF"] by [key_name(usr)].", INVESTIGATE_GRAVITY) set_power() - + . = TRUE + // Power and Icon States /obj/machinery/gravity_generator/main/power_change() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 36f34e1b74f5..6c3daf00e96d 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -239,7 +239,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) add_overlay(causality_field, TRUE) var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated." - radio.talk_into(src, speaking, common_channel, language = get_default_language()) + radio.talk_into(src, speaking, common_channel, language = get_selected_language()) for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10) if(damage < explosion_point) // Cutting it a bit close there engineers radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index dac9b9a1d73e..0eb93d7bf09c 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -266,7 +266,6 @@ if(!new_mob) return - new_mob.grant_language(/datum/language/common) // Some forms can still wear some items for(var/obj/item/W in contents) diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 96467e64ec77..366a300990fd 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -12,7 +12,6 @@ idle_power_usage = 20 resistance_flags = ACID_PROOF var/wait - var/mode = MAIN_SCREEN var/datum/symptom/selected_symptom var/obj/item/reagent_containers/beaker @@ -72,18 +71,14 @@ if(istype(D, /datum/disease/advance)) var/datum/disease/advance/A = D var/disease_name = SSdisease.get_disease_name(A.GetDiseaseID()) - if((disease_name == "Unknown") && A.mutable) - this["can_rename"] = TRUE + this["can_rename"] = ((disease_name == "Unknown") && A.mutable) this["name"] = disease_name this["is_adv"] = TRUE this["symptoms"] = list() - var/symptom_index = 1 for(var/symptom in A.symptoms) var/datum/symptom/S = symptom var/list/this_symptom = list() - this_symptom["name"] = S.name - this_symptom["sym_index"] = symptom_index - symptom_index++ + this_symptom = get_symptom_data(S) this["symptoms"] += list(this_symptom) this["resistance"] = A.totalResistance() this["stealth"] = A.totalStealth() @@ -108,7 +103,7 @@ this["transmission"] = S.transmittable this["level"] = S.level this["neutered"] = S.neutered - this["threshold_desc"] = S.threshold_desc + this["threshold_desc"] = S.threshold_descs . += this /obj/machinery/computer/pandemic/proc/get_resistance_data(datum/reagent/blood/B) @@ -150,29 +145,28 @@ /obj/machinery/computer/pandemic/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open = FALSE, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state) ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "pandemic", name, 700, 500, master_ui, state) + ui = new(user, src, ui_key, "pandemic", name, 520, 550, master_ui, state) ui.open() /obj/machinery/computer/pandemic/ui_data(mob/user) var/list/data = list() data["is_ready"] = !wait - data["mode"] = mode - switch(mode) - if(MAIN_SCREEN) - if(beaker) - data["has_beaker"] = TRUE - if(!beaker.reagents.total_volume || !beaker.reagents.reagent_list) - data["beaker_empty"] = TRUE - var/datum/reagent/blood/B = locate() in beaker.reagents.reagent_list - if(B) - data["has_blood"] = TRUE - data[/datum/reagent/blood] = list() - data[/datum/reagent/blood]["dna"] = B.data["blood_DNA"] || "none" - data[/datum/reagent/blood]["type"] = B.data["blood_type"] || "none" - data["viruses"] = get_viruses_data(B) - data["resistances"] = get_resistance_data(B) - if(SYMPTOM_DETAILS) - data["symptom"] = get_symptom_data(selected_symptom) + if(beaker) + data["has_beaker"] = TRUE + data["beaker_empty"] = (!beaker.reagents.total_volume || !beaker.reagents.reagent_list) + var/datum/reagent/blood/B = locate() in beaker.reagents.reagent_list + if(B) + data["has_blood"] = TRUE + data[/datum/reagent/blood] = list() + data[/datum/reagent/blood]["dna"] = B.data["blood_DNA"] || "none" + data[/datum/reagent/blood]["type"] = B.data["blood_type"] || "none" + data["viruses"] = get_viruses_data(B) + data["resistances"] = get_resistance_data(B) + else + data["has_blood"] = FALSE + else + data["has_beaker"] = FALSE + data["has_blood"] = FALSE return data @@ -198,7 +192,7 @@ if(!A.mutable) return if(A) - var/new_name = stripped_input(usr, "Name the disease", "New name", "", MAX_NAME_LEN) + var/new_name = html_encode(params["name"]) if(!new_name || ..()) return A.AssignName(new_name) @@ -235,18 +229,6 @@ update_icon() addtimer(CALLBACK(src, .proc/reset_replicator_cooldown), 200) . = TRUE - if("symptom_details") - var/picked_symptom_index = text2num(params["picked_symptom"]) - var/index = text2num(params["index"]) - var/datum/disease/advance/A = get_by_index("viruses", index) - var/datum/symptom/S = A.symptoms[picked_symptom_index] - mode = SYMPTOM_DETAILS - selected_symptom = S - . = TRUE - if("back") - mode = MAIN_SCREEN - selected_symptom = null - . = TRUE /obj/machinery/computer/pandemic/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 07dd764a496f..67ece673dc43 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -928,9 +928,10 @@ datum/status_effect/stabilized/blue/on_remove() familiar = new linked.mob_type(get_turf(owner.loc)) familiar.name = linked.mob_name familiar.del_on_death = TRUE - familiar.copy_known_languages_from(owner, FALSE) + 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) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index e005a7fad2cf..8e28e1bd1d00 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -687,7 +687,7 @@ if(SM.flags_1 & HOLOGRAM_1) //Check to see if it's a holodeck creature to_chat(SM, "You also become depressingly aware that you are not a real creature, but instead a holoform. Your existence is limited to the parameters of the holodeck.") to_chat(user, "[SM] accepts [src] and suddenly becomes attentive and aware. It worked!") - SM.copy_known_languages_from(user, FALSE) + SM.copy_languages(user) after_success(user, SM) qdel(src) else diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm index b4a6f9c3fe61..3820e9f38067 100644 --- a/code/modules/ruins/lavaland_ruin_code.dm +++ b/code/modules/ruins/lavaland_ruin_code.dm @@ -114,7 +114,7 @@ assignedrole = "Lavaland Syndicate" /obj/effect/mob_spawn/human/lavaland_syndicate/special(mob/living/new_spawn) - new_spawn.grant_language(/datum/language/codespeak) + new_spawn.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND) /datum/outfit/lavaland_syndicate name = "Lavaland Syndicate Agent" diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 98a1451d41e2..725ea19df683 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -45,8 +45,8 @@ UnregisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech) M.RegisterSignal(M, COMSIG_MOB_SAY, /mob/living/carbon/.proc/handle_tongueless_speech) -/obj/item/organ/tongue/could_speak_in_language(datum/language/dt) - return is_type_in_typecache(dt, languages_possible) +/obj/item/organ/tongue/could_speak_language(language) + return is_type_in_typecache(language, languages_possible) /obj/item/organ/tongue/lizard name = "forked tongue" @@ -220,7 +220,7 @@ modifies_speech = TRUE taste_sensitivity = 25 // not as good as an organic tongue -/obj/item/organ/tongue/robot/can_speak_in_language(datum/language/dt) +/obj/item/organ/tongue/robot/can_speak_language(language) return TRUE // THE MAGIC OF ELECTRONICS /obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args) diff --git a/tgui-next/package.json b/tgui-next/package.json index 820cc6cb33df..9b7253e131c1 100644 --- a/tgui-next/package.json +++ b/tgui-next/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "babel-eslint": "^10.0.3", - "eslint": "^6.5.1", - "eslint-plugin-react": "^7.16.0" + "eslint": "^6.7.2", + "eslint-plugin-react": "^7.17.0" } } diff --git a/tgui-next/packages/common/collections.js b/tgui-next/packages/common/collections.js index bbcea64cd88f..b9d636692352 100644 --- a/tgui-next/packages/common/collections.js +++ b/tgui-next/packages/common/collections.js @@ -100,19 +100,6 @@ export const sortBy = (...iterateeFns) => array => { return mappedArray; }; -/** - * A version of map, but for mapping over two arrays instead of one. - * The iteratee is invoked with three arguments: - * (valueA, valueB, index). - */ -export const product = iterateeFn => (arrayA, arrayB) => { - const result = []; - for (let i = 0; i < arrayA.length; i++) { - result.push(iterateeFn(arrayA[i], arrayB[i], i)); - } - return result; -}; - /** * A fast implementation of reduce. */ diff --git a/tgui-next/packages/common/vector.js b/tgui-next/packages/common/vector.js index 967827f556ec..fa985978963e 100644 --- a/tgui-next/packages/common/vector.js +++ b/tgui-next/packages/common/vector.js @@ -1,45 +1,48 @@ -import { map, product, reduce } from './collections'; +import { map, reduce, zipWith } from './collections'; /** * Creates a vector, with as many dimensions are there are arguments. */ -export const vec = (...components) => { +export const vecCreate = (...components) => { if (Array.isArray(components[0])) { - return new Vector(components[0]); + return [...components[0]]; } - return new Vector(components); + return components; }; const ADD = (a, b) => a + b; const SUB = (a, b) => a - b; const MUL = (a, b) => a * b; +const DIV = (a, b) => a / b; -class Vector { - constructor(components) { - this.c = components; - } +export const vecAdd = (...vecs) => { + return reduce((a, b) => zipWith(ADD)(a, b))(vecs); +}; - add(vec) { - return new Vector(product(ADD)(this.c, vec.c)); - } +export const vecSubtract = (...vecs) => { + return reduce((a, b) => zipWith(SUB)(a, b))(vecs); +}; - subtract(vec) { - return new Vector(product(SUB)(this.c, vec.c)); - } +export const vecMultiply = (...vecs) => { + return reduce((a, b) => zipWith(MUL)(a, b))(vecs); +}; - multiply(n) { - return new Vector(map(x => x * n)(this.c)); - } +export const vecDivide = (...vecs) => { + return reduce((a, b) => zipWith(DIV)(a, b))(vecs); +}; - divide(n) { - return new Vector(map(x => x / n)(this.c)); - } +export const vecScale = (vec, n) => { + return map(x => x * n)(vec); +}; - magnitude() { - return Math.sqrt(reduce(ADD)(product(MUL)(this.c, this.c))); - } +export const vecInverse = vec => { + return map(x => -x)(vec); +}; - normalize() { - return this.divide(this.magnitude()); - } -} +export const vecLength = vec => { + return Math.sqrt(reduce(ADD)(zipWith(MUL)(vec, vec))); +}; + +export const vecNormalize = vec => { + return vecDivide(vec, vecLength(vec)); +}; diff --git a/tgui-next/packages/tgui-dev-server/link/client.js b/tgui-next/packages/tgui-dev-server/link/client.js index d2a7e53cced4..bd33bcd61430 100644 --- a/tgui-next/packages/tgui-dev-server/link/client.js +++ b/tgui-next/packages/tgui-dev-server/link/client.js @@ -48,13 +48,18 @@ const serializeObject = obj => { // Error object if (value instanceof Error) { return { - __type__: 'error', + __error__: true, string: String(value), stack: value.stack, }; } return value; } + if (typeof value === 'number' && !Number.isFinite(value)) { + return { + __number__: String(value), + }; + } return value; }); refs = null; diff --git a/tgui-next/packages/tgui-dev-server/link/server.js b/tgui-next/packages/tgui-dev-server/link/server.js index 8f8dbdf9b5fe..4d0e22d34136 100644 --- a/tgui-next/packages/tgui-dev-server/link/server.js +++ b/tgui-next/packages/tgui-dev-server/link/server.js @@ -32,9 +32,12 @@ export const broadcastMessage = (link, msg) => { const deserializeObject = obj => { return JSON.parse(obj, (key, value) => { if (typeof value === 'object' && value !== null) { - if (value.__type__ === 'error') { + if (value.__error__) { return retrace(value.stack); } + if (value.__number__) { + return parseFloat(value.__number__); + } return value; } return value; diff --git a/tgui-next/packages/tgui/backend.js b/tgui-next/packages/tgui/backend.js index bf3c77eb3af3..cdaf89fc6be9 100644 --- a/tgui-next/packages/tgui/backend.js +++ b/tgui-next/packages/tgui/backend.js @@ -39,10 +39,6 @@ export const backendReducer = (state, action) => { // Calculate our own fields const visible = config.status !== UI_DISABLED; const interactive = config.status === UI_INTERACTIVE; - // IE8: Force the non-fancy setting - if (tridentVersion <= 4) { - config.fancy = 0; - } // Return new state return { ...state, diff --git a/tgui-next/packages/tgui/components/TitleBar.js b/tgui-next/packages/tgui/components/TitleBar.js index c9c4eb630a40..f0a504050080 100644 --- a/tgui-next/packages/tgui/components/TitleBar.js +++ b/tgui-next/packages/tgui/components/TitleBar.js @@ -1,4 +1,6 @@ import { classes, pureComponentHooks } from 'common/react'; +import { toTitleCase } from 'common/string'; +import { tridentVersion } from '../byond'; import { UI_DISABLED, UI_INTERACTIVE, UI_UPDATE } from '../constants'; import { Icon } from './Icon'; @@ -27,13 +29,20 @@ export const TitleBar = props => { color={statusToColor(status)} name="eye" />
- {title} + {title === title.toLowerCase() ? toTitleCase(title) : title}
-
fancy && onDragStart(e)} /> {!!fancy && ( -
+
+ {tridentVersion <= 4 ? 'x' : '×'} +
)}
); diff --git a/tgui-next/packages/tgui/drag.js b/tgui-next/packages/tgui/drag.js index cfdb309d0936..a29146b796eb 100644 --- a/tgui-next/packages/tgui/drag.js +++ b/tgui-next/packages/tgui/drag.js @@ -1,41 +1,45 @@ -import { winset, winget } from './byond'; +import { vecAdd, vecInverse, vecMultiply } from 'common/vector'; +import { winget, winset } from './byond'; import { createLogger } from './logging'; const logger = createLogger('drag'); -const dragState = { - dragging: false, - resizing: false, - windowRef: undefined, - screenOffset: { x: 0, y: 0 }, - dragPointOffset: {}, - resizeMatrix: {}, - initialWindowSize: {}, +let ref; +let dragging = false; +let resizing = false; +let screenOffset = [0, 0]; +let dragPointOffset; +let resizeMatrix; +let initialSize; +let size; + +const getWindowPosition = ref => { + return winget(ref, 'pos').then(pos => [pos.x, pos.y]); +}; + +const setWindowPosition = (ref, vec) => { + return winset(ref, 'pos', vec[0] + ',' + vec[1]); +}; + +const setWindowSize = (ref, vec) => { + return winset(ref, 'size', vec[0] + ',' + vec[1]); }; export const setupDrag = async state => { logger.log('setting up'); - dragState.windowRef = state.config.window; - // Remove window borders - // NOTE: We are currently doing it in the open() tgui module proc, and - // this bit of code is left here just in case everything goes to shit. - // if (state.config.fancy) { - // winset(state.config.window, 'titlebar', false); - // winset(state.config.window, 'can-resize', false); - // } + ref = state.config.window; // Calculate offset caused by windows taskbar - const realPosition = await winget(dragState.windowRef, 'pos'); - dragState.screenOffset = { - x: realPosition.x - window.screenX, - y: realPosition.y - window.screenY, - }; + const realPosition = await getWindowPosition(ref); + screenOffset = [ + realPosition[0] - window.screenLeft, + realPosition[1] - window.screenTop, + ]; // Constraint window position const [relocated, safePosition] = constraintPosition(realPosition); if (relocated) { - winset(dragState.windowRef, 'pos', - safePosition.x + ',' + safePosition.y); + setWindowPosition(ref, safePosition); } - logger.debug('current dragState', dragState); + logger.debug('current state', { ref, screenOffset }); }; /** @@ -43,7 +47,8 @@ export const setupDrag = async state => { * margins which could be a system taskbar. */ const constraintPosition = position => { - let { x, y } = position; + let x = position[0]; + let y = position[1]; let relocated = false; // Left if (x < 0) { @@ -65,101 +70,77 @@ const constraintPosition = position => { y = window.screen.availHeight - window.innerHeight; relocated = true; } - return [relocated, { x, y }]; + return [relocated, [x, y]]; }; export const dragStartHandler = event => { logger.log('drag start'); - dragState.dragging = true; - dragState.dragPointOffset = { - x: window.screenX - event.screenX, - y: window.screenY - event.screenY, - }; + dragging = true; + dragPointOffset = [ + window.screenLeft - event.screenX, + window.screenTop - event.screenY, + ]; document.addEventListener('mousemove', dragMoveHandler); document.addEventListener('mouseup', dragEndHandler); - dragHandler(event); + dragMoveHandler(event); }; -export const dragMoveHandler = event => { - dragHandler(event); -}; - -export const dragEndHandler = event => { +const dragEndHandler = event => { logger.log('drag end'); - dragHandler(event); + dragMoveHandler(event); document.removeEventListener('mousemove', dragMoveHandler); document.removeEventListener('mouseup', dragEndHandler); - dragState.dragging = false; + dragging = false; }; -const dragHandler = event => { - if (!dragState.dragging) { +const dragMoveHandler = event => { + if (!dragging) { return; } event.preventDefault(); - let x = event.screenX - + dragState.screenOffset.x - + dragState.dragPointOffset.x; - let y = event.screenY - + dragState.screenOffset.y - + dragState.dragPointOffset.y; - winset(dragState.windowRef, 'pos', x + ',' + y); + setWindowPosition(ref, vecAdd( + [event.screenX, event.screenY], + screenOffset, + dragPointOffset)); }; export const resizeStartHandler = (x, y) => event => { - logger.log('resize start', [x, y]); - dragState.resizing = true; - dragState.resizeMatrix = { x, y }; - dragState.dragPointOffset = { - x: window.screenX - event.screenX, - y: window.screenY - event.screenY, - }; - dragState.initialWindowSize = { - x: window.innerWidth, - y: window.innerHeight, - }; + resizeMatrix = [x, y]; + logger.log('resize start', resizeMatrix); + resizing = true; + dragPointOffset = [ + window.screenLeft - event.screenX, + window.screenTop - event.screenY, + ]; + initialSize = [ + window.innerWidth, + window.innerHeight, + ]; document.addEventListener('mousemove', resizeMoveHandler); document.addEventListener('mouseup', resizeEndHandler); - resizeHandler(event); -}; - -export const resizeMoveHandler = event => { - resizeHandler(event); + resizeMoveHandler(event); }; -export const resizeEndHandler = event => { - logger.log('resize end', dragState.currentSize); - resizeHandler(event); +const resizeEndHandler = event => { + logger.log('resize end', size); + resizeMoveHandler(event); document.removeEventListener('mousemove', resizeMoveHandler); document.removeEventListener('mouseup', resizeEndHandler); - dragState.resizing = false; + resizing = false; }; -const resizeHandler = event => { - if (!dragState.resizing) { +const resizeMoveHandler = event => { + if (!resizing) { return; } event.preventDefault(); - dragState.currentSize = { - x: ( - dragState.initialWindowSize.x - + (event.screenX - - window.screenX - + dragState.dragPointOffset.x - + 1) - * dragState.resizeMatrix.x - ), - y: ( - dragState.initialWindowSize.y - + (event.screenY - - window.screenY - + dragState.dragPointOffset.y - + 1) - * dragState.resizeMatrix.y - ), - }; + size = vecAdd(initialSize, vecMultiply(resizeMatrix, vecAdd( + [event.screenX, event.screenY], + vecInverse([window.screenLeft, window.screenTop]), + dragPointOffset, + [1, 1]))); // Sane window size values - const x = Math.max(dragState.currentSize.x, 250); - const y = Math.max(dragState.currentSize.y, 120); - winset(dragState.windowRef, 'size', x + ',' + y); + size[0] = Math.max(size[0], 250); + size[1] = Math.max(size[1], 120); + setWindowSize(ref, size); }; diff --git a/tgui-next/packages/tgui/index.js b/tgui-next/packages/tgui/index.js index f43116166c68..1a8b9d4eabcb 100644 --- a/tgui-next/packages/tgui/index.js +++ b/tgui-next/packages/tgui/index.js @@ -119,7 +119,8 @@ const parseStateJson = json => { catch (err) { logger.log(err); logger.log('What we got:', json); - throw err; + const msg = err && err.message; + throw new Error('JSON parsing error: ' + msg); } }; diff --git a/tgui-next/packages/tgui/interfaces/BankMachine.js b/tgui-next/packages/tgui/interfaces/BankMachine.js new file mode 100644 index 000000000000..1021f4f6a1a5 --- /dev/null +++ b/tgui-next/packages/tgui/interfaces/BankMachine.js @@ -0,0 +1,33 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, LabeledList, NoticeBox, Section } from '../components'; + +export const BankMachine = props => { + const { act, data } = useBackend(props); + const { + current_balance, + siphoning, + station_name, + } = data; + return ( + +
+ + act(siphoning ? 'halt' : 'siphon')} /> + )}> + {'$' + current_balance} + + +
+ + Authorized personnel only + +
+ ); +}; diff --git a/tgui-next/packages/tgui/interfaces/Gps.js b/tgui-next/packages/tgui/interfaces/Gps.js index 0630004a226b..752c76b6d84a 100644 --- a/tgui-next/packages/tgui/interfaces/Gps.js +++ b/tgui-next/packages/tgui/interfaces/Gps.js @@ -1,12 +1,12 @@ import { map, sortBy } from 'common/collections'; import { flow } from 'common/fp'; import { clamp } from 'common/math'; -import { vec } from 'common/vector'; +import { vecLength, vecSubtract } from 'common/vector'; import { Fragment } from 'inferno'; import { useBackend } from '../backend'; import { Box, Button, Icon, LabeledList, Section, Table } from '../components'; -const coordsToVec = coords => vec(map(parseFloat)(coords.split(', '))); +const coordsToVec = coords => map(parseFloat)(coords.split(', ')); export const Gps = props => { const { act, data } = useBackend(props); @@ -23,9 +23,9 @@ export const Gps = props => { // Calculate distance to the target. BYOND distance is capped to 127, // that's why we roll our own calculations here. const dist = signal.dist && ( - Math.round(coordsToVec(currentCoords) - .subtract(coordsToVec(signal.coords)) - .magnitude()) + Math.round(vecLength(vecSubtract( + coordsToVec(currentCoords), + coordsToVec(signal.coords)))) ); return { ...signal, dist, index }; }), diff --git a/tgui-next/packages/tgui/interfaces/GravityGenerator.js b/tgui-next/packages/tgui/interfaces/GravityGenerator.js index 070ce2331995..ecc1aa462fbb 100644 --- a/tgui-next/packages/tgui/interfaces/GravityGenerator.js +++ b/tgui-next/packages/tgui/interfaces/GravityGenerator.js @@ -18,20 +18,13 @@ export const GravityGenerator = props => { No data available ) || ( - act('gentoggle')} /> - )}> - - {on ? 'Powered' : 'Unpowered'} - + +