diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm
index dc2ac19e65..add4a8e277 100644
--- a/code/__DEFINES/language.dm
+++ b/code/__DEFINES/language.dm
@@ -3,5 +3,24 @@
#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_BLOODSUCKER "bloodsucker"
+#define LANGUAGE_CLOCKIE "clockie"
+#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_VASSAL "vassal"
+#define LANGUAGE_VOICECHANGE "voicechange"
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index df91223ed1..1dce4ecc42 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -255,6 +255,7 @@ GLOBAL_LIST_EMPTY(radial_menus)
current_user = M.client
//Blank
menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing",layer = ABOVE_HUD_LAYER)
+ menu_holder.plane = ABOVE_HUD_PLANE
menu_holder.appearance_flags |= KEEP_APART
menu_holder.vis_contents += elements + close_button
current_user.images += menu_holder
@@ -285,13 +286,16 @@ GLOBAL_LIST_EMPTY(radial_menus)
Choices should be a list where list keys are movables or text used for element names and return value
and list values are movables/icons/images used for element icons
*/
-/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE)
+/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE)
if(!user || !anchor || !length(choices))
return
if(!uniqueid)
uniqueid = "defmenu_[REF(user)]_[REF(anchor)]"
if(GLOB.radial_menus[uniqueid])
+ if(!no_repeat_close)
+ var/datum/radial_menu/menu = GLOB.radial_menus[uniqueid]
+ menu.finished = TRUE
return
var/datum/radial_menu/menu = new
@@ -308,4 +312,9 @@ GLOBAL_LIST_EMPTY(radial_menus)
var/answer = menu.selected_choice
qdel(menu)
GLOB.radial_menus -= uniqueid
+ if(require_near && !in_range(anchor, user))
+ return
+ if(istype(custom_check))
+ if(!custom_check.Invoke())
+ return
return answer
\ No newline at end of file
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index 3f71d192e3..e5e1434ab8 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -91,7 +91,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 0e08c4cd15..e076c30ae1 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/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 9be484d99a..9fa6ed5cc8 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -30,7 +30,6 @@ Bonus
symptom_delay_max = 120
var/scramble_language = FALSE
var/datum/language/current_language
- var/datum/language_holder/original_language
threshold_desc = 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.",
@@ -48,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
- var/datum/language_holder/mob_language = M.get_language_holder()
- original_language = mob_language.copy()
/datum/symptom/voice_change/Activate(datum/disease/advance/A)
if(!..())
@@ -64,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)
- var/datum/language_holder/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)
..()
@@ -77,7 +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)
- 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/dna.dm b/code/datums/dna.dm
index e0df2a8f1b..8f7a8ca72f 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -355,6 +355,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 54fcbbc6aa..a9438fa80b 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -85,8 +85,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
@@ -101,9 +100,6 @@
if(iscarbon(current))
var/mob/living/carbon/C = current
C.disable_intentional_combat_mode(TRUE)
- 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
@@ -131,6 +127,7 @@
transfer_martial_arts(new_character)
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()
//CIT CHANGE - makes arousal update when transfering bodies
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm
index e474272326..d4db7e34c2 100644
--- a/code/datums/mutations/speech.dm
+++ b/code/datums/mutations/speech.dm
@@ -277,10 +277,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)
+ 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/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 32dde45195..fe617ddb0f 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -11,7 +11,7 @@
var/throw_range = 7
var/mob/pulledby = null
var/initial_language_holder = /datum/language_holder
- var/datum/language_holder/language_holder
+ var/datum/language_holder/language_holder // Mindless mobs and objects need language too, some times. Mind holder takes prescedence.
var/verb_say = "says"
var/verb_ask = "asks"
var/verb_exclaim = "exclaims"
@@ -502,88 +502,94 @@
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 procs
+* Unless you are doing something very specific, these are the ones you want to use.
+*/
+
+/// 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
+ return language_holder
-/atom/movable/proc/grant_language(datum/language/dt, body = FALSE)
- var/datum/language_holder/H = get_language_holder(!body)
- H.grant_language(dt, body)
+/// 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)
-/atom/movable/proc/grant_all_languages(omnitongue=FALSE)
- var/datum/language_holder/H = get_language_holder()
- H.grant_all_languages(omnitongue)
+/// 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
+
+/// 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()
+ var/datum/language_holder/LH = get_language_holder()
+ return LH.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)
+/// 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()
-/atom/movable/proc/remove_all_languages()
- var/datum/language_holder/H = get_language_holder()
- H.remove_all_languages()
+/// 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)
-/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
+/// 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/hologram.dm b/code/game/machinery/hologram.dm
index 067f10fa0f..3a79ff3c82 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -396,7 +396,6 @@ GLOBAL_LIST_EMPTY(network_holopads)
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.
@@ -555,9 +554,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.
@@ -649,7 +647,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
@@ -672,6 +670,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 4e3e11d1e2..a9b6736f05 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
)
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index 2daf6f0c0b..6648db46c4 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -6,17 +6,42 @@
icon_state = "cutout_basic"
w_class = WEIGHT_CLASS_BULKY
resistance_flags = FLAMMABLE
- // Possible restyles for the cutout;
- // add an entry in change_appearance() if you add to here
- var/list/possible_appearances = list("Assistant", "Clown", "Mime",
- "Traitor", "Nuke Op", "Cultist", "Brass Cultist", "Clockwork Cultist",
- "Revolutionary", "Wizard", "Shadowling", "Xenomorph", "Xenomorph Maid", "Swarmer",
- "Ash Walker", "Deathsquad Officer", "Ian", "Slaughter Demon",
- "Laughter Demon", "Private Security Officer", "Securitron", "Gondola", "Monkey")
- var/pushed_over = FALSE //If the cutout is pushed over and has to be righted
- var/deceptive = FALSE //If the cutout actually appears as what it portray and not a discolored version
+ /// Possible restyles for the cutout, add an entry in change_appearance() if you add to here
+ var/static/list/possible_appearances
+ /// If the cutout is pushed over and has to be righted
+ var/pushed_over = FALSE
+ /// If the cutout actually appears as what it portray and not a discolored version
+ var/deceptive = FALSE
- var/lastattacker = null
+/obj/item/cardboard_cutout/Initialize()
+ . = ..()
+ if(possible_appearances)
+ return
+ possible_appearances = sortList(list(
+ "Assistant" = image(icon = src.icon, icon_state = "cutout_greytide"),
+ "Clown" = image(icon = src.icon, icon_state = "cutout_clown"),
+ "Mime" = image(icon = src.icon, icon_state = "cutout_mime"),
+ "Traitor" = image(icon = src.icon, icon_state = "cutout_traitor"),
+ "Nuke Op" = image(icon = src.icon, icon_state = "cutout_fluke"),
+ "Cultist" = image(icon = src.icon, icon_state = "cutout_cultist"),
+ "Brass Cultist" = image(icon = src.icon, icon_state = "cutout_servant"),
+ "Clockwork Cultist" = image(icon = src.icon, icon_state = "cutout_new_servant"),
+ "Revolutionary" = image(icon = src.icon, icon_state = "cutout_viva"),
+ "Wizard" = image(icon = src.icon, icon_state = "cutout_wizard"),
+ "Shadowling" = image(icon = src.icon, icon_state = "cutout_shadowling"),
+ "Xenomorph" = image(icon = src.icon, icon_state = "cutout_fukken_xeno"),
+ "Xenomorph Maid" = image(icon = src.icon, icon_state = "cutout_lusty"),
+ "Swarmer" = image(icon = src.icon, icon_state = "cutout_swarmer"),
+ "Ash Walker" = image(icon = src.icon, icon_state = "cutout_free_antag"),
+ "Deathsquad Officer" = image(icon = src.icon, icon_state = "cutout_deathsquad"),
+ "Ian" = image(icon = src.icon, icon_state = "cutout_ian"),
+ "Slaughter Demon" = image(icon = 'icons/mob/mob.dmi', icon_state = "daemon"),
+ "Laughter Demon" = image(icon = 'icons/mob/mob.dmi', icon_state = "bowmon"),
+ "Private Security Officer" = image(icon = src.icon, icon_state = "cutout_ntsec"),
+ "Securitron" = image(icon = src.icon, icon_state = "cutout_law"),
+ "Gondola" = image(icon = src.icon, icon_state = "cutout_gondola"),
+ "Monkey" = image(icon = src.icon, icon_state = "cutout_monky"),
+ ))
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/cardboard_cutout/attack_hand(mob/living/user)
@@ -76,22 +101,21 @@
push_over()
return BULLET_ACT_HIT
+/**
+ * change_appearance: Changes a skin of the cardboard cutout based on a user's choice
+ *
+ * Arguments:
+ * * crayon The crayon used to change and recolor the cardboard cutout
+ * * user The mob choosing a skin of the cardboard cutout
+ */
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
- if(!crayon || !user)
- return
- if(pushed_over)
- to_chat(user, "Right [src] first!")
- return
- if(crayon.check_empty(user))
- return
- if(crayon.is_capped)
- to_chat(user, "Take the cap off first!")
- return
- var/new_appearance = input(user, "Choose a new appearance for [src].", "26th Century Deception") as null|anything in possible_appearances
- if(!new_appearance || !crayon || !user.canUseTopic(src))
+ var/new_appearance = show_radial_menu(user, src, possible_appearances, custom_check = CALLBACK(src, .proc/check_menu, user, crayon), radius = 36, require_near = TRUE)
+ if(!new_appearance)
return
if(!do_after(user, 10, FALSE, src, TRUE))
- return
+ return FALSE
+ if(!check_menu(user, crayon))
+ return FALSE
user.visible_message("[user] gives [src] a new look.", "Voila! You give [src] a new look.")
crayon.use_charges(1)
crayon.check_empty(user)
@@ -196,7 +220,33 @@
name = "monkey ([rand(1, 999)])"
desc = "A cardboard cutout of a monkey."
icon_state = "cutout_monky"
- return 1
+ else
+ return FALSE
+ return TRUE
+
+/**
+ * check_menu: Checks if we are allowed to interact with a radial menu
+ *
+ * Arguments:
+ * * user The mob interacting with a menu
+ * * crayon The crayon used to interact with a menu
+ */
+/obj/item/cardboard_cutout/proc/check_menu(mob/living/user, obj/item/toy/crayon/crayon)
+ if(!istype(user))
+ return FALSE
+ if(user.incapacitated())
+ return FALSE
+ if(pushed_over)
+ to_chat(user, "Right [src] first!")
+ return FALSE
+ if(!crayon || !user.is_holding(crayon))
+ return FALSE
+ if(crayon.check_empty(user))
+ return FALSE
+ if(crayon.is_capped)
+ to_chat(user, "Take the cap off first!")
+ return FALSE
+ return TRUE
/obj/item/cardboard_cutout/setDir(newdir)
dir = SOUTH
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 60b93d9461..897f452091 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -199,7 +199,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 171b5a465a..381257721e 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -519,7 +519,9 @@
S.name = name
S.ckey = C.ckey
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
S.AddElement(/datum/element/ghost_role_eligibility,penalize_on_ghost = TRUE)
START_PROCESSING(SSprocessing,src)
var/input = stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN)
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index ec443d4e48..9dbbb35862 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -850,12 +850,6 @@
-#define NODESIGN "None"
-#define NANOTRASEN "NanotrasenStandard"
-#define SYNDI "SyndiSnacks"
-#define HEART "Heart"
-#define SMILEY "SmileyFace"
-
/obj/item/storage/box/papersack
name = "paper sack"
desc = "A sack neatly crafted out of paper."
@@ -863,7 +857,18 @@
item_state = "paperbag_None"
resistance_flags = FLAMMABLE
foldable = null
- var/design = NODESIGN
+ /// A list of all available papersack reskins
+ var/list/papersack_designs = list()
+
+/obj/item/storage/box/papersack/Initialize(mapload)
+ . = ..()
+ papersack_designs = sortList(list(
+ "None" = image(icon = src.icon, icon_state = "paperbag_None"),
+ "NanotrasenStandard" = image(icon = src.icon, icon_state = "paperbag_NanotrasenStandard"),
+ "SyndiSnacks" = image(icon = src.icon, icon_state = "paperbag_SyndiSnacks"),
+ "Heart" = image(icon = src.icon, icon_state = "paperbag_Heart"),
+ "SmileyFace" = image(icon = src.icon, icon_state = "paperbag_SmileyFace")
+ ))
/obj/item/storage/box/papersack/update_icon_state()
if(contents.len == 0)
@@ -871,55 +876,64 @@
else
icon_state = "[item_state]_closed"
+
/obj/item/storage/box/papersack/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/pen))
- //if a pen is used on the sack, dialogue to change its design appears
- if(contents.len)
- to_chat(user, "You can't modify [src] with items still inside!")
- return
- var/list/designs = list(NODESIGN, NANOTRASEN, SYNDI, HEART, SMILEY, "Cancel")
- var/switchDesign = input("Select a Design:", "Paper Sack Design", designs[1]) in designs
- if(get_dist(usr, src) > 1)
- to_chat(usr, "You have moved too far away!")
- return
- var/choice = designs.Find(switchDesign)
- if(design == designs[choice] || designs[choice] == "Cancel")
- return 0
- to_chat(usr, "You make some modifications to [src] using your pen.")
- design = designs[choice]
- icon_state = "paperbag_[design]"
- item_state = "paperbag_[design]"
- switch(designs[choice])
- if(NODESIGN)
+ var/choice = show_radial_menu(user, src , papersack_designs, custom_check = CALLBACK(src, .proc/check_menu, user, W), radius = 36, require_near = TRUE)
+ if(!choice)
+ return FALSE
+ if(icon_state == "paperbag_[choice]")
+ return FALSE
+ switch(choice)
+ if("None")
desc = "A sack neatly crafted out of paper."
- if(NANOTRASEN)
+ if("NanotrasenStandard")
desc = "A standard Nanotrasen paper lunch sack for loyal employees on the go."
- if(SYNDI)
+ if("SyndiSnacks")
desc = "The design on this paper sack is a remnant of the notorious 'SyndieSnacks' program."
- if(HEART)
+ if("Heart")
desc = "A paper sack with a heart etched onto the side."
- if(SMILEY)
+ if("SmileyFace")
desc = "A paper sack with a crude smile etched onto the side."
- return 0
+ else
+ return FALSE
+ to_chat(user, "You make some modifications to [src] using your pen.")
+ icon_state = "paperbag_[choice]"
+ item_state = "paperbag_[choice]"
+ return FALSE
else if(W.get_sharpness())
if(!contents.len)
if(item_state == "paperbag_None")
user.show_message("You cut eyeholes into [src].", MSG_VISUAL)
new /obj/item/clothing/head/papersack(user.loc)
qdel(src)
- return 0
+ return FALSE
else if(item_state == "paperbag_SmileyFace")
user.show_message("You cut eyeholes into [src] and modify the design.", MSG_VISUAL)
new /obj/item/clothing/head/papersack/smiley(user.loc)
qdel(src)
- return 0
+ return FALSE
return ..()
-#undef NODESIGN
-#undef NANOTRASEN
-#undef SYNDI
-#undef HEART
-#undef SMILEY
+/**
+ * check_menu: Checks if we are allowed to interact with a radial menu
+ *
+ * Arguments:
+ * * user The mob interacting with a menu
+ * * P The pen used to interact with a menu
+ */
+/obj/item/storage/box/papersack/proc/check_menu(mob/user, obj/item/pen/P)
+ if(!istype(user))
+ return FALSE
+ if(user.incapacitated())
+ return FALSE
+ if(contents.len)
+ to_chat(user, "You can't modify [src] with items still inside!")
+ return FALSE
+ if(!P || !user.is_holding(P))
+ to_chat(user, "You need a pen to modify [src]!")
+ return FALSE
+ return TRUE
/obj/item/storage/box/ingredients //This box is for the randomly chosen version the chef spawns with, it shouldn't actually exist.
name = "ingredients box"
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 722f6178bc..ff59b85332 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -902,79 +902,57 @@
name = "hand of cards"
desc = "A number of cards not in a deck, customarily held in ones hand."
icon = 'icons/obj/toy.dmi'
- icon_state = "nanotrasen_hand2"
+ icon_state = "none"
w_class = WEIGHT_CLASS_TINY
var/list/currenthand = list()
var/choice = null
-
/obj/item/toy/cards/cardhand/attack_self(mob/user)
- user.set_machine(src)
+ var/list/handradial = list()
interact(user)
-/obj/item/toy/cards/cardhand/ui_interact(mob/user)
- . = ..()
- var/dat = "You have:
"
for(var/t in currenthand)
- dat += "A [t].
"
- dat += "Which card will you remove next?"
- var/datum/browser/popup = new(user, "cardhand", "Hand of Cards", 400, 240)
- popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
- popup.set_content(dat)
- popup.open()
+ handradial[t] = image(icon = src.icon, icon_state = "sc_[t]_[deckstyle]")
-
-/obj/item/toy/cards/cardhand/Topic(href, href_list)
- if(..())
- return
if(usr.stat || !ishuman(usr))
return
var/mob/living/carbon/human/cardUser = usr
- var/O = src
- if(href_list["pick"])
- if (cardUser.is_holding(src))
- var/choice = href_list["pick"]
- var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
- src.currenthand -= choice
- C.parentdeck = src.parentdeck
- C.cardname = choice
- C.apply_card_vars(C,O)
- C.pickup(cardUser)
- cardUser.put_in_hands(C)
- cardUser.visible_message("[cardUser] draws a card from [cardUser.p_their()] hand.", "You take the [C.cardname] from your hand.")
-
- interact(cardUser)
- if(src.currenthand.len < 3)
- src.icon_state = "[deckstyle]_hand2"
- else if(src.currenthand.len < 4)
- src.icon_state = "[deckstyle]_hand3"
- else if(src.currenthand.len < 5)
- src.icon_state = "[deckstyle]_hand4"
- if(src.currenthand.len == 1)
- var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(src.loc)
- N.parentdeck = src.parentdeck
- N.cardname = src.currenthand[1]
- N.apply_card_vars(N,O)
- qdel(src)
- N.pickup(cardUser)
- cardUser.put_in_hands(N)
- to_chat(cardUser, "You also take [currenthand[1]] and hold it.")
- cardUser << browse(null, "window=cardhand")
+ if(!(cardUser.mobility_flags & MOBILITY_USE))
return
+ var/O = src
+ var/choice = show_radial_menu(usr,src, handradial, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 36, require_near = TRUE)
+ if(!choice)
+ return FALSE
+ var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc)
+ currenthand -= choice
+ handradial -= choice
+ C.parentdeck = parentdeck
+ C.cardname = choice
+ C.apply_card_vars(C,O)
+ C.pickup(cardUser)
+ cardUser.put_in_hands(C)
+ cardUser.visible_message("[cardUser] draws a card from [cardUser.p_their()] hand.", "You take the [C.cardname] from your hand.")
+
+ interact(cardUser)
+ update_sprite()
+ if(length(currenthand) == 1)
+ var/obj/item/toy/cards/singlecard/N = new/obj/item/toy/cards/singlecard(loc)
+ N.parentdeck = parentdeck
+ N.cardname = currenthand[1]
+ N.apply_card_vars(N,O)
+ qdel(src)
+ N.pickup(cardUser)
+ cardUser.put_in_hands(N)
+ to_chat(cardUser, "You also take [currenthand[1]] and hold it.")
/obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params)
if(istype(C))
if(C.parentdeck == src.parentdeck)
src.currenthand += C.cardname
- user.visible_message("[user] adds a card to [user.p_their()] hand.", "You add the [C.cardname] to your hand.")
+ user.visible_message("[user] adds a card to [user.p_their()] hand.", "You add the [C.cardname] to your hand.")
qdel(C)
interact(user)
- if(currenthand.len > 4)
- src.icon_state = "[deckstyle]_hand5"
- else if(currenthand.len > 3)
- src.icon_state = "[deckstyle]_hand4"
- else if(currenthand.len > 2)
- src.icon_state = "[deckstyle]_hand3"
+ update_sprite(src)
else
to_chat(user, "You can't mix cards from other decks!")
else
@@ -983,7 +961,7 @@
/obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj)
..()
newobj.deckstyle = sourceobj.deckstyle
- newobj.icon_state = "[deckstyle]_hand2" // Another dumb hack, without this the hand is invisible (or has the default deckstyle) until another card is added.
+ update_sprite()
newobj.card_hitsound = sourceobj.card_hitsound
newobj.card_force = sourceobj.card_force
newobj.card_throwforce = sourceobj.card_throwforce
@@ -992,6 +970,31 @@
newobj.card_attack_verb = sourceobj.card_attack_verb
newobj.resistance_flags = sourceobj.resistance_flags
+/**
+ * check_menu: Checks if we are allowed to interact with a radial menu
+ *
+ * Arguments:
+ * * user The mob interacting with a menu
+ */
+/obj/item/toy/cards/cardhand/proc/check_menu(mob/living/user)
+ if(!istype(user))
+ return FALSE
+ if(user.incapacitated())
+ return FALSE
+ return TRUE
+
+/**
+ * This proc updates the sprite for when you create a hand of cards
+ */
+/obj/item/toy/cards/cardhand/proc/update_sprite()
+ cut_overlays()
+ var/overlay_cards = currenthand.len
+
+ var/k = overlay_cards == 2 ? 1 : overlay_cards - 2
+ for(var/i = k; i <= overlay_cards; i++)
+ var/card_overlay = image(icon=src.icon,icon_state="sc_[currenthand[i]]_[deckstyle]",pixel_x=(1-i+k)*3,pixel_y=(1-i+k)*3)
+ add_overlay(card_overlay)
+
/obj/item/toy/cards/singlecard
name = "card"
desc = "a card"
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index e794e12ad7..082c4bd723 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -32,6 +32,7 @@
new_spawn.undershirt = "Nude" //changing underwear/shirt/socks doesn't seem to function correctly right now because of some bug elsewhere?
new_spawn.socks = "Nude"
new_spawn.update_body(TRUE)
+ new_spawn.language_holder.selected_language = /datum/language/sylvan
//Ash walker eggs: Spawns in ash walker dens in lavaland. Ghosts become unbreathing lizards that worship the Necropolis and are advised to retrieve corpses to create more ash walkers.
@@ -63,10 +64,6 @@
else
to_chat(new_spawn, "You have been born outside of your natural home! Whether you decide to return home, or make due with your new home is your own decision.")
- new_spawn.grant_language(/datum/language/draconic)
- var/datum/language_holder/holder = new_spawn.get_language_holder()
- holder.selected_default_language = /datum/language/draconic
-
//Ash walkers on birth understand how to make bone bows, bone arrows and ashen arrows
new_spawn.mind.teach_crafting_recipe(/datum/crafting_recipe/bone_arrow)
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index b10ca8002c..38133d9089 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -32,7 +32,6 @@
/obj/structure/janitorialcart/proc/put_in_cart(obj/item/I, mob/user)
if(!user.transferItemToLoc(I, src))
return
- updateUsrDialog()
to_chat(user, "You put [I] into [src].")
return
@@ -96,70 +95,82 @@
. = ..()
if(.)
return
- user.set_machine(src)
- var/dat
+
+ var/list/items = list()
if(mybag)
- dat += "[mybag.name]
"
+ items += list("Trash bag" = image(icon = mybag.icon, icon_state = mybag.icon_state))
if(mymop)
- dat += "[mymop.name]
"
+ items += list("Mop" = image(icon = mymop.icon, icon_state = mymop.icon_state))
if(mybroom)
- dat += "[mybroom.name]
"
+ items += list("Broom" = image(icon = mybroom.icon, icon_state = mybroom.icon_state))
if(myspray)
- dat += "[myspray.name]
"
+ items += list("Spray bottle" = image(icon = myspray.icon, icon_state = myspray.icon_state))
if(myreplacer)
- dat += "[myreplacer.name]
"
- if(signs)
- dat += "[signs] sign\s
"
- var/datum/browser/popup = new(user, "janicart", name, 240, 160)
- popup.set_content(dat)
- popup.open()
+ items += list("Light replacer" = image(icon = myreplacer.icon, icon_state = myreplacer.icon_state))
+ var/obj/item/caution/sign = locate() in src
+ if(sign)
+ items += list("Sign" = image(icon = sign.icon, icon_state = sign.icon_state))
-
-/obj/structure/janitorialcart/Topic(href, href_list)
- if(!in_range(src, usr))
+ if(!length(items))
return
- if(!isliving(usr))
+ items = sortList(items)
+ var/pick = show_radial_menu(user, src, items, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 38, require_near = TRUE)
+ if(!pick)
return
- var/mob/living/user = usr
- if(href_list["garbage"])
- if(mybag)
+ switch(pick)
+ if("Trash bag")
+ if(!mybag)
+ return
user.put_in_hands(mybag)
to_chat(user, "You take [mybag] from [src].")
mybag = null
- if(href_list["mop"])
- if(mymop)
+ if("Mop")
+ if(!mymop)
+ return
user.put_in_hands(mymop)
to_chat(user, "You take [mymop] from [src].")
mymop = null
- if(href_list["broom"])
- if(mybroom)
+ if("Broom")
+ if(!mybroom)
+ return
user.put_in_hands(mybroom)
to_chat(user, "You take [mybroom] from [src].")
mybroom = null
- if(href_list["spray"])
- if(myspray)
+ if("Spray bottle")
+ if(!myspray)
+ return
user.put_in_hands(myspray)
to_chat(user, "You take [myspray] from [src].")
myspray = null
- if(href_list["replacer"])
- if(myreplacer)
+ if("Light replacer")
+ if(!myreplacer)
+ return
user.put_in_hands(myreplacer)
to_chat(user, "You take [myreplacer] from [src].")
myreplacer = null
- if(href_list["sign"])
- if(signs)
- var/obj/item/caution/Sign = locate() in src
- if(Sign)
- user.put_in_hands(Sign)
- to_chat(user, "You take \a [Sign] from [src].")
- signs--
- else
- WARNING("Signs ([signs]) didn't match contents")
- signs = 0
+ if("Sign")
+ if(signs <= 0)
+ return
+ user.put_in_hands(sign)
+ to_chat(user, "You take \a [sign] from [src].")
+ signs--
+ else
+ return
update_icon()
- updateUsrDialog()
+/**
+ * check_menu: Checks if we are allowed to interact with a radial menu
+ *
+ * Arguments:
+ * * user The mob interacting with a menu
+ */
+/obj/structure/janitorialcart/proc/check_menu(mob/living/user)
+ if(!istype(user))
+ return FALSE
+ if(user.incapacitated())
+ return FALSE
+ return TRUE
/obj/structure/janitorialcart/update_overlays()
. = ..()
diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm
index 53a1f609d1..f321498bfd 100644
--- a/code/game/objects/structures/ladders.dm
+++ b/code/game/objects/structures/ladders.dm
@@ -91,8 +91,13 @@
if (!is_ghost && !in_range(src, user))
return
+ var/list/tool_list = list(
+ "Up" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH),
+ "Down" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = SOUTH)
+ )
+
if (up && down)
- var/result = alert("Go up or down [src]?", "Ladder", "Up", "Down", "Cancel")
+ var/result = show_radial_menu(user, src, tool_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE)
if (!is_ghost && !in_range(src, user))
return // nice try
switch(result)
@@ -112,6 +117,11 @@
if(!is_ghost)
add_fingerprint(user)
+/obj/structure/ladder/proc/check_menu(mob/user)
+ if(user.incapacitated() || !user.Adjacent(src))
+ return FALSE
+ return TRUE
+
/obj/structure/ladder/attack_hand(mob/user)
. = ..()
if(.)
diff --git a/code/game/say.dm b/code/game/say.dm
index 5fa5a2b35d..187994f432 100644
--- a/code/game/say.dm
+++ b/code/game/say.dm
@@ -25,7 +25,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, atom/movable/source)
diff --git a/code/modules/antagonists/abductor/equipment/glands/slime.dm b/code/modules/antagonists/abductor/equipment/glands/slime.dm
index 53b8133528..2df4a1fab9 100644
--- a/code/modules/antagonists/abductor/equipment/glands/slime.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/slime.dm
@@ -10,7 +10,12 @@
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
owner.faction |= "slime"
- owner.grant_language(/datum/language/slime)
+ owner.grant_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
+
+/obj/item/organ/heart/gland/slime/Remove(mob/living/carbon/M, special = 0)
+ ..()
+ owner.faction -= "slime"
+ owner.remove_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
/obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "You feel nauseated!")
diff --git a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm
index 2e9d3c1788..0feb6dfa7e 100644
--- a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm
+++ b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm
@@ -20,7 +20,7 @@
var/poweron_feed = FALSE // Am I feeding?
var/poweron_masquerade = FALSE
// STATS
- var/bloodsucker_level
+ var/bloodsucker_level
var/bloodsucker_level_unspent = 1
var/regen_rate = 0.3 // How fast do I regenerate?
var/additional_regen // How much additional blood regen we gain from bonuses such as high blood.
@@ -209,7 +209,7 @@
// Physiology
CheckVampOrgans() // Heart, Eyes
// Language
- owner.current.grant_language(/datum/language/vampiric)
+ owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_BLOODSUCKER)
owner.hasSoul = FALSE // If false, renders the character unable to sell their soul.
owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles
// Disabilities
@@ -246,7 +246,7 @@
// Update Health
owner.current.setMaxHealth(100)
// Language
- owner.current.remove_language(/datum/language/vampiric)
+ owner.current.remove_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_BLOODSUCKER)
// Soul
if (owner.soulOwner == owner) // Return soul, if *I* own it.
owner.hasSoul = TRUE
@@ -649,10 +649,10 @@
return TRUE
// Check 3) If I am a BLOODSUCKER, then are they my Vassal?
if (mob_B && atom_V && (atom_V in mob_B.vassals))
- return TRUE
+ return TRUE
// Check 4) If we are both VASSAL, then do we have the same master?
if (atom_V && mob_V && atom_V.master == mob_V.master)
- return TRUE
+ return TRUE
return FALSE
@@ -710,7 +710,7 @@
invisibility = INVISIBILITY_ABSTRACT
/obj/screen/bloodsucker/proc/update_counter(value, valuecolor)
- invisibility = 0
+ invisibility = 0
/obj/screen/bloodsucker/blood_counter
icon = 'icons/mob/actions/bloodsucker.dmi'
@@ -758,7 +758,7 @@
/obj/screen/bloodsucker/sunlight_counter/update_counter(value, valuecolor)
..()
- maptext = "