diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 49be0a12c3b..58b8fbaa0f0 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -167,9 +167,13 @@ GLOBAL_VAR(syndicate_code_response) //Code response for traitors. /N */ -/proc/generate_code_phrase()//Proc is used for phrase and response in master_controller.dm +/proc/generate_code_phrase(return_list=FALSE)//Proc is used for phrase and response in master_controller.dm + + if(!return_list) + . = "" + else + . = list() - var/code_phrase = ""//What is returned when the proc finishes. var/words = pick(//How many words there will be. Minimum of two. 2, 4 and 5 have a lesser chance of being selected. 3 is the most likely. 50; 2, 200; 3, @@ -204,39 +208,39 @@ GLOBAL_VAR(syndicate_code_response) //Code response for traitors. switch(rand(1,2))//Mainly to add more options later. if(1) if(names.len&&prob(70)) - code_phrase += pick(names) + . += pick(names) else if(prob(10)) - code_phrase += pick(lizard_name(MALE),lizard_name(FEMALE)) + . += pick(lizard_name(MALE),lizard_name(FEMALE)) else - code_phrase += pick(pick(GLOB.first_names_male,GLOB.first_names_female)) - code_phrase += " " - code_phrase += pick(GLOB.last_names) + var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female)) + new_name += " " + new_name += pick(GLOB.last_names) + . += new_name if(2) - code_phrase += pick(get_all_jobs())//Returns a job. + . += pick(get_all_jobs())//Returns a job. safety -= 1 if(2) switch(rand(1,3))//Food, drinks, or things. Only selectable once. if(1) - code_phrase += lowertext(pick(drinks)) + . += lowertext(pick(drinks)) if(2) - code_phrase += lowertext(pick(foods)) + . += lowertext(pick(foods)) if(3) - code_phrase += lowertext(pick(locations)) + . += lowertext(pick(locations)) safety -= 2 if(3) switch(rand(1,4))//Abstract nouns, objects, adjectives, threats. Can be selected more than once. if(1) - code_phrase += lowertext(pick(nouns)) + . += lowertext(pick(nouns)) if(2) - code_phrase += lowertext(pick(objects)) + . += lowertext(pick(objects)) if(3) - code_phrase += lowertext(pick(adjectives)) + . += lowertext(pick(adjectives)) if(4) - code_phrase += lowertext(pick(threats)) - if(words==1) - code_phrase += "." - else - code_phrase += ", " - - return code_phrase + . += lowertext(pick(threats)) + if(!return_list) + if(words==1) + . += "." + else + . += ", " diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm new file mode 100644 index 00000000000..da915435e5c --- /dev/null +++ b/code/modules/language/codespeak.dm @@ -0,0 +1,69 @@ +/datum/language/common/codespeak + name = "Codespeak" + desc = "Syndicate operatives can use a series of codewords to convey complex information, while sounding like random concepts and drinks to anyone listening in." + key = "t" + default_priority = 0 + +/datum/language/common/codespeak/scramble(input) + var/lookup = check_cache(input) + if(lookup) + return lookup + + . = "" + var/list/words = list() + while(length(.) < length(input)) + words += generate_code_phrase(return_list=TRUE) + . = jointext(words, ", ") + + add_to_cache(input, .) + +/obj/item/weapon/codespeak_manual + name = "codespeak manual" + desc = "The book's cover reads: \"Codespeak(tm) - Secure your communication with metaphors so elaborate, they seem randomly generated!\"" + icon = 'icons/obj/library.dmi' + icon_state = "book2" + var/charges = 1 + +/obj/item/weapon/codespeak_manual/attack_self(mob/living/user) + if(!isliving(user)) + return + + if(user.has_language(/datum/language/common/codespeak)) + to_chat(user, "You start skimming through [src], but you already know Codespeak.") + return + + to_chat(user, "You start skimming through [src], and suddenly your mind is filled with codewords and responses.") + user.grant_language(/datum/language/common/codespeak) + + use_charge() + +/obj/item/weapon/codespeak_manual/attack(mob/living/M, mob/living/user) + if(!istype(M) || !istype(user)) + return + playsound(loc, "punch", 25, 1, -1) + + if(M.stat == DEAD) + M.visible_message("[user] smacks [M]'s lifeless corpse with [src].", "[user] smacks your lifeless corpse with [src].", "You hear smacking.") + else if(M.has_language(/datum/language/common/codespeak)) + 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 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/common/codespeak) + +/obj/item/weapon/codespeak_manual/proc/use_charge() + charges-- + if(!charges) + say("Automatic data erasure in progress!") + visible_message("The cover and contents of [src] start shifting and changing!") + + var/obj/item/weapon/book/random/newbook = new(get_turf(src)) + qdel(src) + + if(ismob(loc)) + var/mob/M = loc + if(M.is_holding(src)) + M.put_in_active_hand(newbook) + +/obj/item/weapon/codespeak_manual/unlimited + name = "deluxe codespeak manual" + charges = INFINITY diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm index 55a57de9941..7e7e5bc20d2 100644 --- a/code/modules/language/language.dm +++ b/code/modules/language/language.dm @@ -56,16 +56,27 @@ return "[trim(full_name)]" +/datum/language/proc/check_cache(input) + var/lookup = scramble_cache[input] + if(lookup) + scramble_cache -= input + scramble_cache[input] = lookup + . = lookup + +/datum/language/proc/add_to_cache(input, scrambled_text) + // Add it to cache, cutting old entries if the list is too long + scramble_cache[input] = scrambled_text + if(scramble_cache.len > SCRAMBLE_CACHE_LEN) + scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) + /datum/language/proc/scramble(input) if(!syllables || !syllables.len) return stars(input) // If the input is cached already, move it to the end of the cache and return it - var/lookup = scramble_cache[input] + var/lookup = check_cache(input) if(lookup) - scramble_cache -= input - scramble_cache[input] = lookup return lookup var/input_size = length(input) @@ -93,10 +104,7 @@ if(input_ending in list("!","?",".")) scrambled_text += input_ending - // Add it to cache, cutting old entries if the list is too long - scramble_cache[input] = scrambled_text - if(scramble_cache.len > SCRAMBLE_CACHE_LEN) - scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1) + add_to_cache(input, scrambled_text) return scrambled_text diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm index 71a530a8fb9..5141cda8970 100644 --- a/code/modules/uplink/uplink_item.dm +++ b/code/modules/uplink/uplink_item.dm @@ -1127,6 +1127,19 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once. item = /obj/item/device/jammer cost = 5 +/datum/uplink_item/device_tools/codespeak_manual + name = "Codespeak Manual" + desc = "Syndicate agents can be trained to use a series of codewords to comvey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. One use." + item = /obj/item/weapon/codespeak_manual + cost = 2 + exclude_modes = list(/datum/game_mode/nuclear) + +/datum/uplink_item/device_tools/codespeak_manual_deluxe + name = "Deluxe Codespeak Manual" + desc = "Syndicate agents can be trained to use a series of codewords to comvey complex information, which sounds like random concepts and drinks to anyone listening. This manual teaches you this Codespeak. You can also hit someone else with the manual in order to teach them. This is the deluxe edition, which has unlimited uses." + cost = 8 + include_modes = list(/datum/game_mode/nuclear) + // Implants /datum/uplink_item/implants category = "Implants" diff --git a/tgstation.dme b/tgstation.dme index dbf28d5ceb0..f4c0a14b3ee 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1379,6 +1379,7 @@ #include "code\modules\jobs\job_types\security.dm" #include "code\modules\jobs\job_types\silicon.dm" #include "code\modules\jobs\map_changes\map_changes.dm" +#include "code\modules\language\codespeak.dm" #include "code\modules\language\common.dm" #include "code\modules\language\draconic.dm" #include "code\modules\language\drone.dm"