From d8d1670b68b76a602c3df8ea2731656b5f35b2ac Mon Sep 17 00:00:00 2001 From: Markolie Date: Fri, 20 Feb 2015 17:46:35 +0100 Subject: [PATCH] Revert "Revert "Saycode/language/species port from Bay"" This reverts commit d54579850c71f193da9f87b727c5b3e9c27c6c53. Conflicts: code/game/gamemodes/nuclear/nuclearbomb.dm code/game/objects/items/devices/radio/intercom.dm code/modules/mob/living/silicon/pai/pai.dm --- code/__HELPERS/game.dm | 55 +- code/__HELPERS/global_lists.dm | 8 + code/__HELPERS/mobs.dm | 20 +- code/__HELPERS/text.dm | 3 +- code/_onclick/observer.dm | 9 +- code/controllers/communications.dm | 83 ++- code/controllers/configuration.dm | 2 +- code/datums/wires/radio.dm | 21 +- code/defines/procs/radio.dm | 81 +++ code/game/area/Space Station 13 areas.dm | 1 + code/game/dna/dna2_domutcheck.dm | 9 + code/game/dna/genes/goon_disabilities.dm | 2 +- code/game/dna/genes/goon_powers.dm | 6 +- code/game/gamemodes/changeling/changeling.dm | 11 +- .../gamemodes/changeling/evolution_menu.dm | 16 +- .../gamemodes/changeling/powers/absorb.dm | 2 +- .../gamemodes/changeling/powers/humanform.dm | 2 +- .../gamemodes/changeling/powers/lesserform.dm | 2 +- .../gamemodes/changeling/powers/transform.dm | 2 + code/game/gamemodes/events/ninja_equipment.dm | 16 +- code/game/gamemodes/nuclear/nuclear.dm | 32 + code/game/gamemodes/nuclear/nuclearbomb.dm | 31 +- code/game/gamemodes/objective.dm | 6 +- code/game/gamemodes/setupgame.dm | 16 - code/game/machinery/bots/bots.dm | 9 +- code/game/machinery/bots/cleanbot.dm | 1 - code/game/machinery/bots/ed209bot.dm | 3 +- code/game/machinery/bots/floorbot.dm | 3 +- code/game/machinery/bots/medbot.dm | 3 +- code/game/machinery/bots/mulebot.dm | 12 +- code/game/machinery/bots/secbot.dm | 4 +- code/game/machinery/camera/tracking.dm | 2 +- code/game/machinery/hologram.dm | 15 +- code/game/machinery/telecomms/broadcaster.dm | 291 ++------ code/game/objects/items/devices/paicard.dm | 17 +- .../objects/items/devices/radio/headset.dm | 2 +- .../game/objects/items/devices/radio/radio.dm | 619 +++++++----------- .../objects/items/devices/transfer_valve.dm | 4 + .../objects/items/robot/robot_upgrades.dm | 4 +- code/game/objects/structures/girders.dm | 429 ++++++------ code/game/vehicles/vehicle.dm | 4 +- code/modules/admin/admin_verbs.dm | 2 +- code/modules/awaymissions/corpse.dm | 1 - .../awaymissions/mission_code/academy.dm | 1 + .../mission_code/blackmarketpackers.dm | 2 +- .../awaymissions/mission_code/centcomAway.dm | 3 +- .../awaymissions/mission_code/challenge.dm | 5 + .../awaymissions/mission_code/clownplanet.dm | 1 + .../awaymissions/mission_code/spacebattle.dm | 1 + .../mission_code/stationCollision.dm | 3 + code/modules/client/preferences_toggles.dm | 10 + code/modules/clothing/masks/gasmask.dm | 38 -- code/modules/clothing/masks/voice.dm | 59 ++ code/modules/karma/karma.dm | 4 +- code/modules/mining/laborcamp/laborstacker.dm | 24 +- code/modules/mob/dead/observer/observer.dm | 17 + code/modules/mob/hear_say.dm | 215 ++++++ code/modules/mob/language.dm | 399 +++++++++-- .../living/carbon/alien/humanoid/humanoid.dm | 2 + .../mob/living/carbon/alien/larva/larva.dm | 2 + code/modules/mob/living/carbon/alien/say.dm | 79 +-- code/modules/mob/living/carbon/brain/brain.dm | 5 +- code/modules/mob/living/carbon/brain/say.dm | 28 +- code/modules/mob/living/carbon/human/human.dm | 130 ++-- .../mob/living/carbon/human/human_damage.dm | 7 +- .../mob/living/carbon/human/human_defines.dm | 4 + code/modules/mob/living/carbon/human/life.dm | 54 +- code/modules/mob/living/carbon/human/say.dm | 331 +++++++--- .../mob/living/carbon/human/update_icons.dm | 9 +- .../mob/living/carbon/human/whisper.dm | 182 ++--- code/modules/mob/living/carbon/metroid/say.dm | 13 + code/modules/mob/living/carbon/species.dm | 122 +++- code/modules/mob/living/say.dm | 528 +++------------ code/modules/mob/living/silicon/ai/ai.dm | 15 + .../mob/living/silicon/ai/freelook/eye.dm | 4 +- code/modules/mob/living/silicon/ai/say.dm | 30 +- code/modules/mob/living/silicon/pai/pai.dm | 14 +- .../mob/living/silicon/pai/software.dm | 36 +- .../mob/living/silicon/robot/component.dm | 5 + .../mob/living/silicon/robot/drone/drone.dm | 80 +-- .../modules/mob/living/silicon/robot/robot.dm | 43 +- .../mob/living/silicon/robot/robot_modules.dm | 33 + code/modules/mob/living/silicon/say.dm | 284 ++++---- code/modules/mob/living/silicon/silicon.dm | 36 + .../modules/mob/living/simple_animal/borer.dm | 41 +- .../mob/living/simple_animal/parrot.dm | 127 ++-- .../mob/living/simple_animal/simple_animal.dm | 22 + code/modules/mob/mob.dm | 1 + code/modules/mob/mob_helpers.dm | 46 ++ code/modules/mob/new_player/new_player.dm | 40 +- code/modules/mob/say.dm | 164 +++-- code/modules/mob/typing_indicator.dm | 85 +++ code/modules/paperwork/faxmachine.dm | 6 +- .../research/designs/machine_designs.dm | 2 +- code/modules/surgery/headreattach.dm | 2 +- code/setup.dm | 16 +- code/stylesheet.dm | 9 + config/example/config.txt | 2 +- icons/mob/human_races/r_golem.dmi | Bin 0 -> 11595 bytes icons/mob/human_races/r_shadow.dmi | Bin 0 -> 1760 bytes icons/mob/human_races/r_slime.dmi | Bin 0 -> 4614 bytes icons/mob/talk.dmi | Bin 2190 -> 2403 bytes icons/obj/robot_storage.dmi | Bin 5159 -> 5078 bytes interface/interface.dm | 2 +- interface/skin.dmf | 14 +- maps/cyberiad.dmm | 2 +- nano/images/uiBackground-Syndicate.png | Bin 37520 -> 213007 bytes nano/images/uiTitleFluff-Syndicate.png | Bin 38450 -> 1429 bytes paradise.dme | 4 + 109 files changed, 2955 insertions(+), 2349 deletions(-) create mode 100644 code/defines/procs/radio.dm create mode 100644 code/modules/clothing/masks/voice.dm create mode 100644 code/modules/mob/hear_say.dm create mode 100644 code/modules/mob/typing_indicator.dm create mode 100644 icons/mob/human_races/r_golem.dmi create mode 100644 icons/mob/human_races/r_shadow.dmi create mode 100644 icons/mob/human_races/r_slime.dmi diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index a692639d802..a47f261f9c1 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -167,8 +167,6 @@ // The old system would loop through lists for a total of 5000 per function call, in an empty server. // This new system will loop at around 1000 in an empty server. -// SCREW THAT SHIT, we're not recursing. - /proc/get_mobs_in_view(var/R, var/atom/source) // Returns a list of mobs in range of R from source. Used in radio and say code. @@ -180,48 +178,40 @@ var/list/range = hear(R, T) - for(var/mob/M in range) - hear += M + for(var/atom/A in range) + if(ismob(A)) + var/mob/M = A + if(M.client) + hear += M + //world.log << "Start = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])" + else if(istype(A, /obj/item/device/radio)) + hear += A - var/list/objects = list() + if(isobj(A) || ismob(A)) + hear |= recursive_mob_check(A, hear, 3, 1, 0, 1) - for(var/obj/O in range) //Get a list of objects in hearing range. We'll check to see if any clients have their "eye" set to the object - objects += O - - for(var/client/C in clients) - if(!istype(C) || !C.eye || istype(C.eye, /mob/aiEye)) - continue //I have no idea when this client check would be needed, but if this runtimes people won't hear anything - //So kinda paranoid about runtime avoidance. - if(istype(C.eye, /obj/machinery/camera)) - continue //No microphones in cameras. - - if(C.mob in hear) - continue - - var/list/hear_and_objects = (hear|objects) //Combined these lists here instead of doing the combine 3 more times. - - if(C.eye in hear_and_objects) - hear += C.mob - - else if(C.mob && C.mob.loc in hear_and_objects) - hear += C.mob - else if(C.mob && C.mob.loc.loc in hear_and_objects) - hear += C.mob - else if(C.mob && C.mob.loc.loc.loc in hear_and_objects) - hear += C.mob return hear /proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios) - //set background = 1 + set background = 1 . = list() // Returns a list of mobs who can hear any of the radios given in @radios var/list/speaker_coverage = list() - for(var/i = 1; i <= radios.len; i++) - var/obj/item/device/radio/R = radios[i] + for(var/obj/item/device/radio/R in radios) if(R) + //Cyborg checks. Receiving message uses a bit of cyborg's charge. + var/obj/item/device/radio/borg/BR = R + if(istype(BR) && BR.myborg) + var/mob/living/silicon/robot/borg = BR.myborg + var/datum/robot_component/CO = borg.get_component("radio") + if(!CO) + continue //No radio component (Shouldn't happen) + if(!borg.is_component_functioning("radio") || !borg.use_power(CO.energy_consumption)) + continue //No power. + var/turf/speaker = get_turf(R) if(speaker) for(var/turf/T in hear(R.canhear_range,speaker)) @@ -239,6 +229,7 @@ . |= M // Since we're already looping through mobs, why bother using |= ? This only slows things down. return . + #define SIGN(X) ((X<0)?-1:1) proc diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 515f1788f66..441e48139c8 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -28,6 +28,7 @@ var/global/list/airlocks = list() //list of all airlocks //Languages/species/whitelist. var/global/list/all_species[0] var/global/list/all_languages[0] +var/global/list/language_keys[0] // Table of say codes for all languages var/global/list/all_nations[0] var/global/list/whitelisted_species = list() @@ -114,6 +115,13 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al var/datum/language/L = new T all_languages[L.name] = L + for (var/language_name in all_languages) + var/datum/language/L = all_languages[language_name] + if(!(L.flags & NONGLOBAL)) + language_keys[":[lowertext(L.key)]"] = L + language_keys[".[lowertext(L.key)]"] = L + language_keys["#[lowertext(L.key)]"] = L + var/rkey = 0 paths = typesof(/datum/species)-/datum/species for(var/T in paths) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index a790124c152..320e2ecd8d7 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -49,15 +49,19 @@ proc/random_facial_hair_style(gender, species = "Human") return f_style -proc/random_name(gender, speciesName = "Human") - var/datum/species/S = all_species[speciesName] - if(S) - return S.makeName(gender) - else - if(gender==FEMALE) +proc/random_name(gender, species = "Human") + + var/datum/species/current_species + if(species) + current_species = all_species[species] + + if(!current_species || current_species.name == "Human") + if(gender==FEMALE) return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) - else - return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) + else + return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) + else + return current_species.get_random_name(gender) proc/random_skin_tone() switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino")) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index cb2fad75ddb..108246c5ad5 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -341,4 +341,5 @@ proc/checkhtml(var/t) return sanitize(input) /proc/trim_strip_html_properly(var/input, var/max_length = MAX_MESSAGE_LEN) - return trim(strip_html_properly(input, max_length)) + return trim(strip_html_properly(input, max_length)) + \ No newline at end of file diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index d8b5617d2a1..210140bdf9f 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -64,10 +64,11 @@ // Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu /obj/machinery/teleport/hub/attack_ghost(mob/user as mob) - var/atom/l = loc - var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z)) - if(com && com.locked) - user.loc = get_turf(com.locked) + var/obj/machinery/teleport/station/S = power_station + if(S) + var/obj/machinery/computer/teleporter/com = S.teleporter_console + if(com && com.target) + user.loc = get_turf(com.target) /obj/effect/portal/attack_ghost(mob/user as mob) if(target) diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index b3a5a9f58d1..523cc7055b9 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -124,30 +124,14 @@ On the map: 1455 for AI access */ -var/list/radiochannels = list( - "Common" = 1459, - "Science" = 1351, - "Command" = 1353, - "Medical" = 1355, - "Engineering" = 1357, - "Security" = 1359, - "Response Team" = 1443, - "Deathsquad" = 1441, - "Syndicate" = 1213, - "Supply" = 1347, - "Service" = 1349, - "AI Private" = 1447 -) -//depenging helpers -var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1443, 1441, 1347, 1349) - -// central command channels, i.e deathsquid & response teams -var/list/CENT_FREQS = list(1441, 1443) - -var/const/COMM_FREQ = 1353 //command, colored gold in chat window +var/const/COMM_FREQ = 1353 var/const/SYND_FREQ = 1213 +var/const/ERT_FREQ = 1345 +var/const/DTH_FREQ = 1341 +var/const/AI_FREQ = 1447 // department channels +var/const/PUB_FREQ = 1459 var/const/SEC_FREQ = 1359 var/const/ENG_FREQ = 1357 var/const/SCI_FREQ = 1351 @@ -155,12 +139,65 @@ var/const/MED_FREQ = 1355 var/const/SUP_FREQ = 1347 var/const/SRV_FREQ = 1349 -// other channels -var/const/AIPRIV_FREQ = 1447 +var/list/radiochannels = list( + "Common" = PUB_FREQ, + "Science" = SCI_FREQ, + "Command" = COMM_FREQ, + "Medical" = MED_FREQ, + "Engineering" = ENG_FREQ, + "Security" = SEC_FREQ, + "Response Team" = ERT_FREQ, + "Special Ops" = DTH_FREQ, + "Syndicate" = SYND_FREQ, + "Supply" = SUP_FREQ, + "Service" = SRV_FREQ, + "AI Private" = AI_FREQ +) + +// central command channels, i.e deathsquid & response teams +var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ) + +// Antag channels, i.e. Syndicate +var/list/ANTAG_FREQS = list(SYND_FREQ) + +//depending helpers +var/list/DEPT_FREQS = list(SCI_FREQ, MED_FREQ, ENG_FREQ, SEC_FREQ, SUP_FREQ, SRV_FREQ, ERT_FREQ, SYND_FREQ, DTH_FREQ) #define TRANSMISSION_WIRE 0 #define TRANSMISSION_RADIO 1 +/proc/frequency_span_class(var/frequency) + // Antags! + if (frequency in ANTAG_FREQS) + return "syndradio" + // centcomm channels (deathsquid and ert) + else if(frequency in CENT_FREQS) + return "centradio" + // command channel + else if(frequency == COMM_FREQ) + return "comradio" + // AI private channel + else if(frequency == AI_FREQ) + return "airadio" + // department radio formatting (poorly optimized, ugh) + else if(frequency == SEC_FREQ) + return "secradio" + else if (frequency == ENG_FREQ) + return "engradio" + else if(frequency == SCI_FREQ) + return "sciradio" + else if(frequency == MED_FREQ) + return "medradio" + else if(frequency == SUP_FREQ) // cargo + return "supradio" + else if(frequency == SRV_FREQ) // service + return "srvradio" + // If all else fails and it's a dept_freq, color me purple! + else if(frequency in DEPT_FREQS) + return "deptradio" + + return "radio" + /* filters */ var/const/RADIO_TO_AIRALARM = "1" var/const/RADIO_FROM_AIRALARM = "2" diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 160137a2e5b..062a650c9ba 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -138,7 +138,7 @@ var/list/station_levels = list(1) // Defines which Z-levels the station exists on. var/list/admin_levels= list(2) // Defines which Z-levels which are for admin functionality, for example including such areas as Central Command and the Syndicate Shuttle var/list/contact_levels = list(1, 5) // Defines which Z-levels which, for example, a Code Red announcement may affect - var/list/player_levels = list(1, 3, 4, 5, 6) // Defines all Z-levels a character can typically reach + var/list/player_levels = list(1, 3, 4, 5, 6, 7) // Defines all Z-levels a character can typically reach var/const/minutes_to_ticks = 60 * 10 // Event settings diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm index a8171270008..9da8890ac32 100644 --- a/code/datums/wires/radio.dm +++ b/code/datums/wires/radio.dm @@ -21,11 +21,24 @@ var/const/WIRE_TRANSMIT = 4 var/obj/item/device/radio/R = holder switch(index) if(WIRE_SIGNAL) - R.listening = !R.listening - R.broadcasting = R.listening + R.listening = !R.listening && !IsIndexCut(WIRE_RECEIVE) + R.broadcasting = R.listening && !IsIndexCut(WIRE_TRANSMIT) if(WIRE_RECEIVE) - R.listening = !R.listening + R.listening = !R.listening && !IsIndexCut(WIRE_SIGNAL) if(WIRE_TRANSMIT) - R.broadcasting = !R.broadcasting \ No newline at end of file + R.broadcasting = !R.broadcasting && !IsIndexCut(WIRE_SIGNAL) + +/datum/wires/radio/UpdateCut(var/index, var/mended) + var/obj/item/device/radio/R = holder + switch(index) + if(WIRE_SIGNAL) + R.listening = mended && !IsIndexCut(WIRE_RECEIVE) + R.broadcasting = mended && !IsIndexCut(WIRE_TRANSMIT) + + if(WIRE_RECEIVE) + R.listening = mended && !IsIndexCut(WIRE_SIGNAL) + + if(WIRE_TRANSMIT) + R.broadcasting = mended && !IsIndexCut(WIRE_SIGNAL) diff --git a/code/defines/procs/radio.dm b/code/defines/procs/radio.dm new file mode 100644 index 00000000000..1e0e045928b --- /dev/null +++ b/code/defines/procs/radio.dm @@ -0,0 +1,81 @@ +#define TELECOMMS_RECEPTION_NONE 0 +#define TELECOMMS_RECEPTION_SENDER 1 +#define TELECOMMS_RECEPTION_RECEIVER 2 +#define TELECOMMS_RECEPTION_BOTH 3 + +/proc/get_frequency_name(var/display_freq) + var/freq_text + + // the name of the channel + if(display_freq in ANTAG_FREQS) + freq_text = "#unkn" + else + for(var/channel in radiochannels) + if(radiochannels[channel] == display_freq) + freq_text = channel + break + + // --- If the frequency has not been assigned a name, just use the frequency as the name --- + if(!freq_text) + freq_text = format_frequency(display_freq) + + return freq_text + +/datum/reception + var/obj/machinery/message_server/message_server = null + var/telecomms_reception = TELECOMMS_RECEPTION_NONE + var/message = "" + +/datum/receptions + var/obj/machinery/message_server/message_server = null + var/sender_reception = TELECOMMS_RECEPTION_NONE + var/list/receiver_reception = new + +/proc/get_message_server() + if(message_servers) + for (var/obj/machinery/message_server/MS in message_servers) + if(MS.active) + return MS + return null + +/proc/check_signal(var/datum/signal/signal) + return signal && signal.data["done"] + +/proc/get_sender_reception(var/atom/sender, var/datum/signal/signal) + return check_signal(signal) ? TELECOMMS_RECEPTION_SENDER : TELECOMMS_RECEPTION_NONE + +/proc/get_receiver_reception(var/receiver, var/datum/signal/signal) + if(receiver && check_signal(signal)) + var/turf/pos = get_turf(receiver) + if(pos && (pos.z in signal.data["level"])) + return TELECOMMS_RECEPTION_RECEIVER + return TELECOMMS_RECEPTION_NONE + +/proc/get_reception(var/atom/sender, var/receiver, var/message = "", var/do_sleep = 1) + var/datum/reception/reception = new + + // check if telecomms I/O route 1459 is stable + reception.message_server = get_message_server() + + var/datum/signal/signal = sender.telecomms_process(do_sleep) // Be aware that this proc calls sleep, to simulate transmition delays + reception.telecomms_reception |= get_sender_reception(sender, signal) + reception.telecomms_reception |= get_receiver_reception(receiver, signal) + reception.message = signal && signal.data["compression"] > 0 ? Gibberish(message, signal.data["compression"] + 50) : message + + return reception + +/proc/get_receptions(var/atom/sender, var/list/atom/receivers, var/do_sleep = 1) + var/datum/receptions/receptions = new + receptions.message_server = get_message_server() + + var/datum/signal/signal + if(sender) + signal = sender.telecomms_process(do_sleep) + receptions.sender_reception = get_sender_reception(sender, signal) + + for(var/atom/receiver in receivers) + if(!signal) + signal = receiver.telecomms_process() + receptions.receiver_reception[receiver] = get_receiver_reception(receiver, signal) + + return receptions diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 43c52ec018c..7d5547f3c45 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -2268,6 +2268,7 @@ area/security/podbay /area/awaycontent name = "space" + report_alerts = 0 /area/awaycontent/a1 icon_state = "awaycontent1" diff --git a/code/game/dna/dna2_domutcheck.dm b/code/game/dna/dna2_domutcheck.dm index 6f0e3412f19..545e65b691d 100644 --- a/code/game/dna/dna2_domutcheck.dm +++ b/code/game/dna/dna2_domutcheck.dm @@ -5,6 +5,7 @@ // flags: See below, bitfield. #define MUTCHK_FORCED 1 /proc/domutcheck(var/mob/living/M, var/connected=null, var/flags=0) + for(var/datum/dna/gene/gene in dna_genes) if(!M || !M.dna) return @@ -75,6 +76,14 @@ var/gene_active = (gene.flags & GENE_ALWAYS_ACTIVATE) if(!gene_active) gene_active = M.dna.GetSEState(gene.block) + + var/defaultgenes // Do not mutate inherent species abilities + if(ishuman(M)) + var/mob/living/carbon/human/H = M + defaultgenes = H.species.default_genes + + if((gene in defaultgenes) && gene_active) + return // Prior state var/gene_prior_status = (gene.type in M.active_genes) diff --git a/code/game/dna/genes/goon_disabilities.dm b/code/game/dna/genes/goon_disabilities.dm index 5de6a0c35c3..1214919a441 100644 --- a/code/game/dna/genes/goon_disabilities.dm +++ b/code/game/dna/genes/goon_disabilities.dm @@ -335,7 +335,7 @@ if(L) usr.attack_log += text("\[[time_stamp()]\] [usr.real_name] ([usr.ckey]) cast the spell [name] on [L.real_name] ([L.ckey]).") - msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast the spell [name] on [L.real_name] ([L.ckey]) (JMP)") + msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast the spell [name] on [L.real_name] ([L.ckey]) (JMP)") L.adjust_fire_stacks(0.5) L.visible_message("\red [L.name] suddenly bursts into flames!") diff --git a/code/game/dna/genes/goon_powers.dm b/code/game/dna/genes/goon_powers.dm index 5ded91894bf..00a7879906f 100644 --- a/code/game/dna/genes/goon_powers.dm +++ b/code/game/dna/genes/goon_powers.dm @@ -162,12 +162,12 @@ H.visible_message("\red [usr] sprays a cloud of fine ice crystals, engulfing [H]!", "[usr] sprays a cloud of fine ice crystals over your [H.head]'s visor.") log_admin("[ckey(usr.key)] has used cryokinesis on [ckey(C.key)], internals yes, suit yes") - msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") + msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") else H.visible_message("\red [usr] sprays a cloud of fine ice crystals engulfing, [H]!", "[usr] sprays a cloud of fine ice crystals cover your [H.head]'s visor and make it into your air vents!.") log_admin("[usr.real_name] ([ckey(usr.key)]) has used cryokinesis on [C.real_name] ([ckey(C.key)]), ()") - msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") + msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") H.bodytemperature = max(0, H.bodytemperature - 50) H.adjustFireLoss(5) if(!handle_suit) @@ -177,7 +177,7 @@ C.visible_message("\red [usr] sprays a cloud of fine ice crystals, engulfing [C]!") log_admin("[ckey(usr.key)] has used cryokinesis on [ckey(C.key)], internals no, suit no") - msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") + msg_admin_attack("[usr.real_name] ([usr.ckey]) has cast cryokinesis on [C.real_name] ([C.ckey]), (JMP)") //playsound(usr.loc, 'bamf.ogg', 50, 0) diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index 76d198d796f..d981da20efe 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -310,13 +310,4 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" user << "We already have this DNA in storage!" return 1 - -//More snowflake stuff, but for languages. -/datum/changeling/proc/changeling_update_languages(var/updated_languages, var/mob/living/carbon/user) - if(!istype(user) || !user) - return - user.languages = list() - for(var/language in updated_languages) - user.languages += language - - return \ No newline at end of file + \ No newline at end of file diff --git a/code/game/gamemodes/changeling/evolution_menu.dm b/code/game/gamemodes/changeling/evolution_menu.dm index 370a65d42a0..32ab8473d66 100644 --- a/code/game/gamemodes/changeling/evolution_menu.dm +++ b/code/game/gamemodes/changeling/evolution_menu.dm @@ -360,10 +360,11 @@ var/list/sting_paths sting_paths = init_subtypes(/obj/effect/proc_holder/changeling) if(mind.changeling.purchasedpowers) remove_changeling_powers(1) + + add_language("Changeling") for(var/language in languages) - if(!(language in mind.changeling.absorbed_languages)) - mind.changeling.absorbed_languages += language + mind.changeling.absorbed_languages |= language // purchase free powers. for(var/obj/effect/proc_holder/changeling/path in sting_paths) @@ -376,6 +377,17 @@ var/list/sting_paths var/mob/living/carbon/C = src //only carbons have dna now, so we have to typecaste mind.changeling.absorbed_dna |= C.dna return 1 + +//Used to dump the languages from the changeling datum into the actual mob. +/mob/proc/changeling_update_languages(var/updated_languages) + + for(var/datum/language/L in updated_languages) + add_language("L.name") + + //This isn't strictly necessary but just to be safe... + add_language("Changeling") + + return /datum/changeling/proc/reset() chosen_sting = null diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm index 6acb6e5a66d..bb9785286dc 100644 --- a/code/game/gamemodes/changeling/powers/absorb.dm +++ b/code/game/gamemodes/changeling/powers/absorb.dm @@ -94,7 +94,7 @@ for(var/language in T.languages) if(!(language in absorbed_languages)) absorbed_languages += language - changeling_update_languages(absorbed_languages, user) + T.changeling_update_languages(absorbed_languages) absorbedcount++ store_dna(new_dna, user) diff --git a/code/game/gamemodes/changeling/powers/humanform.dm b/code/game/gamemodes/changeling/powers/humanform.dm index 81828120875..42e0bb3dad1 100644 --- a/code/game/gamemodes/changeling/powers/humanform.dm +++ b/code/game/gamemodes/changeling/powers/humanform.dm @@ -65,7 +65,7 @@ I.implanted = O user.mind.transfer_to(O) - O.mind.changeling.changeling_update_languages(changeling.absorbed_languages) + O.changeling_update_languages(changeling.absorbed_languages) O.mind.changeling.purchasedpowers -= src //O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/lesserform(null) feedback_add_details("changeling_powers","LFT") diff --git a/code/game/gamemodes/changeling/powers/lesserform.dm b/code/game/gamemodes/changeling/powers/lesserform.dm index f8ebed5798e..a769ee47bd0 100644 --- a/code/game/gamemodes/changeling/powers/lesserform.dm +++ b/code/game/gamemodes/changeling/powers/lesserform.dm @@ -60,7 +60,7 @@ C.mind.transfer_to(O) O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null) - O.mind.changeling.changeling_update_languages(changeling.absorbed_languages) + O.changeling_update_languages(changeling.absorbed_languages) feedback_add_details("changeling_powers","LF") qdel(C) diff --git a/code/game/gamemodes/changeling/powers/transform.dm b/code/game/gamemodes/changeling/powers/transform.dm index b6a9cf0af30..f1ff51a42a2 100644 --- a/code/game/gamemodes/changeling/powers/transform.dm +++ b/code/game/gamemodes/changeling/powers/transform.dm @@ -21,6 +21,8 @@ user.set_species() user.UpdateAppearance() domutcheck(user, null) + + user.changeling_update_languages(changeling.absorbed_languages) feedback_add_details("changeling_powers","TR") return 1 diff --git a/code/game/gamemodes/events/ninja_equipment.dm b/code/game/gamemodes/events/ninja_equipment.dm index 9ed459ef8ce..95b3243ae84 100644 --- a/code/game/gamemodes/events/ninja_equipment.dm +++ b/code/game/gamemodes/events/ninja_equipment.dm @@ -1351,21 +1351,21 @@ ________________________________________________________________________________ var/chance = rand(1,100) switch(chance) if(1 to 70)//High chance of a regular name. - voice = "[rand(0,1)==1?pick(first_names_female):pick(first_names_male)] [pick(last_names)]" + changer.voice = "[rand(0,1)==1?pick(first_names_female):pick(first_names_male)] [pick(last_names)]" if(71 to 80)//Smaller chance of a clown name. - voice = "[pick(clown_names)]" + changer.voice = "[pick(clown_names)]" if(81 to 90)//Small chance of a wizard name. - voice = "[pick(wizard_first)] [pick(wizard_second)]" + changer.voice = "[pick(wizard_first)] [pick(wizard_second)]" if(91 to 100)//Small chance of an existing crew name. var/names[] = new() for(var/mob/living/carbon/human/M in player_list) if(M==U||!M.client||!M.real_name) continue names.Add(M.real_name) - voice = !names.len ? "Cuban Pete" : pick(names) - U << "You are now mimicking [voice]." + changer.voice = !names.len ? "Cuban Pete" : pick(names) + U << "You are now mimicking [changer.voice]." else - U << "The voice synthesizer is [voice!="Unknown"?"now":"already"] deactivated." - voice = "Unknown" + U << "The voice synthesizer is [changer.voice!="Unknown"?"now":"already"] deactivated." + changer.voice = "Unknown" return /obj/item/clothing/mask/gas/voice/space_ninja/proc/switchm() @@ -1408,7 +1408,7 @@ ________________________________________________________________________________ if(3) mode = "Meson Scanner" usr << "[mode] is active."//Leaving usr here since it may be on the floor or on a person. - usr << "Voice mimicking algorithm is set [!vchange?"inactive":"active"]." + usr << "Voice mimicking algorithm is set [!changer.active?"inactive":"active"]." /* diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index de7bc051054..6deb483f0fa 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -132,6 +132,7 @@ proc/issyndicate(mob/living/M as mob) synd_mind.current.loc = synd_spawn[spawnpos] forge_syndicate_objectives(synd_mind) + create_syndicate(synd_mind) greet_syndicate(synd_mind) equip_syndicate(synd_mind.current) @@ -162,7 +163,38 @@ proc/issyndicate(mob/living/M as mob) spawn (rand(waittime_l, waittime_h)) send_intercept() return ..() + +/datum/game_mode/proc/create_syndicate(var/datum/mind/synd_mind) // So we don't have inferior species as ops - randomize a human + var/mob/living/carbon/human/M = synd_mind.current + M.set_species("Human",1) + M.dna.ready_dna(M) // Quadriplegic Nuke Ops won't be participating in the paralympics + var/hair_c = pick("#8B4513","#000000","#FF4500","#FFD700") // Brown, black, red, blonde + var/eye_c = pick("#000000","#8B4513","1E90FF") // Black, brown, blue + var/skin_tone = pick(35, 60, 75, 90, 105, 120, 135, 150) // Caucasian - black + var/hair_style = "Bald" + var/facial_hair_style = "Shaved" + if(M.gender == MALE) + hair_style = pick(hair_styles_male_list) + facial_hair_style = pick(facial_hair_styles_list) + else + hair_style = pick(hair_styles_female_list) + if(prob(5)) + facial_hair_style = pick(facial_hair_styles_list) + + M.r_facial = hex2num(copytext(hair_c, 2, 4)) + M.g_facial = hex2num(copytext(hair_c, 4, 6)) + M.b_facial = hex2num(copytext(hair_c, 6, 8)) + M.r_hair = hex2num(copytext(hair_c, 2, 4)) + M.g_hair = hex2num(copytext(hair_c, 4, 6)) + M.b_hair = hex2num(copytext(hair_c, 6, 8)) + M.r_eyes = hex2num(copytext(eye_c, 2, 4)) + M.g_eyes = hex2num(copytext(eye_c, 4, 6)) + M.b_eyes = hex2num(copytext(eye_c, 6, 8)) + M.s_tone = skin_tone + 35 + M.s_tone = -M.s_tone + 35 + M.h_style = hair_style + M.f_style = facial_hair_style /datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code) var/leader_title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord") diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 330949c3caf..fe3062a194c 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -23,10 +23,7 @@ var/bomb_set var/timing_wire var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. var/lastentered - var/data[0] - var/uiwidth - var/uiheight - var/uititle + flags = FPRINT use_power = 0 unacidable = 1 @@ -84,7 +81,7 @@ var/bomb_set if (istype(O, /obj/item/device/multitool) || istype(O, /obj/item/weapon/wirecutters)) ui_interact(user) - + if (src.extended) if (istype(O, /obj/item/weapon/disk/nuclear)) usr.drop_item() @@ -186,8 +183,12 @@ var/bomb_set obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) ui_interact(user) - + /obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + var/uiwidth + var/uiheight + var/uititle if(!src.opened) data["hacking"] = 0 data["auth"] = src.auth @@ -197,12 +198,12 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) else data["authstatus"] = "Auth. S2" else - if (src.timing) + if (src.timing) data["authstatus"] = "Set" else data["authstatus"] = "Auth. S1" - data["safe"] = src.safety ? "Safe" : "Engaged" - data["time"] = src.timeleft + data["safe"] = src.safety ? "Safe" : "Engaged" + data["time"] = src.timeleft data["timer"] = src.timing data["safety"] = src.safety data["anchored"] = src.anchored @@ -217,7 +218,7 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) uititle = "Nuke Control Panel" else data["hacking"] = 1 - var/list/tempwires[0] + var/list/tempwires[0] for(var/wire in src.wires) tempwires.Add(list(list("name" = wire, "cut" = src.wires[wire]))) data["wires"] = tempwires @@ -227,10 +228,10 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) uiwidth = 420 uiheight = 440 uititle = "Nuclear Bomb Defusion" - ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "nuclear_bomb.tmpl", uititle, uiwidth, uiheight) - ui.set_initial_data(data) + ui.set_initial_data(data) ui.open() /obj/machinery/nuclearbomb/verb/make_deployable() @@ -337,8 +338,8 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) if (src.timing == -1.0) return if (src.safety) - usr << "\red The safety is still on." - nanomanager.update_uis(src) + usr << "\red The safety is still on." + nanomanager.update_uis(src) return src.timing = !( src.timing ) if (src.timing) @@ -426,7 +427,7 @@ obj/machinery/nuclearbomb/proc/nukehack_win(mob/user as mob) if(ticker.mode.name == "nuclear emergency") ticker.mode:nukes_left -- else if(off_station == 1) - world << "A nuclear device was set off, but the explosion was out of reach of the station!" + world << "A nuclear device was set off, but the explosion was out of reach of the station!" else if(off_station == 2) world << "A nuclear device was set off, but the device was not on the station!" else diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index be2ac536afb..af9cfac6fbe 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -727,10 +727,14 @@ datum/objective/absorb var/n_p = 1 //autowin if (ticker.current_state == GAME_STATE_SETTING_UP) for(var/mob/new_player/P in player_list) - if(P.client && P.ready && P.mind!=owner) + if(P.client && P.ready && P.mind != owner) + if(P.client.prefs && (P.client.prefs.species == "Vox" || P.client.prefs.species == "Slime People" || P.client.prefs.species == "Machine")) // Special check for species that can't be absorbed. No better solution. + continue n_p ++ else if (ticker.current_state == GAME_STATE_PLAYING) for(var/mob/living/carbon/human/P in player_list) + if((P.species.flags & IS_SYNTHETIC) || (P.species.flags & NO_SCAN)) + continue if(P.client && !(P.mind in ticker.mode.changelings) && P.mind!=owner) n_p ++ target_amount = min(target_amount, n_p) diff --git a/code/game/gamemodes/setupgame.dm b/code/game/gamemodes/setupgame.dm index 96b1a3d7920..f32258c13db 100644 --- a/code/game/gamemodes/setupgame.dm +++ b/code/game/gamemodes/setupgame.dm @@ -134,22 +134,6 @@ //testing("DNA2: [numsToAssign.len] blocks are unused: [english_list(numsToAssign)]") -// Run AFTER genetics setup and AFTER species setup. -/proc/setup_species() - // SPECIES GENETICS FUN - for(var/name in all_species) - // I hate BYOND. Can't just call while it's in the list. - var/datum/species/species = all_species[name] - if(species.default_block_names.len>0) - testing("Setting up genetics for [species.name] (needs [english_list(species.default_block_names)])") - species.default_blocks.Cut() - for(var/block=1;block= 5) //Cannot reach target. Give up and announce the issue. - speak("Summon command failed, destination unreachable.", radio_frequency, radio_name) + speak("Summon command failed, destination unreachable.", radio_name) bot_reset() /obj/machinery/bot/proc/summon_step() diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm index e30bfa45283..a77235dad26 100644 --- a/code/game/machinery/bots/cleanbot.dm +++ b/code/game/machinery/bots/cleanbot.dm @@ -38,7 +38,6 @@ var/failed_steps var/next_dest var/next_dest_loc - radio_frequency = SRV_FREQ //Service radio_name = "Service" bot_type = CLEAN_BOT bot_type_name = "Cleanbot" diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 703b0b7dd82..bffd8a07032 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -33,7 +33,6 @@ var/arrest_type = 0 //If true, don't handcuff var/projectile = /obj/item/projectile/energy/electrode //Holder for projectile type var/shoot_sound = 'sound/weapons/Taser.ogg' - radio_frequency = SEC_FREQ radio_name = "Security" bot_type = SEC_BOT bot_type_name = "ED-209" @@ -269,7 +268,7 @@ Auto Patrol[]"}, if(declare_arrests) var/area/location = get_area(src) - speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].",radio_frequency, radio_name) + speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_name) target.visible_message("[target] has been stunned by [src]!",\ "[target] has been stunned by [src]!") diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index 3752796f90f..e9a8c67093f 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -49,7 +49,6 @@ var/oldloc = null req_one_access = list(access_construction, access_robotics) var/targetdirection - radio_frequency = ENG_FREQ //Engineering channel radio_name = "Engineering" bot_type = FLOOR_BOT bot_type_name = "Floorbot" @@ -318,7 +317,7 @@ /obj/machinery/bot/floorbot/proc/nag() //Annoy everyone on the channel to refill us! if(!nagged) var/area/location = get_area(src) - speak("Requesting refill at [location]!", radio_frequency, radio_name) + speak("Requesting refill at [location]!", radio_name) nagged = 1 /obj/machinery/bot/floorbot/proc/is_hull_breach(var/turf/t) //Ignore space tiles not considered part of a structure, also ignores shuttle docking areas. diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm index 084514ecd85..aa0dd6c94ab 100644 --- a/code/game/machinery/bots/medbot.dm +++ b/code/game/machinery/bots/medbot.dm @@ -30,7 +30,6 @@ var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users. var/declare_cooldown = 0 //Prevents spam of critical patient alerts. var/stationary_mode = 0 //If enabled, the Medibot will not move automatically. - radio_frequency = MED_FREQ //Medical frequency radio_name = "Medical" //Setting which reagents to use to treat what by default. By id. var/treatment_brute = "tricordrazine" @@ -533,7 +532,7 @@ if((skin == "bezerk")) return var/area/location = get_area(src) - speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_frequency, radio_name) + speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!", radio_name) declare_cooldown = 1 spawn(200) //Twenty seconds declare_cooldown = 0 diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm index 19ef2058f43..ac28b903947 100644 --- a/code/game/machinery/bots/mulebot.dm +++ b/code/game/machinery/bots/mulebot.dm @@ -71,7 +71,7 @@ var/global/mulebot_count = 0 cell.charge = 2000 cell.maxcharge = 2000 - spawn(5) // must wait for map loading to finish + spawn(50) // must wait for map loading to finish add_to_beacons(bot_filter) mulebot_count += 1 @@ -238,7 +238,7 @@ var/global/mulebot_count = 0 //user << browse("M.U.L.E. Mk. III [suffix ? "([suffix])" : ""][dat]", "window=mulebot;size=350x500") //onclose(user, "mulebot") - var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. V [suffix ? "([suffix])" : ""]", 350, 535) + var/datum/browser/popup = new(user, "mulebot", "M.U.L.E. Mk. V [suffix ? "([suffix])" : ""]", 350, 620) popup.set_content(dat) popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) popup.open() @@ -313,6 +313,8 @@ var/global/mulebot_count = 0 updateDialog() if("destination") + if(!delivery_beacons.len) + post_signal(beacon_freq, "findbeacon", "delivery") refresh=0 var/new_dest = input("Select M.U.L.E. Destination", "Mulebot [suffix ? "([suffix])" : ""]", destination) as null|anything in delivery_beacons refresh=1 @@ -683,7 +685,6 @@ var/global/mulebot_count = 0 // called when bot reaches current target /obj/machinery/bot/mulebot/proc/at_target() if(!reached_target) - radio_frequency = SUP_FREQ //Supply channel radio_name = "Supply" Radio.config(list("[radio_name]" = 0)) visible_message("[src] makes a chiming sound!", "You hear a chime.") @@ -696,12 +697,11 @@ var/global/mulebot_count = 0 calling_ai << "\icon[src] [src] wirelessly plays a chiming sound!" playsound(calling_ai, 'sound/machines/chime.ogg',40, 0) calling_ai = null - radio_frequency = AIPRIV_FREQ //Report on AI Private instead if the AI is controlling us. radio_name = "AI Private" Radio.config(list("[radio_name]" = 0)) if(load) // if loaded, unload at target - speak("Destination [destination] reached. Unloading [load].", radio_frequency, radio_name) + speak("Destination [destination] reached. Unloading [load].", radio_name) unload(loaddir) else // not loaded @@ -717,7 +717,7 @@ var/global/mulebot_count = 0 if(AM) load(AM) if(report_delivery) - speak("Now loading [load] at [get_area(src)].", radio_frequency, radio_name) + speak("Now loading [load] at [get_area(src)].", radio_name) // whatever happened, check to see if we return home if(auto_return && destination != home_destination) diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index d7d9d24a774..2b70de39797 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -25,7 +25,6 @@ var/arrest_type = 0 //If true, don't handcuff var/harmbaton = 0 var/base_icon = "secbot" - radio_frequency = SEC_FREQ //Security channel radio_name = "Security" bot_type = SEC_BOT bot_type_name = "Secbot" @@ -50,7 +49,6 @@ /obj/machinery/bot/secbot/pingsky name = "Officer Pingsky" desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment." - radio_frequency = AIPRIV_FREQ radio_name = "AI Private" /obj/machinery/bot/secbot/ofitser @@ -256,7 +254,7 @@ Auto Patrol: []"}, if(declare_arrests) var/area/location = get_area(src) - speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].",radio_frequency, radio_name) + speak("[arrest_type ? "Detaining" : "Arresting"] level [threatlevel] scumbag [target] in [location].", radio_name) target.visible_message("[target] has been [harmbaton ? "beaten" : "stunned"] by [src]!",\ "[target] has been [harmbaton ? "beaten" : "stunned"] by [src]!") diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm index 1d60db31a3c..dd7c175ce4d 100644 --- a/code/game/machinery/camera/tracking.dm +++ b/code/game/machinery/camera/tracking.dm @@ -4,7 +4,7 @@ /mob/living/silicon/ai/proc/InvalidTurf(turf/T as turf) if(!T) return 1 - if((T.z in config.station_levels)) + if((T.z in config.admin_levels)) return 1 if(T.z > 6) return 1 diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 265145b4a04..a04ed3f2053 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -81,13 +81,20 @@ var/const/HOLOPAD_MODE = 0 /*This is the proc for special two-way communication between AI and holopad/people talking near holopad. For the other part of the code, check silicon say.dm. Particularly robot talk.*/ -/obj/machinery/hologram/holopad/hear_talk(mob/living/M, text, verb) +/obj/machinery/hologram/holopad/hear_talk(mob/living/M, text, verb, datum/language/speaking) if(M&&hologram&&master)//Master is mostly a safety in case lag hits or something. - if(!master.say_understands(M))//The AI will be able to understand most mobs talking through the holopad. - text = stars(text) + if(!master.say_understands(M, speaking))//The AI will be able to understand most mobs talking through the holopad. + if(speaking) + text = speaking.scramble(text) + else + text = stars(text) var/name_used = M.GetVoice() //This communication is imperfect because the holopad "filters" voices and is only designed to connect to the master only. - var/rendered = "Holopad received, [name_used] [verb], \"[text]\"" + var/rendered + if(speaking) + rendered = "Holopad received, [name_used] [speaking.format_message(text, verb)]" + else + rendered = "Holopad received, [name_used] [verb], \"[text]\"" master.show_message(rendered, 2) return diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index d2dbe48ce03..16b3e3860c8 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -20,7 +20,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept use_power = 1 idle_power_usage = 25 machinetype = 5 - heatgen = 0 delay = 7 circuitboard = "/obj/item/weapon/circuitboard/telecomms/broadcaster" @@ -59,7 +58,9 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"],, signal.data["compression"], signal.data["level"], signal.frequency) + signal.data["realname"], signal.data["vname"],, + signal.data["compression"], signal.data["level"], signal.frequency, + signal.data["verb"], signal.data["language"] ) /** #### - Simple Broadcast - #### **/ @@ -84,7 +85,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency) + signal.data["realname"], signal.data["vname"], 4, signal.data["compression"], signal.data["level"], signal.frequency, + signal.data["verb"], signal.data["language"]) if(!message_delay) message_delay = 1 @@ -95,7 +97,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Do a snazzy animation! --- */ flick("broadcaster_send", src) -/obj/machinery/telecomms/broadcaster/Destroy() +/obj/machinery/telecomms/broadcaster/Del() // In case message_delay is left on 1, otherwise it won't reset the list and people can't say the same thing twice anymore. if(message_delay) message_delay = 0 @@ -117,7 +119,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept use_power = 0 idle_power_usage = 0 machinetype = 6 - heatgen = 0 var/intercept = 0 // if nonzero, broadcasts all messages to syndicate channel /obj/machinery/telecomms/allinone/receive_signal(datum/signal/signal) @@ -142,19 +143,21 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/datum/radio_frequency/connection = signal.data["connection"] - if(connection.frequency == SYND_FREQ) // if syndicate broadcast, just + if(connection.frequency in ANTAG_FREQS) // if antag broadcast, just Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency) + signal.data["realname"], signal.data["vname"],, signal.data["compression"], list(0), connection.frequency, + signal.data["verb"], signal.data["language"]) else if(intercept) Broadcast_Message(signal.data["connection"], signal.data["mob"], signal.data["vmask"], signal.data["vmessage"], signal.data["radio"], signal.data["message"], signal.data["name"], signal.data["job"], - signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency) + signal.data["realname"], signal.data["vname"], 3, signal.data["compression"], list(0), connection.frequency, + signal.data["verb"], signal.data["language"]) @@ -218,7 +221,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /proc/Broadcast_Message(var/datum/radio_frequency/connection, var/mob/M, var/vmask, var/vmessage, var/obj/item/device/radio/radio, var/message, var/name, var/job, var/realname, var/vname, - var/data, var/compression, var/list/level, var/freq) + var/data, var/compression, var/list/level, var/freq, var/verbage = "says", var/datum/language/speaking = null) + /* ###### Prepare the radio connection ###### */ @@ -246,16 +250,14 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept if(R.receive_range(display_freq, level) > -1) radios += R - // --- Broadcast to syndicate radio! --- + // --- Broadcast to antag radios! --- else if(data == 3) - - var/datum/radio_frequency/syndicateconnection = radio_controller.return_frequency(SYND_FREQ) - - for (var/obj/item/device/radio/R in syndicateconnection.devices["[RADIO_CHAT]"]) - - if(R.receive_range(SYND_FREQ, level) > -1) - radios += R + for(var/antag_freq in ANTAG_FREQS) + var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(antag_freq) + for (var/obj/item/device/radio/R in antag_connection.devices["[RADIO_CHAT]"]) + if(R.receive_range(antag_freq, level) > -1) + radios += R // --- Broadcast to ALL radio devices --- @@ -283,6 +285,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Loop through the receivers and categorize them --- */ + if (R.client && (R.client.prefs.toggles & CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. + continue if(istype(R, /mob/new_player)) // we don't want new players to hear messages. rare but generates runtimes. continue @@ -324,88 +328,17 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept if (length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled) || length(heard_gibberish)) /* --- Some miscellaneous variables to format the string output --- */ - var/part_a = "" // goes in the actual output - var/freq_text // the name of the channel - - // --- Set the name of the channel --- - switch(display_freq) - - if(SYND_FREQ) - freq_text = "#unkn" - if(COMM_FREQ) - freq_text = "Command" - if(1351) - freq_text = "Science" - if(1355) - freq_text = "Medical" - if(1357) - freq_text = "Engineering" - if(1359) - freq_text = "Security" - if(1347) - freq_text = "Supply" - if(1349) - freq_text = "Service" - if(1441) - freq_text = "Special Ops" - if(1443) - freq_text = "Response Team" - if(1447) - freq_text = "AI Private" - //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO - - - // --- If the frequency has not been assigned a name, just use the frequency as the name --- - - if(!freq_text) - freq_text = format_frequency(display_freq) - - // --- Some more pre-message formatting --- + var/freq_text = get_frequency_name(display_freq) var/part_b_extra = "" if(data == 3) // intercepted radio message part_b_extra = " (Intercepted)" - var/part_b = " \icon[radio]\[[freq_text]\][part_b_extra] " // Tweaked for security headsets -- TLE + var/part_a = "\icon[radio]\[[freq_text]\][part_b_extra] " // goes in the actual output + + // --- Some more pre-message formatting --- + var/part_b = " " // Tweaked for security headsets -- TLE var/part_c = "" - // syndies! - if (display_freq == SYND_FREQ) - part_a = "" - - // centcomm channels (deathsquid and ert) - else if (display_freq in CENT_FREQS) - part_a = "" - - // command channel - else if (display_freq == COMM_FREQ) - part_a = "" - - // AI private channel - else if (display_freq == 1447) - part_a = "" - - // department radio formatting (poorly optimized, ugh) - else if (display_freq == SEC_FREQ) - part_a = "" - - else if (display_freq == ENG_FREQ) - part_a = "" - - else if (display_freq == SCI_FREQ) - part_a = "" - - else if (display_freq == MED_FREQ) - part_a = "" - - else if (display_freq == SUP_FREQ) // cargo - part_a = "" - - else if (display_freq == SRV_FREQ) // cargo - part_a = "" - // If all else fails and it's a dept_freq, color me purple! - else if (display_freq in DEPT_FREQS) - part_a = "" - // --- Filter the message; place it in quotes apply a verb --- @@ -424,133 +357,67 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept //BR.messages_admin += blackbox_admin_msg if(istype(blackbox)) switch(display_freq) - if(1459) + if(PUB_FREQ) blackbox.msg_common += blackbox_msg - if(1351) + if(SCI_FREQ) blackbox.msg_science += blackbox_msg - if(1353) + if(COMM_FREQ) blackbox.msg_command += blackbox_msg - if(1355) + if(MED_FREQ) blackbox.msg_medical += blackbox_msg - if(1357) + if(ENG_FREQ) blackbox.msg_engineering += blackbox_msg - if(1359) + if(SEC_FREQ) blackbox.msg_security += blackbox_msg - if(1441) + if(DTH_FREQ) blackbox.msg_deathsquad += blackbox_msg - if(1213) + if(SYND_FREQ) blackbox.msg_syndicate += blackbox_msg - if(1347) + if(SUP_FREQ) blackbox.msg_cargo += blackbox_msg - if(1349) + if(SRV_FREQ) blackbox.msg_service += blackbox_msg else blackbox.messages += blackbox_msg //End of research and feedback code. - var/aitrack = "" - var/aiopen = "" /* ###### Send the message ###### */ /* --- Process all the mobs that heard a masked voice (understood) --- */ if (length(heard_masked)) - var/N = name - var/J = job - var/rendered = "[part_a][N][part_b][quotedmsg][part_c]" for (var/mob/R in heard_masked) - aitrack = "" - aiopen = "\[OPEN\] " - if(data == 4) - aitrack = "" - - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][aitrack][N] ([J]) [aiopen][part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) + R.hear_radio(message,verbage, speaking, part_a, part_b, M, 0, name) /* --- Process all the mobs that heard the voice normally (understood) --- */ if (length(heard_normal)) - var/rendered = "[part_a][realname][part_b][quotedmsg][part_c]" - for (var/mob/R in heard_normal) - aitrack = "" - aiopen = "\[OPEN\] " - if(data == 4) - aitrack = "" - - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][aitrack][realname] ([job]) [aiopen][part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) + R.hear_radio(message, verbage, speaking, part_a, part_b, M, 0, realname) /* --- Process all the mobs that heard the voice normally (did not understand) --- */ if (length(heard_voice)) - var/rendered = "[part_a][vname][part_b][vmessage][part_c]" - for (var/mob/R in heard_voice) - aitrack = "" - aiopen = "\[OPEN\] " - if(data == 4) - aitrack = "" - - - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][aitrack][vname] ([job]) [aiopen][part_b][vmessage]][part_c]", 2) - else - R.show_message(rendered, 2) + R.hear_radio(message,verbage, speaking, part_a, part_b, M,0, vname) /* --- Process all the mobs that heard a garbled voice (did not understand) --- */ // Displays garbled message (ie "f*c* **u, **i*er!") if (length(heard_garbled)) - if(M) - quotedmsg = M.say_quote(stars(message)) - else - quotedmsg = stars(quotedmsg) - - var/rendered = "[part_a][vname][part_b][quotedmsg][part_c]" - for (var/mob/R in heard_garbled) - aitrack = "" - aiopen = "\[OPEN\] " - if(data == 4) - aitrack = "" - - - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][aitrack][vname][aiopen][part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) + R.hear_radio(message, verbage, speaking, part_a, part_b, M, 1, vname) /* --- Complete gibberish. Usually happens when there's a compressed message --- */ if (length(heard_gibberish)) - if(M) - quotedmsg = M.say_quote(Gibberish(message, compression + 50)) - else - quotedmsg = Gibberish(quotedmsg, compression + 50) - - var/rendered = "[part_a][Gibberish(name, compression + 50)][part_b][quotedmsg][part_c]" - for (var/mob/R in heard_gibberish) - aitrack = "" - aiopen = "\[OPEN\] " - if(data == 4) - aitrack = "" - - - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][aitrack][Gibberish(realname, compression + 50)] ([Gibberish(job, compression + 50)]) [aiopen][part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) - + R.hear_radio(message, verbage, speaking, part_a, part_b, M, 1) + return 1 /proc/Broadcast_SimpleMessage(var/source, var/frequency, var/text, var/data, var/mob/M, var/compression, var/level) @@ -588,15 +455,15 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept receive |= R.send_hear(display_freq) - // --- Broadcast to syndicate radio! --- + // --- Broadcast to antag radios! --- else if(data == 3) - var/datum/radio_frequency/syndicateconnection = radio_controller.return_frequency(SYND_FREQ) - - for (var/obj/item/device/radio/R in syndicateconnection.devices["[RADIO_CHAT]"]) - var/turf/position = get_turf(R) - if(position && position.z == level) - receive |= R.send_hear(SYND_FREQ) + for(var/freq in ANTAG_FREQS) + var/datum/radio_frequency/antag_connection = radio_controller.return_frequency(freq) + for (var/obj/item/device/radio/R in antag_connection.devices["[RADIO_CHAT]"]) + var/turf/position = get_turf(R) + if(position && position.z == level) + receive |= R.send_hear(freq) // --- Broadcast to ALL radio devices --- @@ -621,6 +488,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Loop through the receivers and categorize them --- */ + if (R.client && !(R.client.prefs.toggles & CHAT_RADIO)) //Adminning with 80 people on can be fun when you're trying to talk and all you can hear is radios. + continue // --- Check for compression --- @@ -648,34 +517,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept /* --- Some miscellaneous variables to format the string output --- */ var/part_a = "" // goes in the actual output - var/freq_text // the name of the channel - - // --- Set the name of the channel --- - switch(display_freq) - - if(SYND_FREQ) - freq_text = "#unkn" - if(COMM_FREQ) - freq_text = "Command" - if(1351) - freq_text = "Science" - if(1355) - freq_text = "Medical" - if(1357) - freq_text = "Engineering" - if(1359) - freq_text = "Security" - if(1347) - freq_text = "Supply" - if(1349) - freq_text = "Service" - //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO - - - // --- If the frequency has not been assigned a name, just use the frequency as the name --- - - if(!freq_text) - freq_text = format_frequency(display_freq) + var/freq_text = get_frequency_name(display_freq) // --- Some more pre-message formatting --- @@ -689,7 +531,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/part_b = " \icon[radio]\[[freq_text]\][part_b_extra] " // Tweaked for security headsets -- TLE var/part_c = "" - if (display_freq==SYND_FREQ) + if (display_freq in ANTAG_FREQS) part_a = "" else if (display_freq==COMM_FREQ) part_a = "" @@ -705,25 +547,25 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept //BR.messages_admin += blackbox_admin_msg if(istype(blackbox)) switch(display_freq) - if(1459) + if(PUB_FREQ) blackbox.msg_common += blackbox_msg - if(1351) + if(SCI_FREQ) blackbox.msg_science += blackbox_msg - if(1353) + if(COMM_FREQ) blackbox.msg_command += blackbox_msg - if(1355) + if(MED_FREQ) blackbox.msg_medical += blackbox_msg - if(1357) + if(ENG_FREQ) blackbox.msg_engineering += blackbox_msg - if(1359) + if(SEC_FREQ) blackbox.msg_security += blackbox_msg - if(1441) + if(DTH_FREQ) blackbox.msg_deathsquad += blackbox_msg - if(1213) + if(SYND_FREQ) blackbox.msg_syndicate += blackbox_msg - if(1347) + if(SUP_FREQ) blackbox.msg_cargo += blackbox_msg - if(1349) + if(SRV_FREQ) blackbox.msg_service += blackbox_msg else blackbox.messages += blackbox_msg @@ -767,7 +609,7 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/turf/position = get_turf(src) return (position.z in signal.data["level"] && signal.data["done"]) -/atom/proc/telecomms_process() +/atom/proc/telecomms_process(var/do_sleep = 1) // First, we want to generate a new radio signal var/datum/signal/signal = new @@ -785,13 +627,14 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept "done" = 0, "level" = pos.z // The level it is being broadcasted at. ) - signal.frequency = 1459// Common channel + signal.frequency = PUB_FREQ// Common channel //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) - sleep(rand(10,25)) + if(do_sleep) + sleep(rand(10,25)) //world.log << "Level: [signal.data["level"]] - Done: [signal.data["done"]]" diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index cdd866e41c6..e184b0fb066 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -161,19 +161,13 @@ - - - - - - @@ -265,8 +259,11 @@ removePersonality() if(href_list["wires"]) var/t1 = text2num(href_list["wires"]) - if(radio) - radio.wires.CutWireIndex(t1) + switch(t1) + if(4) + radio.ToggleBroadcast() + if(2) + radio.ToggleReception() if(href_list["setlaws"]) var/newlaws = copytext(sanitize(input("Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.pai_laws) as message),1,MAX_MESSAGE_LEN) if(newlaws) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 32bf7da3c7a..29854facc67 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -127,7 +127,7 @@ /obj/item/device/radio/headset/heads/captain/alt name = "\proper the captain's bowman headset" - desc = "The headset of the boss. Protects ears from flashbangs. \nChannels are as follows: :c - command, :s - security, :e - engineering, :u - supply, :v - service, :m - medical, :n - science." + desc = "The headset of the boss. Protects ears from flashbangs. \nChannels are as follows: :c - command, :s - security, :e - engineering, :u - supply, :zz - service, :m - medical, :n - science." flags = EARBANGPROTECT icon_state = "com_headset_alt" item_state = "com_headset_alt" diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 28fdc835308..503fc2b5041 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -1,8 +1,3 @@ -var/GLOBAL_RADIO_TYPE = 1 // radio type to use - // 0 = old radios - // 1 = new radios (subspace technology) - - /obj/item/device/radio icon = 'icons/obj/radio.dmi' name = "station bounced radio" @@ -11,19 +6,18 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use item_state = "walkietalkie" var/on = 1 // 0 for off var/last_transmission - var/frequency = 1459 //common chat + var/frequency = PUB_FREQ //common chat var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies var/canhear_range = 3 // the range which mobs can hear this radio from var/obj/item/device/radio/patch_link = null var/datum/wires/radio/wires = null - var/prison_radio = 0 var/b_stat = 0 var/broadcasting = 0 var/listening = 1 var/freerange = 0 // 0 - Sanitize frequencies, 1 - Full range - var/list/channels = list() //see communications.dm for full list. First channels is a "default" for :h + var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h var/subspace_transmission = 0 - var/syndie = 0//Holder to see if it's a syndicate encrypted radio + var/syndie = 0//Holder to see if it's a syndicate encrpyed radio var/maxf = 1499 // "Example" = FREQ_LISTENING|FREQ_BROADCASTING flags = CONDUCT @@ -31,32 +25,31 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use throw_speed = 2 throw_range = 9 w_class = 2 - g_amt = 25 + m_amt = 75 - - var/const/TRANSMISSION_DELAY = 5 // only 2/second/radio + g_amt = 25 var/const/FREQ_LISTENING = 1 - //FREQ_BROADCASTING = 2 + var/prison_radio = 0 - var/always_talk=0 // ALWAYS catch signals. Useful for covert listening devices. /obj/item/device/radio var/datum/radio_frequency/radio_connection - var/list/datum/radio_frequency/secure_radio_connections + var/list/datum/radio_frequency/secure_radio_connections = new proc/set_frequency(new_frequency) radio_controller.remove_object(src, frequency) frequency = new_frequency radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT) + /obj/item/device/radio/New() - wires = new(src) - if(prison_radio) - wires.CutWireIndex(WIRE_TRANSMIT) - secure_radio_connections = new ..() + wires = new(src) if(radio_controller) initialize() + + if(prison_radio) + wires.CutWireIndex(WIRE_TRANSMIT) /obj/item/device/radio/initialize() @@ -117,9 +110,16 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use /obj/item/device/radio/proc/text_sec_channel(var/chan_name, var/chan_stat) var/list = !!(chan_stat&FREQ_LISTENING)!=0 return {" - [chan_name]: [list ? "Engaged" : "Disengaged"]
+ [chan_name]
+ Speaker: [list ? "Engaged" : "Disengaged"]
"} +/obj/item/device/radio/proc/ToggleBroadcast() + broadcasting = !broadcasting && !(wires.IsIndexCut(WIRE_TRANSMIT) || wires.IsIndexCut(WIRE_SIGNAL)) + +/obj/item/device/radio/proc/ToggleReception() + listening = !listening && !(wires.IsIndexCut(WIRE_RECEIVE) || wires.IsIndexCut(WIRE_SIGNAL)) + /obj/item/device/radio/Topic(href, href_list) //..() if (usr.stat || !on) @@ -129,13 +129,6 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use usr << browse(null, "window=radio") return usr.set_machine(src) - if (href_list["open"]) - var/mob/target = locate(href_list["open"]) - var/mob/living/silicon/ai/A = locate(href_list["open2"]) - if(A && target) - A.open_nearest_door(target) - return - if (href_list["track"]) var/mob/target = locate(href_list["track"]) var/mob/living/silicon/ai/A = locate(href_list["track2"]) @@ -143,23 +136,6 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use A.ai_actual_track(target) return - else if (href_list["faketrack"]) - var/mob/target = locate(href_list["track"]) - var/mob/living/silicon/ai/A = locate(href_list["track2"]) - if(A && target) - - A:cameraFollow = target - A << text("Now tracking [] on camera.", target.name) - if (usr.machine == null) - usr.machine = usr - - while (usr:cameraFollow == target) - usr << "Target is not on or near any active cameras on the station. We'll check again in 5 seconds (unless you use the cancel-camera verb)." - sleep(40) - continue - - return - else if (href_list["freq"]) var/new_frequency = (frequency + text2num(href_list["freq"])) if (!freerange || (frequency < 1200 || frequency > 1600)) @@ -171,16 +147,17 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use return else if (href_list["talk"]) - broadcasting = text2num(href_list["talk"]) + ToggleBroadcast() else if (href_list["listen"]) var/chan_name = href_list["ch_name"] if (!chan_name) - listening = text2num(href_list["listen"]) + ToggleReception() else if (channels[chan_name] & FREQ_LISTENING) channels[chan_name] &= ~FREQ_LISTENING else channels[chan_name] |= FREQ_LISTENING + if (!( master )) if (istype(loc, /mob)) interact(loc) @@ -193,10 +170,7 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use updateDialog() add_fingerprint(usr) -/obj/item/device/radio/proc/isWireCut(var/index) - return wires.IsIndexCut(index) - -/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/zlevel = list(1)) //BS12 EDIT +/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/zlevel = config.contact_levels) //BS12 EDIT var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) if (channel == "department") @@ -219,173 +193,115 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use del(A) return -/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel) - if(!on) return // the device has to be on +// Interprets the message mode when talking into a radio, possibly returning a connection datum +/obj/item/device/radio/proc/handle_message_mode(mob/living/M as mob, message, message_mode) + // If a channel isn't specified, send to common. + if(!message_mode || message_mode == "headset") + return radio_connection + + // Otherwise, if a channel is specified, look for it. + if(channels && channels.len > 0) + if (message_mode == "department") // Department radio shortcut + message_mode = channels[1] + + if (channels[message_mode]) // only broadcast if the channel is set on + return secure_radio_connections[message_mode] + + // If we were to send to a channel we don't have, drop it. + return null + +/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel, var/verb = "says", var/datum/language/speaking = null) + if(!on) return 0 // the device has to be on // Fix for permacell radios, but kinda eh about actually fixing them. - if(!M || !message) return + if(!M || !message) return 0 // Uncommenting this. To the above comment: // The permacell radios aren't suppose to be able to transmit, this isn't a bug and this "fix" is just making radio wires useless. -Giacom - if(isWireCut(WIRE_TRANSMIT)) // The device has to have all its wires and shit intact - return + if(wires.IsIndexCut(WIRE_TRANSMIT)) // The device has to have all its wires and shit intact + return 0 + + M.last_target_click = world.time + + /* Quick introduction: + This new radio system uses a very robust FTL signaling technology unoriginally + dubbed "subspace" which is somewhat similar to 'blue-space' but can't + actually transmit large mass. Headsets are the only radio devices capable + of sending subspace transmissions to the Communications Satellite. + + A headset sends a signal to a subspace listener/reciever elsewhere in space, + the signal gets processed and logged, and an audible transmission gets sent + to each individual headset. + */ + + //#### Grab the connection datum ####// + var/datum/radio_frequency/connection = handle_message_mode(M, message, channel) + if (!istype(connection)) + return 0 + if (!connection) + return 0 + + var/turf/position = get_turf(src) + + //#### Tagging the signal with all appropriate identity values ####// + + // ||-- The mob's name identity --|| + var/displayname = M.name // grab the display name (name you get when you hover over someone's icon) + var/real_name = M.real_name // mob's real name + var/mobkey = "none" // player key associated with mob + var/voicemask = 0 // the speaker is wearing a voice mask + if(M.client) + mobkey = M.key // assign the mob's key - if(GLOBAL_RADIO_TYPE == 1) // NEW RADIO SYSTEMS: By Doohl + var/jobname // the mob's "job" - /* Quick introduction: - This new radio system uses a very robust FTL signaling technology unoriginally - dubbed "subspace" which is somewhat similar to 'blue-space' but can't - actually transmit large mass. Headsets are the only radio devices capable - of sending subspace transmissions to the Communications Satellite. + // --- Human: use their actual job --- + if (ishuman(M)) + var/mob/living/carbon/human/H = M + jobname = H.get_assignment() - A headset sends a signal to a subspace listener/reciever elsewhere in space, - the signal gets processed and logged, and an audible transmission gets sent - to each individual headset. - */ + // --- Carbon Nonhuman --- + else if (iscarbon(M)) // Nonhuman carbon mob + jobname = "No id" - //#### Grab the connection datum ####// - var/datum/radio_frequency/connection = null - //testing("[src]: talk_into([M], [message], [channel])") - if(channel == "headset") - channel = null - if(channel) // If a channel is specified, look for it. - if(channels && channels.len > 0) - if (channel == "department") - //world << "DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"" - channel = channels[1] - connection = secure_radio_connections[channel] - if (!channels[channel]) // if the channel is turned off, don't broadcast - return - else - // If we were to send to a channel we don't have, drop it. - return - else // If a channel isn't specified, send to common. - connection = radio_connection - channel = null - if (!istype(connection)) - return - if (!connection) - return + // --- AI --- + else if (isAI(M)) + jobname = "AI" - var/turf/position = get_turf(src) + // --- Cyborg --- + else if (isrobot(M)) + jobname = "Cyborg" - //#### Tagging the signal with all appropriate identity values ####// + // --- Personal AI (pAI) --- + else if (istype(M, /mob/living/silicon/pai)) + jobname = "Personal AI" - // ||-- The mob's name identity --|| - var/displayname = M.name // grab the display name (name you get when you hover over someone's icon) - var/real_name = M.real_name // mob's real name - var/mobkey = "none" // player key associated with mob - var/voicemask = 0 // the speaker is wearing a voice mask - if(M.client) - mobkey = M.key // assign the mob's key + // --- Unidentifiable mob --- + else + jobname = "Unknown" - var/jobname // the mob's "job" + // --- Modifications to the mob's identity --- - // --- Human: use their actual job --- - if (ishuman(M)) - jobname = M:get_assignment() - - // --- Carbon Nonhuman --- - else if (iscarbon(M)) // Nonhuman carbon mob - jobname = "No id" - - // --- AI --- - else if (isAI(M)) - jobname = "AI" - - // --- Cyborg --- - else if (isrobot(M)) - var/mob/living/silicon/robot/B = M - jobname = "[B.designation] Cyborg" - - // --- Personal AI (pAI) --- - else if (istype(M, /mob/living/silicon/pai)) - jobname = "Personal AI" - - // --- Unidentifiable mob --- - else - jobname = "Unknown" - - - // --- Modifications to the mob's identity --- - - // The mob is disguising their identity: - if (ishuman(M) && M.GetVoice() != real_name) - displayname = M.GetVoice() - jobname = "Unknown" - voicemask = 1 + // The mob is disguising their identity: + if (ishuman(M) && M.GetVoice() != real_name) + displayname = M.GetVoice() + jobname = "Unknown" + voicemask = 1 - /* ###### Radio headsets can only broadcast through subspace ###### */ - - if(subspace_transmission) - // First, we want to generate a new radio signal - var/datum/signal/signal = new - signal.transmission_method = 2 // 2 would be a subspace transmission. - // transmission_method could probably be enumerated through #define. Would be neater. - - // --- Finally, tag the actual signal with the appropriate values --- - signal.data = list( - // Identity-associated tags: - "mob" = M, // store a reference to the mob - "mobtype" = M.type, // the mob's type - "realname" = real_name, // the mob's real name - "name" = displayname, // the mob's display name - "job" = jobname, // the mob's job - "key" = mobkey, // the mob's key - "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood - "vname" = M.voice_name, // the name to display if the voice wasn't understood - "vmask" = voicemask, // 1 if the mob is using a voice gas mask - - // We store things that would otherwise be kept in the actual mob - // so that they can be logged even AFTER the mob is deleted or something - - // Other tags: - "compression" = rand(45,50), // compressed radio signal - "message" = message, // the actual sent message - "connection" = connection, // the radio connection to use - "radio" = src, // stores the radio used for transmission - "slow" = 0, // how much to sleep() before broadcasting - simulates net lag - "traffic" = 0, // dictates the total traffic sum that the signal went through - "type" = 0, // determines what type of radio input it is: normal broadcast - "server" = null, // the last server to log this signal - "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery - "level" = position.z // The source's z level - ) - signal.frequency = connection.frequency // Quick frequency set - - //#### Sending the signal to all subspace receivers ####// - - for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) - - // Allinone can act as receivers. - for(var/obj/machinery/telecomms/allinone/R in telecomms_list) - R.receive_signal(signal) - - // Receiving code can be located in Telecommunications.dm - return - - - /* ###### Intercoms and station-bounced radios ###### */ - - var/filter_type = 2 - - /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ - if(istype(src, /obj/item/device/radio/intercom)) - filter_type = 1 - + /* ###### Radio headsets can only broadcast through subspace ###### */ + if(subspace_transmission) + // First, we want to generate a new radio signal var/datum/signal/signal = new - signal.transmission_method = 2 - - - /* --- Try to send a normal subspace broadcast first */ + signal.transmission_method = 2 // 2 would be a subspace transmission. + // transmission_method could probably be enumerated through #define. Would be neater. + // --- Finally, tag the actual signal with the appropriate values --- signal.data = list( - + // Identity-associated tags: "mob" = M, // store a reference to the mob "mobtype" = M.type, // the mob's type "realname" = real_name, // the mob's real name @@ -394,215 +310,110 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use "key" = mobkey, // the mob's key "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood "vname" = M.voice_name, // the name to display if the voice wasn't understood - "vmask" = voicemask, // 1 if the mob is using a voice gas mas + "vmask" = voicemask, // 1 if the mob is using a voice gas mask - "compression" = 0, // uncompressed radio signal + // We store things that would otherwise be kept in the actual mob + // so that they can be logged even AFTER the mob is deleted or something + + // Other tags: + "compression" = rand(45,50), // compressed radio signal "message" = message, // the actual sent message "connection" = connection, // the radio connection to use "radio" = src, // stores the radio used for transmission - "slow" = 0, - "traffic" = 0, - "type" = 0, - "server" = null, - "reject" = 0, - "level" = position.z + "slow" = 0, // how much to sleep() before broadcasting - simulates net lag + "traffic" = 0, // dictates the total traffic sum that the signal went through + "type" = 0, // determines what type of radio input it is: normal broadcast + "server" = null, // the last server to log this signal + "reject" = 0, // if nonzero, the signal will not be accepted by any broadcasting machinery + "level" = position.z, // The source's z level + "language" = speaking, + "verb" = verb ) signal.frequency = connection.frequency // Quick frequency set + //#### Sending the signal to all subspace receivers ####// + for(var/obj/machinery/telecomms/receiver/R in telecomms_list) R.receive_signal(signal) + // Allinone can act as receivers. + for(var/obj/machinery/telecomms/allinone/R in telecomms_list) + R.receive_signal(signal) - sleep(rand(10,25)) // wait a little... - - if(signal.data["done"] && position.z in signal.data["level"]) - // we're done here. - return - - // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level. - // Send a mundane broadcast with limited targets: - - //THIS IS TEMPORARY. - if(!connection) return //~Carn - - Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), - src, message, displayname, jobname, real_name, M.voice_name, - filter_type, signal.data["compression"], list(position.z), connection.frequency) + // Receiving code can be located in Telecommunications.dm + return signal.data["done"] && position.z in signal.data["level"] + /* ###### Intercoms and station-bounced radios ###### */ - else // OLD RADIO SYSTEMS: By Goons? + var/filter_type = 2 - var/datum/radio_frequency/connection = null - if(channel && channels && channels.len > 0) - if (channel == "department") - //world << "DEBUG: channel=\"[channel]\" switching to \"[channels[1]]\"" - channel = channels[1] - connection = secure_radio_connections[channel] - else - connection = radio_connection - channel = null - if (!istype(connection)) - return - var/display_freq = connection.frequency + /* --- Intercoms can only broadcast to other intercoms, but bounced radios can broadcast to bounced radios and intercoms --- */ + if(istype(src, /obj/item/device/radio/intercom)) + filter_type = 1 - //world << "DEBUG: used channel=\"[channel]\" frequency= \"[display_freq]\" connection.devices.len = [connection.devices.len]" - var/eqjobname + var/datum/signal/signal = new + signal.transmission_method = 2 - if (ishuman(M)) - eqjobname = M:get_assignment() - else if (iscarbon(M)) - eqjobname = "No id" //only humans can wear ID - else if (isAI(M)) - eqjobname = "AI" - else if (isrobot(M)) - eqjobname = "Cyborg"//Androids don't really describe these too well, in my opinion. - else if (istype(M, /mob/living/silicon/pai)) - eqjobname = "Personal AI" - else - eqjobname = "Unknown" - if (isWireCut(WIRE_TRANSMIT)) - return + /* --- Try to send a normal subspace broadcast first */ - var/list/receive = list() + signal.data = list( - //for (var/obj/item/device/radio/R in radio_connection.devices) - for (var/obj/item/device/radio/R in connection.devices["[RADIO_CHAT]"]) // Modified for security headset code -- TLE - //if(R.accept_rad(src, message)) - receive |= R.send_hear(display_freq, 0) + "mob" = M, // store a reference to the mob + "mobtype" = M.type, // the mob's type + "realname" = real_name, // the mob's real name + "name" = displayname, // the mob's display name + "job" = jobname, // the mob's job + "key" = mobkey, // the mob's key + "vmessage" = pick(M.speak_emote), // the message to display if the voice wasn't understood + "vname" = M.voice_name, // the name to display if the voice wasn't understood + "vmask" = voicemask, // 1 if the mob is using a voice gas mas - //world << "DEBUG: receive.len=[receive.len]" - var/list/heard_masked = list() // masked name or no real name - var/list/heard_normal = list() // normal message - var/list/heard_voice = list() // voice message - var/list/heard_garbled = list() // garbled message + "compression" = 0, // uncompressed radio signal + "message" = message, // the actual sent message + "connection" = connection, // the radio connection to use + "radio" = src, // stores the radio used for transmission + "slow" = 0, + "traffic" = 0, + "type" = 0, + "server" = null, + "reject" = 0, + "level" = position.z, + "language" = speaking, + "verb" = verb + ) + signal.frequency = connection.frequency // Quick frequency set - for (var/mob/R in receive) - if (R.say_understands(M)) - if (ishuman(M) && M.GetVoice() != M.real_name) - heard_masked += R - else - heard_normal += R - else - heard_voice += R + for(var/obj/machinery/telecomms/receiver/R in telecomms_list) + R.receive_signal(signal) - if (length(heard_masked) || length(heard_normal) || length(heard_voice) || length(heard_garbled)) - var/part_a = "" - //var/part_b = " \icon[src]\[[format_frequency(frequency)]\] " - var/freq_text - switch(display_freq) - if(SYND_FREQ) - freq_text = "#unkn" - if(COMM_FREQ) - freq_text = "Command" - if(1351) - freq_text = "Science" - if(1355) - freq_text = "Medical" - if(1357) - freq_text = "Engineering" - if(1359) - freq_text = "Security" - if(1347) - freq_text = "Supply" - //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO - if(!freq_text) - freq_text = format_frequency(display_freq) + sleep(rand(10,25)) // wait a little... - var/part_b = " \icon[src]\[[freq_text]\] " // Tweaked for security headsets -- TLE - var/part_c = "" + if(signal.data["done"] && position.z in signal.data["level"]) + // we're done here. + return 1 - if (display_freq==SYND_FREQ) - part_a = "" - else if (display_freq==COMM_FREQ) - part_a = "" - else if (display_freq in DEPT_FREQS) - part_a = "" + // Oh my god; the comms are down or something because the signal hasn't been broadcasted yet in our level. + // Send a mundane broadcast with limited targets: - var/quotedmsg = M.say_quote(message) + //THIS IS TEMPORARY. YEAH RIGHT + if(!connection) return 0 //~Carn - //This following recording is intended for research and feedback in the use of department radio channels. + return Broadcast_Message(connection, M, voicemask, pick(M.speak_emote), + src, message, displayname, jobname, real_name, M.voice_name, + filter_type, signal.data["compression"], list(position.z), connection.frequency,verb,speaking) - var/part_blackbox_b = " \[[freq_text]\] " // Tweaked for security headsets -- TLE - var/blackbox_msg = "[part_a][M.name][part_blackbox_b][quotedmsg][part_c]" - //var/blackbox_admin_msg = "[part_a][M.name] (Real name: [M.real_name])[part_blackbox_b][quotedmsg][part_c]" - if(istype(blackbox)) - //BR.messages_admin += blackbox_admin_msg - switch(display_freq) - if(1459) - blackbox.msg_common += blackbox_msg - if(1351) - blackbox.msg_science += blackbox_msg - if(1353) - blackbox.msg_command += blackbox_msg - if(1355) - blackbox.msg_medical += blackbox_msg - if(1357) - blackbox.msg_engineering += blackbox_msg - if(1359) - blackbox.msg_security += blackbox_msg - if(1441) - blackbox.msg_deathsquad += blackbox_msg - if(1213) - blackbox.msg_syndicate += blackbox_msg - if(1347) - blackbox.msg_cargo += blackbox_msg - if(1349) - blackbox.msg_service += blackbox_msg - else - blackbox.messages += blackbox_msg - //End of research and feedback code. - - if (length(heard_masked)) - var/N = M.name - var/J = eqjobname - if(ishuman(M) && M.GetVoice() != M.real_name) - N = M.GetVoice() - J = "Unknown" - var/rendered = "[part_a][N][part_b][quotedmsg][part_c]" - for (var/mob/R in heard_masked) - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][N] ([J]) \[OPEN\] [part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) - - if (length(heard_normal)) - var/rendered = "[part_a][M.real_name][part_b][quotedmsg][part_c]" - - for (var/mob/R in heard_normal) - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][M.real_name] ([eqjobname]) \[OPEN\] [part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) - - if (length(heard_voice)) - var/rendered = "[part_a][M.voice_name][part_b][pick(M.speak_emote)][part_c]" - - for (var/mob/R in heard_voice) - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][M.voice_name] ([eqjobname]) \[OPEN\] [part_b][pick(M.speak_emote)][part_c]", 2) - else - R.show_message(rendered, 2) - - if (length(heard_garbled)) - quotedmsg = M.say_quote(stars(message)) - var/rendered = "[part_a][M.voice_name][part_b][quotedmsg][part_c]" - - for (var/mob/R in heard_voice) - if(istype(R, /mob/living/silicon/ai)) - R.show_message("[part_a][M.voice_name]\[OPEN\] [part_b][quotedmsg][part_c]", 2) - else - R.show_message(rendered, 2) - -/obj/item/device/radio/hear_talk(mob/M as mob, msg) +/obj/item/device/radio/hear_talk(mob/M as mob, msg, var/verb = "says", var/datum/language/speaking = null) if (broadcasting) if(get_dist(src, M) <= canhear_range) - talk_into(M, msg) + talk_into(M, msg,null,verb,speaking) + + /* /obj/item/device/radio/proc/accept_rad(obj/item/device/radio/R as obj, message) @@ -621,7 +432,7 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use // what the range is in which mobs will hear the radio // returns: -1 if can't receive, range otherwise - if (isWireCut(WIRE_RECEIVE)) + if (wires.IsIndexCut(WIRE_RECEIVE)) return -1 if(!listening) return -1 @@ -629,7 +440,7 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use var/turf/position = get_turf(src) if(!position || !(position.z in level)) return -1 - if(freq == SYND_FREQ) + if(freq in ANTAG_FREQS) if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys return -1 if (!on) @@ -656,15 +467,13 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use return get_mobs_in_view(canhear_range, src) -/obj/item/device/radio/examine() - set src in view() - - ..() - if ((in_range(src, usr) || loc == usr)) +/obj/item/device/radio/examine(mob/user) + . = ..() + if ((in_range(src, user) || loc == user)) if (b_stat) - usr.show_message("\blue \the [src] can be attached and modified!") + user.show_message("\blue \the [src] can be attached and modified!") else - usr.show_message("\blue \the [src] can not be modified or attached!") + user.show_message("\blue \the [src] can not be modified or attached!") return /obj/item/device/radio/attackby(obj/item/weapon/W as obj, mob/user as mob) @@ -697,8 +506,14 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use //Giving borgs their own radio to have some more room to work with -Sieve /obj/item/device/radio/borg + var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks var/obj/item/device/encryptionkey/keyslot = null//Borg radios can handle a single encryption key - + var/shut_up = 0 + icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. + icon_state = "radio" + canhear_range = 3 + subspace_transmission = 1 + /obj/item/device/radio/borg/syndicate syndie = 1 keyslot = new /obj/item/device/encryptionkey/syndicate @@ -713,6 +528,13 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use ..() set_frequency(1441) +/obj/item/device/radio/borg/talk_into() + . = ..() + if (isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + var/datum/robot_component/C = R.components["radio"] + R.use_power(C.energy_consumption) + /obj/item/device/radio/borg/attackby(obj/item/weapon/W as obj, mob/user as mob) // ..() user.set_machine(src) @@ -758,18 +580,25 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use src.channels = list() src.syndie = 0 + var/mob/living/silicon/robot/D = src.loc + if(D.module) + for(var/ch_name in D.module.channels) + if(ch_name in src.channels) + continue + src.channels += ch_name + src.channels[ch_name] += D.module.channels[ch_name] if(keyslot) for(var/ch_name in keyslot.channels) if(ch_name in src.channels) continue src.channels += ch_name - src.channels[ch_name] = keyslot.channels[ch_name] + src.channels[ch_name] += keyslot.channels[ch_name] if(keyslot.syndie) src.syndie = 1 - for (var/ch_name in channels) + for (var/ch_name in src.channels) if(!radio_controller) sleep(30) // Waiting for the radio_controller to be created. if(!radio_controller) @@ -784,12 +613,23 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use if(usr.stat || !on) return if (href_list["mode"]) - subspace_transmission = !subspace_transmission - if(!subspace_transmission)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled + if(subspace_transmission != 1) + subspace_transmission = 1 + usr << "Subspace Transmission is enabled" + else + subspace_transmission = 0 + usr << "Subspace Transmission is disabled" + if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled channels = list() else recalculateChannels() - usr << "Subspace Transmission is [(subspace_transmission) ? "enabled" : "disabled"]" + if (href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. + shut_up = !shut_up + if(shut_up) + canhear_range = 0 + else + canhear_range = 3 + ..() /obj/item/device/radio/borg/interact(mob/user as mob) @@ -806,6 +646,7 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use + +
Toggle Broadcast Mode
+ Loudspeaker: [shut_up ? "Disengaged" : "Engaged"]
"} if(subspace_transmission)//Don't even bother if subspace isn't turned on @@ -830,11 +671,3 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use /obj/item/device/radio/off listening = 0 - -/obj/item/device/radio/Destroy() - if(radio_connection) - radio_connection.remove_listener(src) - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - R.radio = null - ..() diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index a3e0d2f7b78..1dc2142d31a 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -63,6 +63,10 @@ attached_device.HasProximity(AM) return +/obj/item/device/transfer_valve/hear_talk(mob/living/M as mob, msg) + ..() + for(var/obj/O in contents) + O.hear_talk(M, msg) /obj/item/device/transfer_valve/attack_self(mob/user as mob) ui_interact(user) diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 23bed41262c..41520fabb93 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -32,9 +32,11 @@ R.icon_state = "robot" del(R.module) R.module = null - R.camera.network.Remove(list("Engineering","Medical","MINE")) + R.camera.network.Remove(list("Engineering","Medical","Mining Outpost")) R.updatename("Default") R.status_flags |= CANPUSH + R.languages = list() + R.speech_synthesizer_langs = list() R.notify_ai(2) R.updateicon() diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index d8e22940639..7bf35f6c6e0 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -4,151 +4,83 @@ density = 1 layer = 2 var/state = 0 + var/health = 200 - attackby(obj/item/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/wrench) && state == 0) - if(anchored && !istype(src,/obj/structure/girder/displaced)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - user << "\blue Now disassembling the girder" - if(do_after(user,40)) - if(!src) return - user << "\blue You dissasembled the girder!" - new /obj/item/stack/sheet/metal(get_turf(src)) - del(src) - else if(!anchored) - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - user << "\blue Now securing the girder" - if(get_turf(user, 40)) - user << "\blue You secured the girder!" - new/obj/structure/girder( src.loc ) - del(src) - - else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) - user << "\blue Now slicing apart the girder" - if(do_after(user,30)) +/obj/structure/girder/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/wrench) && state == 0) + if(anchored && !istype(src,/obj/structure/girder/displaced)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + user << "\blue Now disassembling the girder" + if(do_after(user,40)) if(!src) return - user << "\blue You slice apart the girder!" + user << "\blue You dissasembled the girder!" new /obj/item/stack/sheet/metal(get_turf(src)) del(src) - - else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) - user << "\blue You drill through the girder!" - new /obj/item/stack/sheet/metal(get_turf(src)) - del(src) - - else if(istype(W, /obj/item/weapon/screwdriver) && state == 2 && istype(src,/obj/structure/girder/reinforced)) - playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) - user << "\blue Now unsecuring support struts" - if(do_after(user,40)) - if(!src) return - user << "\blue You unsecured the support struts!" - state = 1 - - else if(istype(W, /obj/item/weapon/wirecutters) && istype(src,/obj/structure/girder/reinforced) && state == 1) - playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) - user << "\blue Now removing support struts" - if(do_after(user,40)) - if(!src) return - user << "\blue You removed the support struts!" + else if(!anchored) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + user << "\blue Now securing the girder" + if(get_turf(user, 40)) + user << "\blue You secured the girder!" new/obj/structure/girder( src.loc ) del(src) - else if(istype(W, /obj/item/weapon/crowbar) && state == 0 && anchored ) - playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) - user << "\blue Now dislodging the girder" - if(do_after(user, 40)) - if(!src) return - user << "\blue You dislodged the girder!" - new/obj/structure/girder/displaced( src.loc ) - del(src) + else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) + user << "\blue Now slicing apart the girder" + if(do_after(user,30)) + if(!src) return + user << "\blue You slice apart the girder!" + new /obj/item/stack/sheet/metal(get_turf(src)) + del(src) - else if(istype(W, /obj/item/stack/sheet)) + else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) + user << "\blue You drill through the girder!" + new /obj/item/stack/sheet/metal(get_turf(src)) + del(src) - var/obj/item/stack/sheet/S = W - switch(S.type) + else if(istype(W, /obj/item/weapon/screwdriver) && state == 2 && istype(src,/obj/structure/girder/reinforced)) + playsound(src.loc, 'sound/items/Screwdriver.ogg', 100, 1) + user << "\blue Now unsecuring support struts" + if(do_after(user,40)) + if(!src) return + user << "\blue You unsecured the support struts!" + state = 1 - if(/obj/item/stack/sheet/metal, /obj/item/stack/sheet/metal/cyborg) - if(!anchored) - if(S.amount < 2) return - var/pdiff=performWallPressureCheck(src.loc) - if(!pdiff) - S.use(2) - user << "\blue You create a false wall! Push on it to open or close the passage." - new /obj/structure/falsewall (src.loc) - del(src) - else - user << "\red There is too much air moving through the gap! The door wouldn't stay closed if you built it." - message_admins("Attempted false wall made by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)] had a pressure difference of [pdiff]!") - log_admin("Attempted false wall made by [user.real_name] (user.ckey) at [loc] had a pressure difference of [pdiff]!") - return - else - if(S.amount < 2) return ..() - user << "\blue Now adding plating..." - if (do_after(user,40)) - if(!src || !S || S.amount < 2) return - S.use(2) - user << "\blue You added the plating!" - var/turf/Tsrc = get_turf(src) - Tsrc.ChangeTurf(/turf/simulated/wall) - for(var/turf/simulated/wall/X in Tsrc.loc) - if(X) X.add_hiddenprint(usr) - del(src) - return + else if(istype(W, /obj/item/weapon/wirecutters) && istype(src,/obj/structure/girder/reinforced) && state == 1) + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + user << "\blue Now removing support struts" + if(do_after(user,40)) + if(!src) return + user << "\blue You removed the support struts!" + new/obj/structure/girder( src.loc ) + del(src) - if(/obj/item/stack/sheet/plasteel) - if(!anchored) - if(S.amount < 2) return - var/pdiff=performWallPressureCheck(src.loc) - if(!pdiff) - S.use(2) - user << "\blue You create a false wall! Push on it to open or close the passage." - new /obj/structure/falsewall/reinforced (src.loc) - del(src) - else - user << "\red There is too much air moving through the gap! The door wouldn't stay closed if you built it." - message_admins("Attempted false rwall made by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)] had a pressure difference of [pdiff]!") - log_admin("Attempted false rwall made by [user.real_name] ([user.ckey]) at [loc] had a pressure difference of [pdiff]!") - return - else - if (src.icon_state == "reinforced") //I cant believe someone would actually write this line of code... - if(S.amount < 1) return ..() - user << "\blue Now finalising reinforced wall." - if(do_after(user, 50)) - if(!src || !S || S.amount < 1) return - S.use(1) - user << "\blue Wall fully reinforced!" - var/turf/Tsrc = get_turf(src) - Tsrc.ChangeTurf(/turf/simulated/wall/r_wall) - for(var/turf/simulated/wall/r_wall/X in Tsrc.loc) - if(X) X.add_hiddenprint(usr) - del(src) - return - else - if(S.amount < 1) return ..() - user << "\blue Now reinforcing girders" - if (do_after(user,60)) - if(!src || !S || S.amount < 1) return - S.use(1) - user << "\blue Girders reinforced!" - new/obj/structure/girder/reinforced( src.loc ) - del(src) - return + else if(istype(W, /obj/item/weapon/crowbar) && state == 0 && anchored ) + playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + user << "\blue Now dislodging the girder" + if(do_after(user, 40)) + if(!src) return + user << "\blue You dislodged the girder!" + new/obj/structure/girder/displaced( src.loc ) + del(src) - if(S.sheettype) - var/M = S.sheettype + else if(istype(W, /obj/item/stack/sheet)) + + var/obj/item/stack/sheet/S = W + switch(S.type) + + if(/obj/item/stack/sheet/metal, /obj/item/stack/sheet/metal/cyborg) if(!anchored) if(S.amount < 2) return var/pdiff=performWallPressureCheck(src.loc) if(!pdiff) S.use(2) user << "\blue You create a false wall! Push on it to open or close the passage." - var/F = text2path("/obj/structure/falsewall/[M]") - new F (src.loc) + new /obj/structure/falsewall (src.loc) del(src) else user << "\red There is too much air moving through the gap! The door wouldn't stay closed if you built it." - message_admins("Attempted false [M] wall made by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)] had a pressure difference of [pdiff]!") - log_admin("Attempted false [M] wall made by [user.real_name] ([user.ckey]) at [loc] had a pressure difference of [pdiff]!") + message_admins("Attempted false wall made by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)] had a pressure difference of [pdiff]!") + log_admin("Attempted false wall made by [user.real_name] (user.ckey) at [loc] had a pressure difference of [pdiff]!") return else if(S.amount < 2) return ..() @@ -158,67 +90,138 @@ S.use(2) user << "\blue You added the plating!" var/turf/Tsrc = get_turf(src) - Tsrc.ChangeTurf(text2path("/turf/simulated/wall/mineral/[M]")) - for(var/turf/simulated/wall/mineral/X in Tsrc.loc) + Tsrc.ChangeTurf(/turf/simulated/wall) + for(var/turf/simulated/wall/X in Tsrc.loc) if(X) X.add_hiddenprint(usr) del(src) return - add_hiddenprint(usr) + if(/obj/item/stack/sheet/plasteel) + if(!anchored) + if(S.amount < 2) return + var/pdiff=performWallPressureCheck(src.loc) + if(!pdiff) + S.use(2) + user << "\blue You create a false wall! Push on it to open or close the passage." + new /obj/structure/falsewall/reinforced (src.loc) + del(src) + else + user << "\red There is too much air moving through the gap! The door wouldn't stay closed if you built it." + message_admins("Attempted false rwall made by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)] had a pressure difference of [pdiff]!") + log_admin("Attempted false rwall made by [user.real_name] ([user.ckey]) at [loc] had a pressure difference of [pdiff]!") + return + else + if (src.icon_state == "reinforced") //I cant believe someone would actually write this line of code... + if(S.amount < 1) return ..() + user << "\blue Now finalising reinforced wall." + if(do_after(user, 50)) + if(!src || !S || S.amount < 1) return + S.use(1) + user << "\blue Wall fully reinforced!" + var/turf/Tsrc = get_turf(src) + Tsrc.ChangeTurf(/turf/simulated/wall/r_wall) + for(var/turf/simulated/wall/r_wall/X in Tsrc.loc) + if(X) X.add_hiddenprint(usr) + del(src) + return + else + if(S.amount < 1) return ..() + user << "\blue Now reinforcing girders" + if (do_after(user,60)) + if(!src || !S || S.amount < 1) return + S.use(1) + user << "\blue Girders reinforced!" + new/obj/structure/girder/reinforced( src.loc ) + del(src) + return - else if(istype(W, /obj/item/pipe)) - var/obj/item/pipe/P = W - if (P.pipe_type in list(0, 1, 5)) //simple pipes, simple bends, and simple manifolds. - user.drop_item() - P.loc = src.loc - user << "\blue You fit the pipe into the [src]!" - else - ..() - - - bullet_act(var/obj/item/projectile/Proj) - if(istype(Proj ,/obj/item/projectile/beam/pulse)) - src.ex_act(2) - ..() - return 0 - - blob_act() - if(prob(40)) - del(src) - - bullet_act(var/obj/item/projectile/Proj) - if(istype(Proj ,/obj/item/projectile/beam/pulse)) - src.ex_act(2) - ..() - return 0 - - ex_act(severity) - switch(severity) - if(1.0) - qdel(src) - return - if(2.0) - if (prob(75)) - var/remains = pick(/obj/item/stack/rods,/obj/item/stack/sheet/metal) - new remains(loc) - qdel(src) - return - if(3.0) - if (prob(30)) - var/remains = pick(/obj/item/stack/rods,/obj/item/stack/sheet/metal) - new remains(loc) - qdel(src) - return + if(S.sheettype) + var/M = S.sheettype + if(!anchored) + if(S.amount < 2) return + var/pdiff=performWallPressureCheck(src.loc) + if(!pdiff) + S.use(2) + user << "\blue You create a false wall! Push on it to open or close the passage." + var/F = text2path("/obj/structure/falsewall/[M]") + new F (src.loc) + del(src) + else + user << "\red There is too much air moving through the gap! The door wouldn't stay closed if you built it." + message_admins("Attempted false [M] wall made by [user.real_name] ([formatPlayerPanel(user,user.ckey)]) at [formatJumpTo(loc)] had a pressure difference of [pdiff]!") + log_admin("Attempted false [M] wall made by [user.real_name] ([user.ckey]) at [loc] had a pressure difference of [pdiff]!") + return else - return + if(S.amount < 2) return ..() + user << "\blue Now adding plating..." + if (do_after(user,40)) + if(!src || !S || S.amount < 2) return + S.use(2) + user << "\blue You added the plating!" + var/turf/Tsrc = get_turf(src) + Tsrc.ChangeTurf(text2path("/turf/simulated/wall/mineral/[M]")) + for(var/turf/simulated/wall/mineral/X in Tsrc.loc) + if(X) X.add_hiddenprint(usr) + del(src) + return + + add_hiddenprint(usr) + + else if(istype(W, /obj/item/pipe)) + var/obj/item/pipe/P = W + if (P.pipe_type in list(0, 1, 5)) //simple pipes, simple bends, and simple manifolds. + user.drop_item() + P.loc = src.loc + user << "\blue You fit the pipe into the [src]!" + else + ..() + +/obj/structure/girder/blob_act() + if(prob(40)) + del(src) + +/obj/structure/girder/bullet_act(var/obj/item/projectile/Proj) + if(istype(Proj, /obj/item/projectile/beam)) + health -= Proj.damage + ..() + if(health <= 0) + new /obj/item/stack/sheet/metal(get_turf(src)) + del(src) + + if(istype(Proj ,/obj/item/projectile/beam/pulse)) + src.ex_act(2) + ..() + return 0 + +/obj/structure/girder/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(75)) + var/remains = pick(/obj/item/stack/rods,/obj/item/stack/sheet/metal) + new remains(loc) + qdel(src) + return + if(3.0) + if (prob(30)) + var/remains = pick(/obj/item/stack/rods,/obj/item/stack/sheet/metal) + new remains(loc) + qdel(src) + return + else + return /obj/structure/girder/displaced icon_state = "displaced" anchored = 0 + health = 50 /obj/structure/girder/reinforced icon_state = "reinforced" state = 2 + health = 500 /obj/structure/cultgirder icon= 'icons/obj/cult.dmi' @@ -226,47 +229,55 @@ anchored = 1 density = 1 layer = 2 + var/health = 250 - attackby(obj/item/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/wrench)) - playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) - user << "\blue Now disassembling the girder" - if(do_after(user,40)) - user << "\blue You dissasembled the girder!" - new /obj/effect/decal/remains/human(get_turf(src)) - del(src) +/obj/structure/cultgirder/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/wrench)) + playsound(src.loc, 'sound/items/Ratchet.ogg', 100, 1) + user << "\blue Now disassembling the girder" + if(do_after(user,40)) + user << "\blue You dissasembled the girder!" + dismantle() - else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) - user << "\blue Now slicing apart the girder" - if(do_after(user,30)) - user << "\blue You slice apart the girder!" - new /obj/effect/decal/remains/human(get_turf(src)) - del(src) + else if(istype(W, /obj/item/weapon/pickaxe/plasmacutter)) + user << "\blue Now slicing apart the girder" + if(do_after(user,30)) + user << "\blue You slice apart the girder!" + dismantle() - else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) - user << "\blue You drill through the girder!" - new /obj/effect/decal/remains/human(get_turf(src)) - del(src) + else if(istype(W, /obj/item/weapon/pickaxe/diamonddrill)) + user << "\blue You drill through the girder!" + dismantle() + +/obj/structure/cultgirder/proc/dismantle() + new /obj/effect/decal/remains/human(get_turf(src)) + qdel(src) - blob_act() - if(prob(40)) - del(src) +/obj/structure/cultgirder/blob_act() + if(prob(40)) + dismantle() + +/obj/structure/cultgirder/bullet_act(var/obj/item/projectile/Proj) //No beam check- How else will you destroy the cult girder with silver bullets????? + health -= Proj.damage + ..() + if(health <= 0) + dismantle() + return - - ex_act(severity) - switch(severity) - if(1.0) +/obj/structure/cultgirder/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + if (prob(30)) + new /obj/effect/decal/remains/human(loc) qdel(src) - return - if(2.0) - if (prob(30)) - new /obj/effect/decal/remains/human(loc) - qdel(src) - return - if(3.0) - if (prob(5)) - new /obj/effect/decal/remains/human(loc) - qdel(src) - return - else - return \ No newline at end of file + return + if(3.0) + if (prob(5)) + new /obj/effect/decal/remains/human(loc) + qdel(src) + return + else + return \ No newline at end of file diff --git a/code/game/vehicles/vehicle.dm b/code/game/vehicles/vehicle.dm index 9924fea07d0..a61015cf6d6 100644 --- a/code/game/vehicles/vehicle.dm +++ b/code/game/vehicles/vehicle.dm @@ -182,9 +182,9 @@ mecha.loc.assume_air(leaked_gas) else del(leaked_gas) - if(mecha.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + /*if(mecha.hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) // LAG INDUCING - it'll keep on creating sparks if(mecha.get_charge()) mecha.spark_system.start() mecha.cell.charge -= min(20,mecha.cell.charge) - mecha.cell.maxcharge -= min(20,mecha.cell.maxcharge) + mecha.cell.maxcharge -= min(20,mecha.cell.maxcharge) */ return \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ce3ca49fd22..e7ab656bfb4 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -42,7 +42,7 @@ var/list/admin_verbs_admin = list( /client/proc/admin_memo, /*admin memo system. show/delete/write. +SERVER needed to delete admin memos of others*/ /client/proc/dsay, /*talk in deadchat using our ckey/fakekey*/ /client/proc/toggleprayers, /*toggles prayers on/off*/ -// /client/proc/toggle_hear_radio, /*toggles whether we hear the radio*/ + /client/proc/toggle_hear_radio, /*toggles whether we hear the radio*/ /client/proc/investigate_show, /*various admintools for investigation. Such as a singulo grief-log*/ /datum/admins/proc/toggleooc, /*toggles ooc on/off for everyone*/ /datum/admins/proc/toggleoocdead, /*toggles ooc on/off for everyone who is dead*/ diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index f62cef10073..7fa81ce358e 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -35,7 +35,6 @@ /obj/effect/landmark/corpse/proc/createCorpse() //Creates a mob and checks for gear in each slot before attempting to equip it. var/mob/living/carbon/human/human/M = new /mob/living/carbon/human/human (src.loc) - M.dna.mutantrace = mutantrace M.real_name = src.name M.death(1) //Kills the new mob M.timeofdeath = timeofdeath diff --git a/code/modules/awaymissions/mission_code/academy.dm b/code/modules/awaymissions/mission_code/academy.dm index 997276e74b8..16af3141647 100644 --- a/code/modules/awaymissions/mission_code/academy.dm +++ b/code/modules/awaymissions/mission_code/academy.dm @@ -3,6 +3,7 @@ /area/awaymission/academy name = "\improper Academy Asteroids" icon_state = "away" + report_alerts = 0 /area/awaymission/academy/headmaster name = "\improper Academy Fore Block" diff --git a/code/modules/awaymissions/mission_code/blackmarketpackers.dm b/code/modules/awaymissions/mission_code/blackmarketpackers.dm index d2d215053af..468863f3026 100644 --- a/code/modules/awaymissions/mission_code/blackmarketpackers.dm +++ b/code/modules/awaymissions/mission_code/blackmarketpackers.dm @@ -4,7 +4,7 @@ name = "\improper BMP Asteroids" icon_state = "away" luminosity = 0 - + report_alerts = 0 /area/awaymission/BMPship/Aft name = "\improper Aft Block" diff --git a/code/modules/awaymissions/mission_code/centcomAway.dm b/code/modules/awaymissions/mission_code/centcomAway.dm index 70be2fa7202..06f36c5bf44 100644 --- a/code/modules/awaymissions/mission_code/centcomAway.dm +++ b/code/modules/awaymissions/mission_code/centcomAway.dm @@ -4,7 +4,8 @@ name = "XCC-P5831" icon_state = "away" requires_power = 0 - + report_alerts = 0 + /area/awaymission/centcomAway/general name = "XCC-P5831" music = "music/ambigen3.ogg" diff --git a/code/modules/awaymissions/mission_code/challenge.dm b/code/modules/awaymissions/mission_code/challenge.dm index f7aa861eb80..966ce6053f6 100644 --- a/code/modules/awaymissions/mission_code/challenge.dm +++ b/code/modules/awaymissions/mission_code/challenge.dm @@ -1,5 +1,10 @@ //Challenge Areas +/area/awaymission/challenge + name = "Challenge" + icon_state = "away" + report_alerts = 0 + /area/awaymission/challenge/start name = "Where Am I?" icon_state = "away" diff --git a/code/modules/awaymissions/mission_code/clownplanet.dm b/code/modules/awaymissions/mission_code/clownplanet.dm index 45b0dc1c7de..359037ada0a 100644 --- a/code/modules/awaymissions/mission_code/clownplanet.dm +++ b/code/modules/awaymissions/mission_code/clownplanet.dm @@ -6,6 +6,7 @@ luminosity = 1 lighting_use_dynamic = 0 requires_power = 0 + report_alerts = 0 /area/awaymission/clownplanet/miningtown name = "\improper Clown Planet - Bananium-o-Rama" diff --git a/code/modules/awaymissions/mission_code/spacebattle.dm b/code/modules/awaymissions/mission_code/spacebattle.dm index dc86365f4ee..3f9c9925772 100644 --- a/code/modules/awaymissions/mission_code/spacebattle.dm +++ b/code/modules/awaymissions/mission_code/spacebattle.dm @@ -4,6 +4,7 @@ name = "\improper Space Battle" icon_state = "away" requires_power = 0 + report_alerts = 0 /area/awaymission/spacebattle/cruiser name = "\improper Nanotrasen Cruiser" diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index fdfd016e40a..dee5ae20af6 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -19,6 +19,9 @@ * Areas */ //Gateroom gets its own APC specifically for the gate + /area/awaymission + report_alerts = 0 + /area/awaymission/gateroom //Library, medbay, storage room diff --git a/code/modules/client/preferences_toggles.dm b/code/modules/client/preferences_toggles.dm index 8b4b300a6b0..2960f159546 100644 --- a/code/modules/client/preferences_toggles.dm +++ b/code/modules/client/preferences_toggles.dm @@ -25,6 +25,16 @@ src << "As a ghost, you will now [(prefs.toggles & CHAT_GHOSTRADIO) ? "hear all radio chat in the world" : "only hear from nearby speakers"]." prefs.save_preferences(src) feedback_add_details("admin_verb","TGR") + +/client/proc/toggle_hear_radio() + set name = "Show/Hide RadioChatter" + set category = "Preferences" + set desc = "Toggle seeing radiochatter from radios and speakers" + if(!holder) return + prefs.toggles ^= CHAT_RADIO + prefs.save_preferences(src) + usr << "You will [(prefs.toggles & CHAT_RADIO) ? "no longer" : "now"] see radio chatter from radios or speakers" + feedback_add_details("admin_verb","THR") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/verb/toggleadminhelpsound() set name = "Hear/Silence Adminhelps" diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm index c728f0d88bb..dc584be1e73 100644 --- a/code/modules/clothing/masks/gasmask.dm +++ b/code/modules/clothing/masks/gasmask.dm @@ -51,44 +51,6 @@ siemens_coefficient = 0.7 species_fit = list("Vox") -/obj/item/clothing/mask/gas/voice - name = "gas mask" - //desc = "A face-covering mask that can be connected to an air supply. It seems to house some odd electronics." - var/mode = 0// 0==Scouter | 1==Night Vision | 2==Thermal | 3==Meson - var/voice = "Unknown" - var/vchange = 0//This didn't do anything before. It now checks if the mask has special functions/N - origin_tech = "syndicate=4" - species_fit = list("Vox") - -/obj/item/clothing/mask/gas/voice/space_ninja - name = "ninja mask" - desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement." - icon_state = "s-ninja(norm)" - item_state = "s-ninja_mask" - vchange = 1 - unacidable = 1 - siemens_coefficient = 0.2 - species_fit = list("Vox") - -/obj/item/clothing/mask/gas/voice/space_ninja/scar - name = "ninja mask" - desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement. This mask appears to have already seen battle." - icon_state = "s-ninja(scar)" - item_state = "s-ninja_mask" - -/obj/item/clothing/mask/gas/voice/space_ninja/visor - name = "ninja mask" - desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement. This variant appears to have a visor to increase vision." - icon_state = "s-ninja(visor)" - item_state = "s-ninja_mask" - -/obj/item/clothing/mask/gas/voice/space_ninja/monocular - name = "ninja mask" - desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement. This variant appears to focus the user's vision out of a single port." - icon_state = "s-ninja(mon)" - item_state = "s-ninja_mask" - - /obj/item/clothing/mask/gas/clown_hat name = "clown wig and mask" desc = "A true prankster's facial attire. A clown is incomplete without his wig and mask." diff --git a/code/modules/clothing/masks/voice.dm b/code/modules/clothing/masks/voice.dm new file mode 100644 index 00000000000..3d28b720d79 --- /dev/null +++ b/code/modules/clothing/masks/voice.dm @@ -0,0 +1,59 @@ +/obj/item/voice_changer + name = "voice changer" + desc = "A voice scrambling module. If you can see this, report it as a bug on the tracker." + var/voice //If set and item is present in mask/suit, this name will be used for the wearer's speech. + var/active + +/obj/item/clothing/mask/gas/voice + name = "gas mask" + desc = "A face-covering mask that can be connected to an air supply. It seems to house some odd electronics." + var/obj/item/voice_changer/changer + origin_tech = "syndicate=4" + +/obj/item/clothing/mask/gas/voice/verb/Toggle_Voice_Changer() + set category = "Object" + set src in usr + + changer.active = !changer.active + usr << "You [changer.active ? "enable" : "disable"] the voice-changing module in \the [src]." + +/obj/item/clothing/mask/gas/voice/verb/Set_Voice(name as text) + set category = "Object" + set src in usr + + var/voice = sanitize(copytext(name,1,MAX_MESSAGE_LEN)) + if(!voice || !length(voice)) return + changer.voice = voice + usr << "You are now mimicking [changer.voice]." + +/obj/item/clothing/mask/gas/voice/New() + ..() + changer = new(src) + +/obj/item/clothing/mask/gas/voice/space_ninja + name = "ninja mask" + desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement." + icon_state = "s-ninja(norm)" + item_state = "s-ninja_mask" + unacidable = 1 + siemens_coefficient = 0.2 + species_fit = list("Vox") + var/mode = 0// 0==Scouter | 1==Night Vision | 2==Thermal | 3==Meson + +/obj/item/clothing/mask/gas/voice/space_ninja/scar + name = "ninja mask" + desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement. This mask appears to have already seen battle." + icon_state = "s-ninja(scar)" + item_state = "s-ninja_mask" + +/obj/item/clothing/mask/gas/voice/space_ninja/visor + name = "ninja mask" + desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement. This variant appears to have a visor to increase vision." + icon_state = "s-ninja(visor)" + item_state = "s-ninja_mask" + +/obj/item/clothing/mask/gas/voice/space_ninja/monocular + name = "ninja mask" + desc = "A close-fitting mask that acts both as an air filter and a post-modern fashion statement. This variant appears to focus the user's vision out of a single port." + icon_state = "s-ninja(mon)" + item_state = "s-ninja_mask" \ No newline at end of file diff --git a/code/modules/karma/karma.dm b/code/modules/karma/karma.dm index 0b97d51c8b3..38c101b4370 100644 --- a/code/modules/karma/karma.dm +++ b/code/modules/karma/karma.dm @@ -345,8 +345,8 @@ You've gained [totalkarma] total karma in your time here.
"} message_admins("SQL ERROR during karmaspent updating (updating existing entry). Error: \[[err]\]\n") return else - usr << "You have been charged [cost] karma." - message_admins("[key_name(usr)] has been charged [cost] karma.") + usr << "You have been [refund ? "refunded" : "charged"] [cost] karma." + message_admins("[key_name(usr)] has been [refund ? "refunded" : "charged"] [cost] karma.") return /client/proc/karmarefund(var/type,var/name,var/cost) diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index ed588a76482..facaf65c5da 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -12,14 +12,15 @@ var/obj/item/weapon/card/id/prisoner/inserted_id var/obj/machinery/door/airlock/release_door var/door_tag = "prisonshuttle" - var/obj/item/device/radio/Radio //needed to send messages to sec radio var/use_release_door = 0 + var/obj/item/device/radio/intercom/announcer /obj/machinery/mineral/labor_claim_console/New() ..() - Radio = new/obj/item/device/radio(src) - Radio.listening = 0 + announcer = new /obj/item/device/radio/intercom(null) + announcer.config(list("Security" = 0)) + spawn(7) src.machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir)) var/t @@ -103,8 +104,8 @@ else if(shuttle.location == 1) if (shuttle.moving_status == SHUTTLE_IDLE) - Radio.set_frequency(SEC_FREQ) - Radio.talk_into(src, "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval.", SEC_FREQ) + var/message = "[inserted_id.registered_name] has returned to the station. Minerals and Prisoner ID card ready for retrieval." + announcer.autosay(message, "Labor Camp Controller", "Security") usr << "Shuttle received message and will be sent shortly." shuttle.launch() else @@ -131,7 +132,7 @@ /obj/machinery/mineral/stacking_machine/laborstacker var/points = 0 //The unclaimed value of ore stacked. Value for each ore loosely relative to its rarity. - var/list/ore_values = list(("glass" = 1), ("metal" = 2), ("solid plasma" = 20), ("plasteel" = 23), ("reinforced glass" = 4), ("gold" = 20), ("silver" = 20), ("uranium" = 20), ("diamond" = 25), ("bananium" = 50)) + var/list/ore_values = list(("glass" = 1), ("metal" = 2), ("iron" = 3), ("solid plasma" = 20), ("plasteel" = 23), ("reinforced glass" = 4), ("gold" = 20), ("silver" = 20), ("uranium" = 20), ("diamond" = 25), ("bananium" = 50)) /obj/machinery/mineral/stacking_machine/laborstacker/proc/get_ore_values() var/dat = "
Transmit:[(!radio.isWireCut(WIRE_TRANSMIT)) ? "En" : "Dis" ]abled + [radio.broadcasting ? "En" : "Dis" ]abled
Receive:[(!radio.isWireCut(WIRE_RECEIVE)) ? "En" : "Dis" ]abled - -
Signal Pulser:[(!radio.isWireCut(WIRE_SIGNAL)) ? "En" : "Dis" ]abled + [radio.listening ? "En" : "Dis" ]abled
" @@ -155,6 +156,17 @@ S.loc = output.loc else O.loc = output.loc + + //Output amounts that are past stack_amt. + for(var/sheet in stack_storage) + if(stack_storage[sheet] >= stack_amt) + var/stacktype = stack_paths[sheet] + var/obj/item/stack/sheet/S = new stacktype (get_turf(output)) + S.amount = stack_amt + stack_storage[sheet] -= stack_amt + + console.updateUsrDialog() + return /**********************Point Lookup Console**************************/ diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 4be7623c8ff..e999f919091 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -24,6 +24,7 @@ var/atom/movable/following = null var/medHUD = 0 var/secHUD = 0 + var/anonsay = 0 /mob/dead/observer/New(var/mob/body=null, var/flags=1) sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF @@ -490,6 +491,11 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(usr != src) return ..() + + if (href_list["track"]) + var/mob/target = locate(href_list["track"]) in mob_list + if(target) + ManualFollow(target) if (href_list["follow"]) var/mob/target = locate(href_list["follow"]) in mob_list @@ -532,3 +538,14 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp following = null ..() //END TELEPORT HREF CODE + +/mob/dead/observer/verb/toggle_anonsay() + set category = "Ghost" + set name = "Toggle Anonymous Chat" + set desc = "Toggles showing your key in dead chat." + + src.anonsay = !src.anonsay + if(anonsay) + src << "Your key won't be shown when you speak in dead chat." + else + src << "Your key will be publicly visible again." diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm new file mode 100644 index 00000000000..f63566a0483 --- /dev/null +++ b/code/modules/mob/hear_say.dm @@ -0,0 +1,215 @@ +// At minimum every mob has a hear_say proc. + +/mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if(!client) + return + + if(speaker && !speaker.client && istype(src,/mob/dead/observer) && client.prefs.toggles & CHAT_GHOSTEARS && !speaker in view(src)) + //Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE') + //Or someone snoring. So we make it where they won't hear it. + return + + //make sure the air can transmit speech - hearer's side + var/turf/T = get_turf(src) + if ((T) && (!(istype(src, /mob/dead/observer)))) //Ghosts can hear even in vacuum. + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1) + return + + if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + italics = 1 + sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact + + if(sleeping || stat == 1) + hear_sleep(message) + return + + //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. + if (language && (language.flags & NONVERBAL)) + if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) + message = stars(message) + + if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!say_understands(speaker,language)) + if(istype(speaker,/mob/living/simple_animal)) + var/mob/living/simple_animal/S = speaker + message = pick(S.speak) + else + if(language) + message = language.scramble(message) + else + message = stars(message) + + var/speaker_name = speaker.name + if(istype(speaker, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = speaker + speaker_name = H.GetVoice() + + if(italics) + message = "[message]" + + var/track = null + if(istype(src, /mob/dead/observer)) + if(italics && client.prefs.toggles & CHAT_GHOSTRADIO) + return + if(speaker_name != speaker.real_name && speaker.real_name) + speaker_name = "[speaker.real_name] ([speaker_name])" + track = "(follow) " + if(client.prefs.toggles & CHAT_GHOSTEARS && speaker in view(src)) + message = "[message]" + + if(sdisabilities & DEAF || ear_deaf) + if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set + if(speaker == src) + src << "You cannot hear yourself speak!" + else + src << "[speaker_name][alt_name] talks but you cannot hear \him." + else + if(language) + src << "[speaker_name][alt_name] [track][language.format_message(message, verb)]" + else + src << "[speaker_name][alt_name] [track][verb], \"[message]\"" + if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z)) + var/turf/source = speaker? get_turf(speaker) : get_turf(src) + src.playsound_local(source, speech_sound, sound_vol, 1) + + +/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") + + if(!client) + return + + if(sleeping || stat==1) //If unconscious or sleeping + hear_sleep(message) + return + + var/track = null + + //non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet. + if (language && (language.flags & NONVERBAL)) + if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src))) + message = stars(message) + + if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages + if(!say_understands(speaker,language)) + if(istype(speaker,/mob/living/simple_animal)) + var/mob/living/simple_animal/S = speaker + if(S.speak && S.speak.len) + message = pick(S.speak) + else + return + else + if(language) + message = language.scramble(message) + else + message = stars(message) + + if(hard_to_hear) + message = stars(message) + + var/speaker_name = speaker.name + + if(vname) + speaker_name = vname + + if(istype(speaker, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = speaker + if(H.voice) + speaker_name = H.voice + + if(hard_to_hear) + speaker_name = "unknown" + + var/changed_voice + + if(istype(src, /mob/living/silicon/ai) && !hard_to_hear) + var/jobname // the mob's "job" + var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any. + + if (ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + + if((H.wear_id && istype(H.wear_id,/obj/item/weapon/card/id/syndicate)) && (H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice))) + + changed_voice = 1 + var/mob/living/carbon/human/I = locate(speaker_name) + + if(I) + impersonating = I + jobname = impersonating.get_assignment() + else + jobname = "Unknown" + else + jobname = H.get_assignment() + + else if (iscarbon(speaker)) // Nonhuman carbon mob + jobname = "No id" + else if (isAI(speaker)) + jobname = "AI" + else if (isrobot(speaker)) + jobname = "Cyborg" + else if (istype(speaker, /mob/living/silicon/pai)) + jobname = "Personal AI" + else + jobname = "Unknown" + + if(changed_voice) + if(impersonating) + track = "[speaker_name] ([jobname])" + else + track = "[speaker_name] ([jobname])" + else + track = "[speaker_name] ([jobname])" + + if(istype(src, /mob/dead/observer)) + if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. + speaker_name = "[speaker.real_name] ([speaker_name])" + track = "[speaker_name] (follow)" + + var/formatted + if(language) + formatted = language.format_message_radio(message, verb) + else + formatted = "[verb], \"[message]\"" + if(sdisabilities & DEAF || ear_deaf) + if(prob(20)) + src << "You feel your headset vibrate but can hear nothing from it!" + else if(track) + src << "[part_a][track][part_b][formatted]" + else + src << "[part_a][speaker_name][part_b][formatted]" + +/mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null) + if(!client) + return + + if(say_understands(speaker, language)) + message = "[src] [verb], \"[message]\"" + else + message = "[src] [verb]." + + if(src.status_flags & PASSEMOTES) + for(var/obj/item/weapon/holder/H in src.contents) + H.show_message(message) + for(var/mob/living/M in src.contents) + M.show_message(message) + src.show_message(message) + +/mob/proc/hear_sleep(var/message) + var/heard = "" + if(prob(15)) + var/list/punctuation = list(",", "!", ".", ";", "?") + var/list/messages = text2list(message, " ") + var/R = rand(1, messages.len) + var/heardword = messages[R] + if(copytext(heardword,1, 1) in punctuation) + heardword = copytext(heardword,2) + if(copytext(heardword,-1) in punctuation) + heardword = copytext(heardword,1,lentext(heardword)) + heard = "...You hear something about...[heardword]" + + else + heard = "...You almost hear someone talking..." + + src << heard diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index 0a043db41ef..3b4f1cc6f39 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -1,3 +1,5 @@ +#define SCRAMBLE_CACHE_LEN 20 + /* Datum based languages. Easily editable and modular. */ @@ -5,13 +7,106 @@ /datum/language var/name = "an unknown language" // Fluff name of language if any. var/desc = "A language." // Short description for 'Check Languages'. - var/speech_verb = "says" // 'says', 'hisses'. - var/ask_verb = "asks" // Used when sentence ends in a ? + var/speech_verb = "says" // 'says', 'hisses', 'farts'. + var/ask_verb = "asks" // Used when sentence ends in a ? var/exclaim_verb = "exclaims" // Used when sentence ends in a ! - var/colour = "say_quote" // CSS style to use for strings in this language. + var/whisper_verb // Optional. When not specified speech_verb + quietly/softly is used instead. + var/signlang_verb = list() // list of emotes that might be displayed if this language has NONVERBAL or SIGNLANG flags + var/colour = "body" // CSS style to use for strings in this language. var/key = "x" // Character used to speak in language eg. :o for Unathi. var/flags = 0 // Various language flags. var/native // If set, non-native speakers will have trouble speaking. + var/list/syllables // Used when scrambling text for a non-speaker. + var/list/space_chance = 55 // Likelihood of getting a space in the random scramble string. + +/datum/language/proc/get_random_name(var/gender, name_count=2, syllable_count=4) + if(!syllables || !syllables.len) + if(gender==FEMALE) + return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names)) + else + return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names)) + + var/full_name = "" + var/new_name = "" + + for(var/i = 0;i0;x--) + new_name += pick(syllables) + full_name += " [capitalize(lowertext(new_name))]" + + return "[trim(full_name)]" + +/datum/language + var/list/scramble_cache = list() + +/datum/language/proc/scramble(var/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 + if(input in scramble_cache) + var/n = scramble_cache[input] + scramble_cache -= input + scramble_cache[input] = n + return n + + var/input_size = length(input) + var/scrambled_text = "" + var/capitalize = 1 + + while(length(scrambled_text) < input_size) + var/next = pick(syllables) + if(capitalize) + next = capitalize(next) + capitalize = 0 + scrambled_text += next + var/chance = rand(100) + if(chance <= 5) + scrambled_text += ". " + capitalize = 1 + else if(chance > 5 && chance <= space_chance) + scrambled_text += " " + + scrambled_text = trim(scrambled_text) + var/ending = copytext(scrambled_text, length(scrambled_text)) + if(ending == ".") + scrambled_text = copytext(scrambled_text,1,length(scrambled_text)-1) + var/input_ending = copytext(input, input_size) + 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) + + + return scrambled_text + +/datum/language/proc/format_message(message, verb) + return "[verb], \"[capitalize(message)]\"" + +/datum/language/proc/format_message_radio(message, verb) + return "[verb], \"[capitalize(message)]\"" + +/datum/language/proc/get_talkinto_msg_range(message) + // if you yell, you'll be heard from two tiles over instead of one + return (copytext(message, length(message)) == "!") ? 2 : 1 + +/datum/language/proc/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + log_say("[key_name(speaker)] : ([name]) [message]") + + if(!speaker_mask) speaker_mask = speaker.name + var/msg = "[name], [speaker_mask] [format_message(message, get_spoken_verb(message))]" + + for(var/mob/player in player_list) + if(istype(player,/mob/dead) || ((src in player.languages) && check_special_condition(player))) + player << msg + +/datum/language/proc/check_special_condition(var/mob/other) + return 1 /datum/language/proc/get_spoken_verb(var/msg_end) switch(msg_end) @@ -19,8 +114,25 @@ return exclaim_verb if("?") return ask_verb - return speech_verb - + return speech_verb + +// Noise "language", for audible emotes. +/datum/language/noise + name = "Noise" + desc = "Noises" + key = "" + flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG + +/datum/language/noise/format_message(message, verb) + return "[message]" + +/datum/language/noise/format_message_radio(message, verb) + return "[message]" + +/datum/language/noise/get_talkinto_msg_range(message) + // if you make a loud noise (screams etc), you'll be heard from 4 tiles over instead of two + return (copytext(message, length(message)) == "!") ? 4 : 2 + /datum/language/unathi name = "Sinta'unathi" desc = "The common language of Moghes, composed of sibilant hisses and rattles. Spoken natively by Unathi." @@ -29,17 +141,38 @@ exclaim_verb = "roars" colour = "soghun" key = "o" - flags = WHITELISTED + flags = RESTRICTED + syllables = list("ss","ss","ss","ss","skak","seeki","resh","las","esi","kor","sh") + +/datum/language/unathi/get_random_name() + + var/new_name = ..() + while(findtextEx(new_name,"sss",1,null)) + new_name = replacetext(new_name, "sss", "ss") + return capitalize(new_name) /datum/language/tajaran name = "Siik'tajr" - desc = "An expressive language that combines yowls and chirps with posture, tail and ears. Native to the Tajaran." + desc = "The traditionally employed tongue of Ahdomai, composed of expressive yowls and chirps. Native to the Tajaran." speech_verb = "mrowls" ask_verb = "mrowls" exclaim_verb = "yowls" colour = "tajaran" key = "j" - flags = WHITELISTED + flags = RESTRICTED + syllables = list("rr","rr","tajr","kir","raj","kii","mir","kra","ahk","nal","vah","khaz","jri","ran","darr", \ + "mi","jri","dynh","manq","rhe","zar","rrhaz","kal","chur","eech","thaa","dra","jurl","mah","sanu","dra","ii'r", \ + "ka","aasi","far","wa","baq","ara","qara","zir","sam","mak","hrar","nja","rir","khan","jun","dar","rik","kah", \ + "hal","ket","jurl","mah","tul","cresh","azu","ragh") + +/datum/language/tajaran/get_random_name(var/gender) + + var/new_name = ..(gender,1) + if(prob(80)) + new_name += " [pick(list("Hadii","Kaytam","Zhan-Khazan","Hharar","Njarir'Akhan"))]" + else + new_name += ..(gender,1) + return new_name /datum/language/skrell name = "Skrellian" @@ -49,7 +182,8 @@ exclaim_verb = "warbles" colour = "skrell" key = "k" - flags = WHITELISTED + flags = RESTRICTED + syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!") /datum/language/vox name = "Vox-pidgin" @@ -59,7 +193,12 @@ exclaim_verb = "SHRIEKS" colour = "vox" key = "v" - flags = RESTRICTED + flags = RESTRICTED | WHITELISTED + syllables = list("ti","ti","ti","hi","hi","ki","ki","ki","ki","ya","ta","ha","ka","ya","chi","cha","kah", \ + "SKRE","AHK","EHK","RAWK","KRA","AAA","EEE","KI","II","KRI","KA") + +/datum/language/vox/get_random_name() + return ..(FEMALE,1,6) /datum/language/diona name = "Rootspeak" @@ -67,79 +206,258 @@ speech_verb = "creaks and rustles" ask_verb = "creaks" exclaim_verb = "rustles" - colour = "soghun" + colour = "diona" key = "q" flags = RESTRICTED + syllables = list("hs","zt","kr","st","sh") +/datum/language/diona/get_random_name() + var/new_name = "[pick(list("To Sleep Beneath","Wind Over","Embrace of","Dreams of","Witnessing","To Walk Beneath","Approaching the"))]" + new_name += " [pick(list("the Void","the Sky","Encroaching Night","Planetsong","Starsong","the Wandering Star","the Empty Day","Daybreak","Nightfall","the Rain"))]" + return new_name + +/datum/language/trinary + name = "Trinary" + desc = "A modification of binary to allow fuzzy logic. 0 is no, 1 is maybe, 2 is yes. Credited with giving Machine People the ability to think creatively." + speech_verb = "states" + ask_verb = "queries" + exclaim_verb = "exclaims" + colour = "trinary" + key = "5" + flags = RESTRICTED | WHITELISTED + syllables = list("02011","01222","10100","10210","21012","02011","21200","1002","2001","0002","0012","0012","000","120","121","201","220","10","11","0") + /datum/language/kidan name = "Chittin" - desc = "The noise made by rubbing it's antennae together is actually a complex form of communication for Kidan." - speech_verb = "rubs its antenna together" - ask_verb = "rubs its antenna together" - exclaim_verb = "rubs its antenna together" - colour = "tajaran" + desc = "The noise made by rubbing its antennae together is actually a complex form of communication for Kidan." + speech_verb = "rubs its antennae together" + ask_verb = "rubs its antennae together" + exclaim_verb = "rubs its antennae together" + colour = "kidan" key = "4" - flags = RESTRICTED - + flags = RESTRICTED | WHITELISTED + syllables = list("click","clack") + /datum/language/slime name = "Bubblish" - desc = "Languages of slimes, a mixture of bubbling noises and pops. Almost impossible to speak without mechanical aid for non slime people." + desc = "The language of slimes. It's a mixture of bubbling noises and pops. Very difficult to speak without mechanical aid for humans." speech_verb = "bubbles and pops" ask_verb = "bubbles and pops" exclaim_verb = "bubbles and pops" - colour = "skrell" + colour = "slime" key = "f" + flags = RESTRICTED | WHITELISTED + syllables = list("blob","plop","pop","bop","boop") + +/datum/language/common + name = "Galactic Common" + desc = "The common galactic tongue." + speech_verb = "says" + whisper_verb = "whispers" + key = "0" flags = RESTRICTED + syllables = list("blah","blah","blah","bleh","meh","neh","nah","wah") + +//TODO flag certain languages to use the mob-type specific say_quote and then get rid of these. +/datum/language/common/get_spoken_verb(var/msg_end) + switch(msg_end) + if("!") + return pick("exclaims","shouts","yells") //TODO: make the basic proc handle lists of verbs. + if("?") + return ask_verb + return speech_verb /datum/language/human name = "Sol Common" desc = "A bastardized hybrid of informal English and elements of Mandarin Chinese; the common language of the Sol system." + speech_verb = "says" + whisper_verb = "whispers" + colour = "solcom" key = "1" flags = RESTRICTED + syllables = list("tao","shi","tzu","yi","com","be","is","i","op","vi","ed","lec","mo","cle","te","dis","e") -/datum/language/trinary - name = "Trinary" - desc = "A modification of binary to allow fuzzy logic. 0 is no, 1 maybe, 2 yes. Credited with giving Machine People the ability to think creatively." - key = "5" - flags = RESTRICTED - +/datum/language/human/get_spoken_verb(var/msg_end) + switch(msg_end) + if("!") + return pick("exclaims","shouts","yells") //TODO: make the basic proc handle lists of verbs. + if("?") + return ask_verb + return speech_verb // Galactic common languages (systemwide accepted standards). /datum/language/trader name = "Tradeband" desc = "Maintained by the various trading cartels in major systems, this elegant, structured language is used for bartering and bargaining." speech_verb = "enunciates" + colour = "say_quote" key = "2" + space_chance = 100 + syllables = list("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", + "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", + "magna", "aliqua", "ut", "enim", "ad", "minim", "veniam", "quis", "nostrud", + "exercitation", "ullamco", "laboris", "nisi", "ut", "aliquip", "ex", "ea", "commodo", + "consequat", "duis", "aute", "irure", "dolor", "in", "reprehenderit", "in", + "voluptate", "velit", "esse", "cillum", "dolore", "eu", "fugiat", "nulla", + "pariatur", "excepteur", "sint", "occaecat", "cupidatat", "non", "proident", "sunt", + "in", "culpa", "qui", "officia", "deserunt", "mollit", "anim", "id", "est", "laborum") /datum/language/gutter name = "Gutter" desc = "Much like Standard, this crude pidgin tongue descended from numerous languages and serves as Tradeband for criminal elements." speech_verb = "growls" + colour = "rough" key = "3" + syllables = list ("gra","ba","ba","breh","bra","rah","dur","ra","ro","gro","go","ber","bar","geh","heh", "gra") + +/datum/language/xenocommon + name = "Xenomorph" + colour = "alien" + desc = "The common tongue of the xenomorphs." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + key = "6" + flags = RESTRICTED + syllables = list("sss","sSs","SSS") + +/datum/language/xenos + name = "Hivemind" + desc = "Xenomorphs have the strange ability to commune over a psychic hivemind." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + colour = "alien" + key = "a" + flags = RESTRICTED | HIVEMIND + +/datum/language/xenos/check_special_condition(var/mob/other) + var/mob/living/carbon/M = other + if(!istype(M)) + return 1 + return 0 + +/datum/language/ling + name = "Changeling" + desc = "Although they are normally wary and suspicious of each other, changelings can commune over a distance." + speech_verb = "says" + colour = "changeling" + key = "g" + flags = RESTRICTED | HIVEMIND + +/datum/language/ling/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(speaker.mind && speaker.mind.changeling) + ..(speaker,message,speaker.mind.changeling.changelingID) + else + ..(speaker,message) + +/datum/language/corticalborer + name = "Cortical Link" + desc = "Cortical borers possess a strange link between their tiny minds." + speech_verb = "sings" + ask_verb = "sings" + exclaim_verb = "sings" + colour = "alien" + key = "x" + flags = RESTRICTED | HIVEMIND + +/datum/language/corticalborer/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + var/mob/living/simple_animal/borer/B + + if(istype(speaker,/mob/living/carbon)) + var/mob/living/carbon/M = speaker + B = M.has_brain_worms() + else if(istype(speaker,/mob/living/simple_animal/borer)) + B = speaker + + if(B) + speaker_mask = B.truename + ..(speaker,message,speaker_mask) + +/datum/language/binary + name = "Robot Talk" + desc = "Most human stations support free-use communications protocols and routing hubs for synthetic use." + colour = "say_quote" + speech_verb = "states" + ask_verb = "queries" + exclaim_verb = "declares" + key = "b" + flags = RESTRICTED | HIVEMIND + var/drone_only + +/datum/language/binary/broadcast(var/mob/living/speaker,var/message,var/speaker_mask) + + if(!speaker.binarycheck()) + return + + if (!message) + return + + var/message_start = "[name], [speaker.name]" + var/message_body = "[speaker.say_quote(message)], \"[message]\"" + + for (var/mob/M in dead_mob_list) + if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping + M.show_message("[message_start] [message_body]", 2) + + for (var/mob/living/S in living_mob_list) + + if(drone_only && !istype(S,/mob/living/silicon/robot/drone)) + continue + else if(istype(S , /mob/living/silicon/ai)) + message_start = "[name], [speaker.name]" + else if (!S.binarycheck()) + continue + + S.show_message("[message_start] [message_body]", 2) + + var/list/listening = hearers(1, src) + listening -= src + + for (var/mob/living/M in listening) + if(istype(M, /mob/living/silicon) || M.binarycheck()) + continue + M.show_message("synthesised voice beeps, \"beep beep beep\"",2) + + //robot binary xmitter component power usage + if (isrobot(speaker)) + var/mob/living/silicon/robot/R = speaker + var/datum/robot_component/C = R.components["comms"] + R.use_power(C.energy_consumption) + +/datum/language/binary/drone + name = "Drone Talk" + desc = "A heavily encoded damage control coordination stream." + speech_verb = "transmits" + ask_verb = "transmits" + exclaim_verb = "transmits" + colour = "say_quote" + key = "d" + flags = RESTRICTED | HIVEMIND + drone_only = 1 // Language handling. /mob/proc/add_language(var/language) - for(var/datum/language/L in languages) - if(L && L.name == language) - return 0 - var/datum/language/new_language = all_languages[language] - if(!istype(new_language,/datum/language)) + if(!istype(new_language) || new_language in languages) return 0 - languages += new_language + languages |= new_language return 1 /mob/proc/remove_language(var/rem_language) + var/datum/language/L = all_languages[rem_language] + . = (L in languages) + languages.Remove(L) - for(var/datum/language/L in languages) - if(L && L.name == rem_language) - languages -= L - return 1 +// Can we speak this language, as opposed to just understanding it? +/mob/proc/can_speak(datum/language/speaking) - return 0 + return (universal_speak || (speaking && speaking.flags & INNATE) || speaking in src.languages) //TBD /mob/verb/check_languages() @@ -150,7 +468,10 @@ var/dat = "Known Languages

" for(var/datum/language/L in languages) - dat += "[L.name] (:[L.key])
[L.desc]

" + if(!(L.flags & NONGLOBAL)) + dat += "[L.name] (:[L.key])
[L.desc]

" src << browse(dat, "window=checklanguage") - return \ No newline at end of file + return + +#undef SCRAMBLE_CACHE_LEN diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index 0eb6fe764ee..721c2a4b3fb 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -21,6 +21,8 @@ if(name == "alien") name = text("alien ([rand(1, 1000)])") real_name = name + add_language("Xenomorph") + add_language("Hivemind") ..() //This is fine, works the same as a human diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 5515c951514..a918e069bb7 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -23,6 +23,8 @@ name = "alien larva ([rand(1, 1000)])" real_name = name regenerate_icons() + add_language("Xenomorph") + add_language("Hivemind") ..() //This is fine, works the same as a human diff --git a/code/modules/mob/living/carbon/alien/say.dm b/code/modules/mob/living/carbon/alien/say.dm index 9604a50559d..8b4177470a4 100644 --- a/code/modules/mob/living/carbon/alien/say.dm +++ b/code/modules/mob/living/carbon/alien/say.dm @@ -1,69 +1,28 @@ /mob/living/carbon/alien/say(var/message) + var/verb = "says" + var/message_range = world.view - if (silent) - return + if(client) + if(client.prefs.muted & MUTE_IC) + src << "\red You cannot speak in IC (Muted)." + return - if (length(message) >= 2) - if (department_radio_keys[copytext(message, 1, 3)] == "alientalk") - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - if (stat == 2) - return say_dead(message) - else - alien_talk(message) - else - if (copytext(message, 1, 2) != "*" && !stat) - playsound(loc, "hiss", 25, 1, 1)//So aliens can hiss while they hiss yo/N - return ..(message) - else + message = trim_strip_html_properly(message) -/mob/living/proc/alien_talk(var/message) + if(stat == 2) + return say_dead(message) + + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + var/datum/language/speaking = parse_language(message) + + if(speaking) + message = copytext(message, 2+length(speaking.key)) - log_say("[key_name(src)] : [message]") message = trim(message) - if (!message) + if(!message || stat) return - var/message_a = say_quote(message) - var/rendered = "Hivemind, [name] [message_a]" - for (var/mob/living/S in player_list) - if(!S.stat) - if(S.alien_talk_understand) - if(S.alien_talk_understand == alien_talk_understand) - S.show_message(rendered, 2) - else if (S.hivecheck()) - S.show_message(rendered, 2) - - var/list/listening = hearers(1, src) - listening -= src - listening += src - - var/list/heard = list() - for (var/mob/M in listening) - if(!istype(M, /mob/living/carbon/alien) && !M.alien_talk_understand) - heard += M - - - if (length(heard)) - var/message_b - - message_b = "hsssss" - message_b = say_quote(message_b) - message_b = "[message_b]" - - rendered = "[voice_name] [message_b]" - - for (var/mob/M in heard) - M.show_message(rendered, 2) - - message = say_quote(message) - - rendered = "Hivemind, [name] [message_a]" - var/rendered2 = null - for (var/mob/M in player_list) - if (istype(M, /mob/new_player)) - continue - if (M.stat > 1 && istype(M, /mob/dead/observer)) - rendered2 = "Hivemind, [name] (Follow) [message_a]" - M.show_message(rendered2, 2) \ No newline at end of file + ..(message, speaking, verb, null, null, message_range, null) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index f181cc05464..bbcd527386b 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -55,4 +55,7 @@ canmove = 1 use_me = 1 //If it can move, let it emote else canmove = 0 - return canmove \ No newline at end of file + return canmove + +/mob/living/carbon/brain/binarycheck() + return istype(loc, /obj/item/device/mmi/posibrain) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm index 1e7a9da9a76..26dc7b30f3f 100644 --- a/code/modules/mob/living/carbon/brain/say.dm +++ b/code/modules/mob/living/carbon/brain/say.dm @@ -1,3 +1,4 @@ +//TODO: Convert this over for languages. /mob/living/carbon/brain/say(var/message) if (silent) return @@ -8,18 +9,31 @@ if(!(container && (istype(container, /obj/item/device/mmi) || istype(container, /obj/item/device/mmi/posibrain)))) return //No MMI, can't speak, bucko./N else - if ((department_radio_keys[copytext(message, 1, 3)] == "binary") && (container && istype(container, /obj/item/device/mmi/posibrain))) - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - robot_talk(message) - return + var/datum/language/speaking = parse_language(message) + if(speaking) + message = copytext(message, 2+length(speaking.key)) + var/verb = "says" + var/ending = copytext(message, length(message)) + if (speaking) + verb = speaking.get_spoken_verb(ending) + else + if(ending=="!") + verb=pick("exclaims","shouts","yells") + if(ending=="?") + verb="asks" + if(prob(emp_damage*4)) if(prob(10))//10% chane to drop the message entirely return else message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher + + if(speaking && speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return + if(istype(container, /obj/item/device/mmi/radio_enabled)) var/obj/item/device/mmi/radio_enabled/R = container if(R.radio) - spawn(0) R.radio.hear_talk(src, sanitize(message)) - ..() \ No newline at end of file + spawn(0) R.radio.hear_talk(src, trim(sanitize(message)), verb, speaking) + ..(trim(message), speaking, verb) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 5f3a0cca482..ff64560fbbe 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -9,6 +9,40 @@ var/datum/species/species //Contains icon generation and language information, set during New(). var/embedded_flag //To check if we've need to roll for damage on movement while an item is imbedded in us. +/mob/living/carbon/human/New(var/new_loc, var/new_species = null, var/delay_ready_dna=0) + if(!species) + if(new_species) + set_species(new_species,null,1) + else + set_species() + + var/datum/reagents/R = new/datum/reagents(1000) + reagents = R + R.my_atom = src + + hud_list[HEALTH_HUD] = image('icons/mob/hud.dmi', src, "hudhealth100") + hud_list[STATUS_HUD] = image('icons/mob/hud.dmi', src, "hudhealthy") + hud_list[ID_HUD] = image('icons/mob/hud.dmi', src, "hudunknown") + hud_list[WANTED_HUD] = image('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPLOYAL_HUD] = image('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPCHEM_HUD] = image('icons/mob/hud.dmi', src, "hudblank") + hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank") + hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank") + hud_list[STATUS_HUD_OOC] = image('icons/mob/hud.dmi', src, "hudhealthy") + hud_list[NATIONS_HUD] = image('icons/mob/hud.dmi', src, "hudblank") + + ..() + + if(dna) + dna.real_name = real_name + + prev_gender = gender // Debug for plural genders + make_blood() + + // Set up DNA. + if(!delay_ready_dna) + dna.ready_dna(src) + /mob/living/carbon/human/dummy real_name = "Test Dummy" status_flags = GODMODE|CANPUSH @@ -49,8 +83,6 @@ /mob/living/carbon/human/grey/New(var/new_loc) ..(new_loc, "Grey") - spell_list += new /obj/effect/proc_holder/spell/wizard/targeted/remotetalk - /mob/living/carbon/human/human/New(var/new_loc) ..(new_loc, "Human") @@ -63,50 +95,6 @@ h_style = "blue IPC screen" ..(new_loc, "Machine") -/mob/living/carbon/human/New(var/new_loc, var/new_species = null, var/delay_ready_dna=0) - if(!species) - if(new_species) - set_species(new_species,null,1) - else - set_species() - - if(species.language) - var/datum/language/L = all_languages[species.language] - if(L) - languages += L - - var/datum/reagents/R = new/datum/reagents(1000) - reagents = R - R.my_atom = src - - if(!dna) - dna = new /datum/dna(null) - dna.species=species.name - - hud_list[HEALTH_HUD] = image('icons/mob/hud.dmi', src, "hudhealth100") - hud_list[STATUS_HUD] = image('icons/mob/hud.dmi', src, "hudhealthy") - hud_list[ID_HUD] = image('icons/mob/hud.dmi', src, "hudunknown") - hud_list[WANTED_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPLOYAL_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPCHEM_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - hud_list[STATUS_HUD_OOC] = image('icons/mob/hud.dmi', src, "hudhealthy") - hud_list[NATIONS_HUD] = image('icons/mob/hud.dmi', src, "hudblank") - - ..() - - if(dna) - dna.real_name = real_name - - prev_gender = gender // Debug for plural genders - make_blood() - - // Set up DNA. - if(!delay_ready_dna) - dna.ready_dna(src) - - /mob/living/carbon/human/Bump(atom/movable/AM as mob|obj, yes) if ((!( yes ) || now_pushing)) return @@ -1313,7 +1301,8 @@ usr << "\blue [self ? "Your" : "[src]'s"] pulse is [src.get_pulse(GETPULSE_HAND)]." /mob/living/carbon/human/proc/set_species(var/new_species, var/force_organs, var/default_colour) - + + var/datum/species/oldspecies = species if(!dna) if(!new_species) new_species = "Human" @@ -1323,19 +1312,34 @@ else dna.species = new_species - if(species && (species.name && species.name == new_species)) - return - - if(species && species.language) - remove_language(species.language) + if(species) + if(species.name && species.name == new_species) + return + if(species.language) + remove_language(species.language) + + if(species.default_language) + remove_language(species.default_language) + species = all_species[new_species] + + if(oldspecies) + if(oldspecies.default_genes.len) + oldspecies.handle_dna(src,1) // Remove any genes that belong to the old species if(force_organs || !organs || !organs.len) species.create_organs(src) + + if(vessel) + vessel = null + make_blood() if(species.language) add_language(species.language) + + if(species.default_language) + add_language(species.default_language) see_in_dark = species.darksight if(see_in_dark > 2) @@ -1343,9 +1347,6 @@ else see_invisible = SEE_INVISIBLE_LIVING - if(species.default_mutations.len>0 || species.default_blocks.len>0) - do_deferred_species_setup=1 - spawn(0) update_icons() @@ -1358,21 +1359,18 @@ r_skin = 0 g_skin = 0 b_skin = 0 + + if(!dna) + dna = new /datum/dna(null) + dna.species = species.name + dna.real_name = real_name + dna.mutantrace = null species.handle_post_spawn(src) spawn(0) - update_icons() - if(species && species.flags & NO_BLOOD) //We want the var for safety but we can do without the actual blood. - if(vessel.has_reagent("water") || vessel.has_reagent("blood")) - var/water = vessel.get_reagent_amount("water") - var/blood = vessel.get_reagent_amount("blood") - vessel.remove_reagent("water",water) - vessel.remove_reagent("blood",blood) - if(species.bloodflags & BLOOD_SLIME) - vessel.add_reagent("water",560-vessel.total_volume) - else - vessel.add_reagent("blood",560-vessel.total_volume) + overlays.Cut() + update_mutantrace(1) fixblood() if(species) diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 4db067181cb..49b6a73143c 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -32,9 +32,12 @@ timeofdeath = 0 /mob/living/carbon/human/getBrainLoss() - if(species && species.flags & NO_INTORGANS) return + if(species && species.flags & NO_INTORGANS) + return var/res = brainloss var/datum/organ/internal/brain/sponge = internal_organs_by_name["brain"] + if(!sponge) + return if (sponge.is_bruised()) res += 20 if (sponge.is_broken()) @@ -197,6 +200,7 @@ UpdateDamageIcon() hud_updateflag |= 1 << HEALTH_HUD updatehealth() + speech_problem_flag = 1 //Heal MANY external organs, in random order @@ -218,6 +222,7 @@ parts -= picked updatehealth() hud_updateflag |= 1 << HEALTH_HUD + speech_problem_flag = 1 if(update) UpdateDamageIcon() // damage MANY external organs, in random order diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index b98ea2c790f..4e373c7cdb8 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -50,6 +50,10 @@ var/icon/stand_icon = null var/icon/lying_icon = null + + var/voice = "" //Instead of new say code calling GetVoice() over and over and over, we're just going to ask this variable, which gets updated in Life() + + var/speech_problem_flag = 0 var/miming = null //Toggle for the mime's abilities. var/special_voice = "" // For changing our voice. Used by a symptom. diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 8319046d5d5..0f32d9d187e 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -33,27 +33,9 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc var/prev_gender = null // Debug for plural genders var/temperature_alert = 0 var/in_stasis = 0 - var/do_deferred_species_setup=0 var/exposedtimenow = 0 var/firstexposed = 0 -// Doing this during species init breaks shit. -/mob/living/carbon/human/proc/DeferredSpeciesSetup() - var/mut_update=0 - if(species.default_mutations.len>0) - for(var/mutation in species.default_mutations) - if(!(mutation in mutations)) - mutations.Add(mutation) - mut_update=1 - if(species.default_blocks.len>0) - for(var/block in species.default_blocks) - if(!dna.GetSEState(block)) - dna.SetSEState(block,1) - mut_update=1 - if(mut_update) - domutcheck(src,null,MUTCHK_FORCED) - update_mutations() - /mob/living/carbon/human/Life() set invisibility = 0 //set background = 1 @@ -63,10 +45,6 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc ..() - if(do_deferred_species_setup) - DeferredSpeciesSetup() - do_deferred_species_setup=0 - //Apparently, the person who wrote this code designed it so that //blinded get reset each cycle and then get activated later in the //code. Very ugly. I dont care. Moving this stuff here so its easy @@ -84,6 +62,8 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc if(life_tick%30==15) hud_updateflag = 1022 + + voice = GetVoice() //No need to update all of these procs if the guy is dead. if(stat != DEAD && !in_stasis) @@ -252,22 +232,26 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc drop_item() emote("cough") if (disabilities & TOURETTES) + speech_problem_flag = 1 if ((prob(10) && paralysis <= 1)) Stun(10) switch(rand(1, 3)) if(1) emote("twitch") if(2 to 3) - say("[prob(50) ? ";" : ""][pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS")]") + var/tourettes = pick("SHIT", "PISS", "FUCK", "CUNT", "COCKSUCKER", "MOTHERFUCKER", "TITS") + say("[prob(50) ? ";" : ""][tourettes]") var/x_offset = pixel_x + rand(-2,2) //Should probably be moved into the twitch emote at some point. var/y_offset = pixel_y + rand(-1,1) animate(src, pixel_x = pixel_x + x_offset, pixel_y = pixel_y + y_offset, time = 1) animate(pixel_x = pixel_x - x_offset, pixel_y = pixel_y - y_offset, time = 1) if (disabilities & NERVOUS) + speech_problem_flag = 1 if (prob(10)) stuttering = max(10, stuttering) if (getBrainLoss() >= 60 && stat != 2) + speech_problem_flag = 1 if (prob(3)) switch(pick(1,2,3)) if(1) @@ -329,6 +313,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc if(gene.is_active(src)) /* if (prob(10) && prob(gene.instability)) adjustCloneLoss(1) */ + speech_problem_flag = 1 gene.OnMobLife(src) if (radiation) @@ -1091,6 +1076,7 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc if(halloss > 0) adjustHalLoss(-3) else if(sleeping) + speech_problem_flag = 1 handle_dreams() adjustStaminaLoss(-10) adjustHalLoss(-3) @@ -1944,7 +1930,29 @@ var/global/list/brutefireloss_overlays = list("1" = image("icon" = 'icons/mob/sc var/client/C = client for(var/mob/living/carbon/human/H in view(src, 14)) C.images += H.hud_list[NATIONS_HUD] + +/mob/living/carbon/human/handle_silent() + if(..()) + speech_problem_flag = 1 + return silent +/mob/living/carbon/human/handle_slurring() + if(..()) + speech_problem_flag = 1 + return slurring + +/mob/living/carbon/human/handle_stunned() + if(species.flags & NO_PAIN) + stunned = 0 + return 0 + if(..()) + speech_problem_flag = 1 + return stunned + +/mob/living/carbon/human/handle_stuttering() + if(..()) + speech_problem_flag = 1 + return stuttering // Need this in species. //#undef HUMAN_MAX_OXYLOSS diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 028f0efe755..4cc61b36290 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -1,81 +1,152 @@ /mob/living/carbon/human/say(var/message) - if(miming) - if(length(message) >= 2) - if(mind && mind.changeling) - if(copytext(message, 1, 2) != "*" && department_radio_keys[copytext(message, 1, 3)] != "changeling") - return - else - return ..(message) - if(stat == DEAD) - return ..(message) - if(length(message) >= 1) //In case people forget the '*help' command, this will slow them the message and prevent people from saying one letter at a time - if (copytext(message, 1, 2) != "*") - return + var/verb = "says" + var/alt_name = "" + var/message_range = world.view + var/italics = 0 - if(dna) - if(length(message) >= 2) - if (copytext(message, 1, 2) != "*" && department_radio_keys[copytext(message, 1, 3)] != "changeling") - for(var/datum/dna/gene/gene in dna_genes) - if(!gene.block) - continue - if(gene.is_active(src)) - message = gene.OnSay(src,message) - /* - if(dna.mutantrace == "lizard") - if(copytext(message, 1, 2) != "*") - message = replacetext(message, "s", stutter("ss")) + if(client) + if(client.prefs.muted & MUTE_IC) + src << "\red You cannot speak in IC (Muted)." + return - if(dna.mutantrace == "slime" && prob(5)) - if(copytext(message, 1, 2) != "*") - if(copytext(message, 1, 2) == ";") - message = ";" - else - message = "" - message += "SKR" - var/imax = rand(5,20) - for(var/i = 0,iYou're muzzled and cannot speak!
" + return + + var/message_mode = parse_message_mode(message, "headset") + + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + if(name != GetVoice()) + alt_name = "(as [get_id_name("Unknown")])" + + //parse the radio code and consume it + if (message_mode) + if (message_mode == "headset") + message = copytext(message,2) //it would be really nice if the parse procs could do this for us. + else + message = copytext(message,3) + + //parse the language code and consume it + var/datum/language/speaking = parse_language(message) + if(speaking) + message = copytext(message,2+length(speaking.key)) + else if(species.default_language) + speaking = all_languages[species.default_language] + + var/ending = copytext(message, length(message)) + if (speaking) + // This is broadcast to all mobs with the language, + // irrespective of distance or anything else. + if(speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return + //If we've gotten this far, keep going! + verb = speaking.get_spoken_verb(ending) + else + if(ending=="!") + verb=pick("exclaims","shouts","yells") + if(ending=="?") + verb="asks" + + message = trim(message) + + if(speech_problem_flag) + var/list/handle_r = handle_speech_problems(message) + message = handle_r[1] + verb = handle_r[2] + speech_problem_flag = handle_r[3] + + if(!message || message == "") + return + + var/list/obj/item/used_radios = new + + switch (message_mode) + if("headset") + if(l_ear && istype(l_ear,/obj/item/device/radio)) + var/obj/item/device/radio/R = l_ear + R.talk_into(src,message,null,verb,speaking) + used_radios += l_ear + else if(r_ear && istype(r_ear,/obj/item/device/radio)) + var/obj/item/device/radio/R = r_ear + R.talk_into(src,message,null,verb,speaking) + used_radios += r_ear + + if("right ear") + var/obj/item/device/radio/R + var/has_radio = 0 + if(r_ear && istype(r_ear,/obj/item/device/radio)) + R = r_ear + has_radio = 1 + if(r_hand && istype(r_hand, /obj/item/device/radio)) + R = r_hand + has_radio = 1 + if(has_radio) + R.talk_into(src,message,null,verb,speaking) + used_radios += R - if(wear_mask) - if(istype(wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja) && wear_mask:voice == "Unknown") - if(copytext(message, 1, 2) != "*") - var/list/temp_message = text2list(message, " ") - var/list/pick_list = list() - for(var/i = 1, i <= temp_message.len, i++) - pick_list += i - for(var/i=1, i <= abs(temp_message.len/3), i++) - var/H = pick(pick_list) - if(findtext(temp_message[H], "*") || findtext(temp_message[H], ";") || findtext(temp_message[H], ":")) continue - temp_message[H] = ninjaspeak(temp_message[H]) - pick_list -= H - message = list2text(temp_message, " ") - message = replacetext(message, "o", "¤") - message = replacetext(message, "p", "þ") - message = replacetext(message, "l", "£") - message = replacetext(message, "s", "§") - message = replacetext(message, "u", "µ") - message = replacetext(message, "b", "ß") + if("left ear") + var/obj/item/device/radio/R + var/has_radio = 0 + if(l_ear && istype(l_ear,/obj/item/device/radio)) + R = l_ear + has_radio = 1 + if(l_hand && istype(l_hand,/obj/item/device/radio)) + R = l_hand + has_radio = 1 + if(has_radio) + R.talk_into(src,message,null,verb,speaking) + used_radios += R - else if(istype(wear_mask, /obj/item/clothing/mask/horsehead)) - var/obj/item/clothing/mask/horsehead/hoers = wear_mask - if(hoers.voicechange) - if(!(copytext(message, 1, 2) == "*" || (mind && mind.changeling && department_radio_keys[copytext(message, 1, 3)] != "changeling"))) - message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!") + if("intercom") + for(var/obj/item/device/radio/intercom/I in view(1, null)) + I.talk_into(src, message, verb, speaking) + used_radios += I + if("whisper") + whisper_say(message, speaking, alt_name) + return + else + if(message_mode) + if(l_ear && istype(l_ear,/obj/item/device/radio)) + l_ear.talk_into(src,message, message_mode, verb, speaking) + used_radios += l_ear + else if(r_ear && istype(r_ear,/obj/item/device/radio)) + r_ear.talk_into(src,message, message_mode, verb, speaking) + used_radios += r_ear - if ((M_HULK in mutations) && health >= 25 && length(message)) - if(copytext(message, 1, 2) != "*") - message = "[uppertext(message)]!!" //because I don't know how to code properly in getting vars from other files -Bro + var/sound/speech_sound + var/sound_vol + if(species.speech_sounds && prob(species.speech_chance)) + speech_sound = sound(pick(species.speech_sounds)) + sound_vol = 50 - if (src.slurring) - if(copytext(message, 1, 2) != "*") - message = slur(message) + //speaking into radios + if(used_radios.len) + italics = 1 + message_range = 1 + if(speaking) + message_range = speaking.get_talkinto_msg_range(message) + var/msg + if(!speaking || !(speaking.flags & NO_TALK_MSG)) + msg = "\The [src] talks into \the [used_radios[1]]" + for(var/mob/living/M in hearers(5, src)) + if((M != src) && msg) + M.show_message(msg) + if (speech_sound) + sound_vol *= 0.5 - if((species.name == "Vox" || species.name == "Vox Armalis") && prob(20)) - playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) - - ..(message) + ..(message, speaking, verb, alt_name, italics, message_range, speech_sound, sound_vol) //ohgod we should really be passing a datum here. /mob/living/carbon/human/proc/forcesay(list/append) if(stat == CONSCIOUS) @@ -100,6 +171,7 @@ if(findtext(temp, "*", 1, 2)) //emotes return temp = copytext(trim_left(temp), 1, rand(5,8)) + var/trimmed = trim_left(temp) if(length(trimmed)) if(append) @@ -108,25 +180,45 @@ say(temp) winset(client, "input", "text=[null]") -/mob/living/carbon/human/say_understands(var/other,var/datum/language/speaking = null) +/mob/living/carbon/human/say_understands(var/mob/other,var/datum/language/speaking = null) if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak. return 1 - if (istype(other, /mob/living/silicon)) - return 1 - if (istype(other, /mob/living/carbon/brain)) - return 1 - if (istype(other, /mob/living/carbon/slime)) + + if(species.can_understand(other)) return 1 + + //These only pertain to common. Languages are handled by mob/say_understands() + if (!speaking) + if (istype(other, /mob/living/carbon/monkey/diona)) + if(other.languages.len >= 2) //They've sucked down some blood and can speak common now. + return 1 + if (istype(other, /mob/living/silicon)) + return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + if (istype(other, /mob/living/carbon/slime)) + return 1 + + //This is already covered by mob/say_understands() + //if (istype(other, /mob/living/simple_animal)) + // if((other.universal_speak && !speaking) || src.universal_speak || src.universal_understand) + // return 1 + // return 0 + return ..() /mob/living/carbon/human/GetVoice() - if(istype(src.wear_mask, /obj/item/clothing/mask/gas/voice)) - var/obj/item/clothing/mask/gas/voice/V = src.wear_mask - if(V.vchange) - return V.voice - else - return name + + var/voice_sub + for(var/obj/item/gear in list(wear_mask,wear_suit,head)) + if(!gear) + continue + var/obj/item/voice_changer/changer = locate() in gear + if(changer && changer.active && changer.voice) + voice_sub = changer.voice + if(voice_sub) + return voice_sub if(mind && mind.changeling && mind.changeling.mimicing) return mind.changeling.mimicing if(GetSpecialVoice()) @@ -143,4 +235,81 @@ return /mob/living/carbon/human/proc/GetSpecialVoice() - return special_voice \ No newline at end of file + return special_voice + + +/* + ***Deprecated*** + let this be handled at the hear_say or hear_radio proc + This is left in for robot speaking when humans gain binary channel access until I get around to rewriting + robot_talk() proc. + There is no language handling build into it however there is at the /mob level so we accept the call + for it but just ignore it. +*/ + +/mob/living/carbon/human/say_quote(var/message, var/datum/language/speaking = null) + var/verb = "says" + var/ending = copytext(message, length(message)) + + if(speaking) + verb = speaking.get_spoken_verb(ending) + else + if(ending == "!") + verb = "exclaims" + else if(ending == "?") + verb = "asks" + + return verb + +/mob/living/carbon/human/proc/handle_speech_problems(var/message) + + var/list/returns[3] + var/verb = "says" + var/handled = 0 + if(silent || (sdisabilities & MUTE)) + message = "" + handled = 1 + if(istype(wear_mask, /obj/item/clothing/mask/horsehead)) + var/obj/item/clothing/mask/horsehead/hoers = wear_mask + if(hoers.voicechange) + if(mind && mind.changeling && department_radio_keys[copytext(message, 1, 3)] != "changeling") + message = pick("NEEIIGGGHHHH!", "NEEEIIIIGHH!", "NEIIIGGHH!", "HAAWWWWW!", "HAAAWWW!") + verb = pick("whinnies","neighs", "says") + handled = 1 + + if(dna) + for(var/datum/dna/gene/gene in dna_genes) + if(!gene.block) + continue + if(gene.is_active(src)) + message = gene.OnSay(src,message) + handled = 1 + + if(message != "") + if((M_HULK in mutations) && health >= 25 && length(message)) + message = "[uppertext(message)]!!!" + verb = pick("yells","roars","hollers") + handled = 1 + if(slurring) + message = slur(message) + verb = "slurs" + handled = 1 + if(stuttering) + message = stutter(message) + verb = "stammers" + handled = 1 + + var/braindam = getBrainLoss() + if(braindam >= 60) + handled = 1 + if(prob(braindam/4)) + message = stutter(message) + verb = "gibbers" + if(prob(braindam)) + message = uppertext(message) + verb = "yells loudly" + + returns[1] = message + returns[2] = verb + returns[3] = handled + return returns diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 9a47536c759..937c85bce8e 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -290,11 +290,12 @@ proc/get_damage_icon_part(damage_state, body_part) //Robotic limbs are handled in get_icon() so all we worry about are missing or dead limbs. //No icon stored, so we need to start with a basic one. var/datum/organ/external/chest = get_organ("chest") - base_icon = chest.get_icon(g,fat) + if(chest) + base_icon = chest.get_icon(g,fat) - if(chest.status & ORGAN_DEAD) - base_icon.ColorTone(necrosis_color_mod) - base_icon.SetIntensity(0.7) + if(chest.status & ORGAN_DEAD) + base_icon.ColorTone(necrosis_color_mod) + base_icon.SetIntensity(0.7) for(var/datum/organ/external/part in organs) diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm index 58bbfc54dec..43e8af94f50 100644 --- a/code/modules/mob/living/carbon/human/whisper.dm +++ b/code/modules/mob/living/carbon/human/whisper.dm @@ -1,11 +1,8 @@ //Lallander was here /mob/living/carbon/human/whisper(message as text) + var/alt_name = "" - message = trim(copytext(strip_html_simple(message), 1, MAX_MESSAGE_LEN)) - - if (!message || silent || miming) - return - + message = trim_strip_html_properly(message) log_whisper("[src.name]/[src.key] : [message]") if (src.client) @@ -16,28 +13,74 @@ if (src.client.handle_spam_prevention(message,MUTE_IC)) return - if (src.stat == 2) return src.say_dead(message) if (src.stat) return - var/alt_name = "" - if (istype(src, /mob/living/carbon/human) && src.name != GetVoice()) - var/mob/living/carbon/human/H = src - alt_name = " (as [H.get_id_name("Unknown")])" - // Mute disability - if (src.sdisabilities & MUTE) - return + if(name != GetVoice()) + alt_name = "(as [get_id_name("Unknown")])" + + //parse the language code and consume it + var/datum/language/speaking = parse_language(message) + if (speaking) + message = copytext(message,2+length(speaking.key)) + + whisper_say(message, speaking, alt_name) + + +//This is used by both the whisper verb and human/say() to handle whispering +/mob/living/carbon/human/proc/whisper_say(var/message, var/datum/language/speaking = null, var/alt_name="", var/verb="whispers") if (istype(src.wear_mask, /obj/item/clothing/mask/muzzle)) + src << "You're muzzled and cannot speak!" return - var/italics = 1 var/message_range = 1 + var/eavesdropping_range = 2 + var/watching_range = 5 + var/italics = 1 - if(istype(src.wear_mask, /obj/item/clothing/mask/gas/voice/space_ninja)&&src.wear_mask:voice=="Unknown") + var/not_heard //the message displayed to people who could not hear the whispering + if (speaking) + if (speaking.whisper_verb) + verb = speaking.whisper_verb + not_heard = "[verb] something" + else + var/adverb = pick("quietly", "softly") + verb = "[speaking.speech_verb] [adverb]" + not_heard = "[speaking.speech_verb] something [adverb]" + else + not_heard = "[verb] something" //TODO get rid of the null language and just prevent speech if language is null + + message = capitalize(trim(message)) + + if(speech_problem_flag) + var/list/handle_r = handle_speech_problems(message) + message = handle_r[1] + verb = handle_r[2] + if(verb == "yells loudly") + verb = "slurs emphatically" + else + var/adverb = pick("quietly", "softly") + verb = "[verb] [adverb]" + + speech_problem_flag = handle_r[3] + + if(!message || message=="") + return + + //looks like this only appears in whisper. Should it be elsewhere as well? Maybe handle_speech_problems? + var/voice_sub + for(var/obj/item/gear in list(wear_mask,wear_suit,head)) + if(!gear) + continue + var/obj/item/voice_changer/changer = locate() in gear + if(changer && changer.active && changer.voice) + voice_sub = changer.voice + + if(voice_sub == "Unknown") if(copytext(message, 1, 2) != "*") var/list/temp_message = text2list(message, " ") var/list/pick_list = list() @@ -49,97 +92,60 @@ temp_message[H] = ninjaspeak(temp_message[H]) pick_list -= H message = list2text(temp_message, " ") - message = replacetext(message, "o", "?") - message = replacetext(message, "p", "?") - message = replacetext(message, "l", "?") - message = replacetext(message, "s", "?") - message = replacetext(message, "u", "?") - message = replacetext(message, "b", "?") - - if (src.stuttering) - message = stutter(message) - - for (var/obj/O in view(message_range, src)) - spawn (0) - if (O) - O.hear_talk(src, message) + message = replacetext(message, "o", "�") + message = replacetext(message, "p", "�") + message = replacetext(message, "l", "�") + message = replacetext(message, "s", "�") + message = replacetext(message, "u", "�") + message = replacetext(message, "b", "�") var/list/listening = hearers(message_range, src) listening |= src + //ghosts + for (var/mob/M in dead_mob_list) //does this include players who joined as observers as well? + if (!(M.client)) + continue + if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) + listening |= M + //Pass whispers on to anything inside the immediate listeners. for(var/mob/L in listening) for(var/mob/C in L.contents) if(istype(C,/mob/living)) listening += C - var/list/eavesdropping = hearers(2, src) + //pass on the message to objects that can hear us. + for (var/obj/O in view(message_range, src)) + spawn (0) + if (O) + O.hear_talk(src, message, verb, speaking) + + var/list/eavesdropping = hearers(eavesdropping_range, src) eavesdropping -= src eavesdropping -= listening - var/list/watching = hearers(5, src) + var/list/watching = hearers(watching_range, src) watching -= src watching -= listening watching -= eavesdropping - var/list/heard_a = list() // understood us - var/list/heard_b = list() // didn't understand us + //now mobs + var/speech_bubble_test = say_test(message) + var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]") + spawn(30) del(speech_bubble) - for (var/mob/M in listening) - if (M.say_understands(src)) - heard_a += M - else - heard_b += M + for(var/mob/M in listening) + M << speech_bubble + M.hear_say(message, verb, speaking, alt_name, italics, src) - var/rendered = null + if (eavesdropping.len) + var/new_message = stars(message) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less. + for(var/mob/M in eavesdropping) + M << speech_bubble + M.hear_say(new_message, verb, speaking, alt_name, italics, src) - for (var/mob/M in watching) - if (M.say_understands(src)) - rendered = "[src.name] whispers something." - else - rendered = "[src.voice_name] whispers something." - M.show_message(rendered, 2) - - if (length(heard_a)) - var/message_a = message - - if (italics) - message_a = "[message_a]" - //This appears copied from carbon/living say.dm so the istype check for mob is probably not needed. Appending for src is also not needed as the game will check that automatically. - rendered = "[GetVoice()][alt_name] whispers, \"[message_a]\"" - - for (var/mob/M in heard_a) - M.show_message(rendered, 2) - - if (length(heard_b)) - var/message_b - - message_b = stars(message) - - if (italics) - message_b = "[message_b]" - - rendered = "[src.voice_name] whispers, \"[message_b]\"" - - for (var/mob/M in heard_b) - M.show_message(rendered, 2) - - for (var/mob/M in eavesdropping) - if (M.say_understands(src)) - var/message_c - message_c = stars(message) - rendered = "[GetVoice()][alt_name] whispers, \"[message_c]\"" - M.show_message(rendered, 2) - else - rendered = "[src.voice_name] whispers something." - M.show_message(rendered, 2) - - if (italics) - message = "[message]" - rendered = "[GetVoice()][alt_name] whispers, \"[message]\"" - - for (var/mob/M in dead_mob_list) - if (!(M.client)) - continue - if (M.stat > 1 && !(M in heard_a) && (M.client.prefs.toggles & CHAT_GHOSTEARS)) + if (watching.len) + var/rendered = "[src.name] [not_heard]." + for (var/mob/M in watching) M.show_message(rendered, 2) diff --git a/code/modules/mob/living/carbon/metroid/say.dm b/code/modules/mob/living/carbon/metroid/say.dm index 89708595da4..f4de10ceb74 100644 --- a/code/modules/mob/living/carbon/metroid/say.dm +++ b/code/modules/mob/living/carbon/metroid/say.dm @@ -21,3 +21,16 @@ return 1 return ..() +/mob/living/carbon/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + if (speaker in Friends) + speech_buffer = list() + speech_buffer.Add(speaker) + speech_buffer.Add(lowertext(html_decode(message))) + ..() + +/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="") + if (speaker in Friends) + speech_buffer = list() + speech_buffer.Add(speaker) + speech_buffer.Add(lowertext(html_decode(message))) + ..() diff --git a/code/modules/mob/living/carbon/species.dm b/code/modules/mob/living/carbon/species.dm index 6512ee05247..02587d04994 100644 --- a/code/modules/mob/living/carbon/species.dm +++ b/code/modules/mob/living/carbon/species.dm @@ -8,10 +8,10 @@ var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. var/eyes = "eyes_s" // Icon for eyes. + var/blurb = "A completely nondescript species." // A brief lore summary for use in the chargen screen. var/primitive // Lesser form, if any (ie. monkey for humans) var/tail // Name of tail image in species effects icon file. - var/language // Default racial language, if any. var/unarmed //For empty hand harm-intent attack var/unarmed_type = /datum/unarmed_attack var/mutantrace // Safeguard due to old code. @@ -41,11 +41,8 @@ var/brute_mod = null // Physical damage reduction/malus. var/burn_mod = null // Burn damage reduction/malus. - // For grays var/max_hurt_damage = 9 // Max melee damage dealt + 5 if hulk - var/list/default_mutations = list() - var/list/default_blocks = list() // Don't touch. - var/list/default_block_names = list() // Use this instead, using the names from setupgame.dm + var/list/default_genes = list() var/flags = 0 // Various specific features. var/bloodflags=0 @@ -60,12 +57,21 @@ //Used in icon caching. var/race_key = 0 var/icon/icon_template - + + // Language/culture vars. + var/default_language = "Galactic Common" // Default language is used when 'say' is used without modifiers. + var/language = "Galactic Common" // Default racial language, if any. + var/secondary_langs = list() // The names of secondary languages that are available to this species. + var/list/speech_sounds // A list of sounds to potentially play when speaking. + var/list/speech_chance // The likelihood of a speech sound playing. /datum/species/New() unarmed = new unarmed_type() - +/datum/species/proc/get_random_name(var/gender) + var/datum/language/species_language = all_languages[language] + return species_language.get_random_name(gender) + /datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. //This is a basic humanoid limb setup. H.organs = list() @@ -81,7 +87,7 @@ H.organs_by_name["l_foot"] = new/datum/organ/external/l_foot(H.organs_by_name["l_leg"]) H.organs_by_name["r_foot"] = new/datum/organ/external/r_foot(H.organs_by_name["r_leg"]) - if (name!="Slime People") + if (name != "Slime People") new/datum/organ/internal/heart(H) new/datum/organ/internal/lungs(H) new/datum/organ/internal/liver(H) @@ -247,6 +253,10 @@ return 1 /datum/species/proc/handle_post_spawn(var/mob/living/carbon/C) //Handles anything not already covered by basic species assignment. + handle_dna(C) + return + +/datum/species/proc/handle_dna(var/mob/living/carbon/C, var/remove) //Handles DNA mutations, as that doesn't work at init. return // Used for species-specific names (Vox, etc) @@ -262,6 +272,10 @@ return message /datum/species/proc/equip(var/mob/living/carbon/human/H) + return + +/datum/species/proc/can_understand(var/mob/other) + return /datum/species/human name = "Human" @@ -272,17 +286,29 @@ flags = HAS_LIPS | HAS_UNDERWEAR | CAN_BE_FAT bodyflags = HAS_SKIN_TONE unarmed_type = /datum/unarmed_attack/punch + blurb = "Humanity originated in the Sol system, and over the last five centuries has spread \ + colonies across a wide swathe of space. They hold a wide range of forms and creeds.

\ + While the central Sol government maintains control of its far-flung people, powerful corporate \ + interests, rampant cyber and bio-augmentation and secretive factions make life on most human \ + worlds tumultous at best." /datum/species/unathi name = "Unathi" icobase = 'icons/mob/human_races/r_lizard.dmi' deform = 'icons/mob/human_races/r_def_lizard.dmi' path = /mob/living/carbon/human/unathi + default_language = "Galactic Common" language = "Sinta'unathi" tail = "sogtail" unarmed_type = /datum/unarmed_attack/claws primitive = /mob/living/carbon/monkey/unathi darksight = 3 + + blurb = "A heavily reptillian species, Unathi (or 'Sinta as they call themselves) hail from the \ + Uuosa-Eso system, which roughly translates to 'burning mother'.

Coming from a harsh, radioactive \ + desert planet, they mostly hold ideals of honesty, virtue, martial combat and bravery above all \ + else, frequently even their own lives. They prefer warmer temperatures than most species and \ + their native tongue is a heavy hissing laungage called Sinta'Unathi." flags = HAS_LIPS | HAS_UNDERWEAR bodyflags = FEET_CLAWS | HAS_TAIL | HAS_SKIN_COLOR @@ -305,10 +331,17 @@ icobase = 'icons/mob/human_races/r_tajaran.dmi' deform = 'icons/mob/human_races/r_def_tajaran.dmi' path = /mob/living/carbon/human/tajaran + default_language = "Galactic Common" language = "Siik'tajr" tail = "tajtail" unarmed_type = /datum/unarmed_attack/claws darksight = 8 + + blurb = "The Tajaran race is a species of feline-like bipeds hailing from the planet of Ahdomai in the \ + S'randarr system. They have been brought up into the space age by the Humans and Skrell, and have been \ + influenced heavily by their long history of Slavemaster rule. They have a structured, clan-influenced way \ + of family and politics. They prefer colder environments, and speak a variety of languages, mostly Siik'Maas, \ + using unique inflections their mouths form." cold_level_1 = 200 cold_level_2 = 140 @@ -331,9 +364,16 @@ icobase = 'icons/mob/human_races/r_skrell.dmi' deform = 'icons/mob/human_races/r_def_skrell.dmi' path = /mob/living/carbon/human/skrell + default_language = "Galactic Common" language = "Skrellian" primitive = /mob/living/carbon/monkey/skrell unarmed_type = /datum/unarmed_attack/punch + + blurb = "An amphibious species, Skrell come from the star system known as Qerr'Vallis, which translates to 'Star of \ + the royals' or 'Light of the Crown'.

Skrell are a highly advanced and logical race who live under the rule \ + of the Qerr'Katish, a caste within their society which keeps the empire of the Skrell running smoothly. Skrell are \ + herbivores on the whole and tend to be co-operative with the other species of the galaxy, although they rarely reveal \ + the secrets of their empire to their allies." flags = HAS_LIPS | HAS_UNDERWEAR bloodflags = BLOOD_GREEN @@ -348,8 +388,20 @@ icobase = 'icons/mob/human_races/r_vox.dmi' deform = 'icons/mob/human_races/r_def_vox.dmi' path = /mob/living/carbon/human/vox - language = "Vox-pidgin" + + default_language = "Galactic Common" + language = "Vox-pidgin" + speech_sounds = list('sound/voice/shriek1.ogg') + speech_chance = 20 + unarmed_type = /datum/unarmed_attack/claws //I dont think it will hurt to give vox claws too. + + blurb = "The Vox are the broken remnants of a once-proud race, now reduced to little more than \ + scavenging vermin who prey on isolated stations, ships or planets to keep their own ancient arkships \ + alive. They are four to five feet tall, reptillian, beaked, tailed and quilled; human crews often \ + refer to them as 'shitbirds' for their violent and offensive nature, as well as their horrible \ + smell.

Most humans will never meet a Vox raider, instead learning of this insular species through \ + dealing with their traders and merchants; those that do rarely enjoy the experience." warning_low_pressure = 50 hazard_low_pressure = 0 @@ -393,7 +445,6 @@ name = "Vox Armalis" icobase = 'icons/mob/human_races/r_armalis.dmi' deform = 'icons/mob/human_races/r_armalis.dmi' - language = "Vox-pidgin" path = /mob/living/carbon/human/voxarmalis unarmed_type = /datum/unarmed_attack/claws/armalis @@ -454,20 +505,19 @@ icobase = 'icons/mob/human_races/r_kidan.dmi' deform = 'icons/mob/human_races/r_def_kidan.dmi' path = /mob/living/carbon/human/kidan + default_language = "Galactic Common" language = "Chittin" unarmed_type = /datum/unarmed_attack/claws - brute_mod = 0.8 flags = IS_WHITELISTED bloodflags = BLOOD_GREEN bodyflags = FEET_CLAWS - - /datum/species/slime name = "Slime People" + default_language = "Galactic Common" language = "Bubblish" path = /mob/living/carbon/human/slime primitive = /mob/living/carbon/slime @@ -478,37 +528,48 @@ /datum/species/slime/handle_post_spawn(var/mob/living/carbon/human/H) H.dna = new /datum/dna(null) - H.dna.species=H.species.name + H.dna.real_name = H.real_name + H.dna.species = H.species.name H.dna.mutantrace = "slime" - H.update_mutantrace() - return ..() + ..() -/datum/species/grey // /vg/ +/datum/species/grey name = "Grey" icobase = 'icons/mob/human_races/r_grey.dmi' deform = 'icons/mob/human_races/r_def_grey.dmi' - language = "Grey" + default_language = "Galactic Common" + //language = "Grey" // Perhaps if they ever get a hivemind unarmed_type = /datum/unarmed_attack/punch darksight = 5 // BOOSTED from 2 eyes = "grey_eyes_s" brute_mod = 1.25 //greys are fragile + + default_genes = list(M_REMOTE_TALK) primitive = /mob/living/carbon/monkey // TODO flags = IS_WHITELISTED | HAS_LIPS | HAS_UNDERWEAR | CAN_BE_FAT - - // Both must be set or it's only a 45% chance of manifesting. - default_mutations=list(M_REMOTE_TALK) - default_block_names=list("REMOTETALK") - + +/datum/species/grey/handle_dna(var/mob/living/carbon/C, var/remove) + if(!remove) + C.dna.SetSEState(REMOTETALKBLOCK,1,1) + C.mutations |= M_REMOTE_TALK + genemutcheck(C,REMOTETALKBLOCK,null,MUTCHK_FORCED) + else + C.dna.SetSEState(REMOTETALKBLOCK,0,1) + C.mutations -= M_REMOTE_TALK + genemutcheck(C,REMOTETALKBLOCK,null,MUTCHK_FORCED) + C.update_mutations() + ..() /datum/species/diona name = "Diona" icobase = 'icons/mob/human_races/r_diona.dmi' deform = 'icons/mob/human_races/r_def_plant.dmi' path = /mob/living/carbon/human/diona + default_language = "Galactic Common" language = "Rootspeak" unarmed_type = /datum/unarmed_attack/diona primitive = /mob/living/carbon/monkey/diona @@ -523,6 +584,14 @@ heat_level_1 = 300 heat_level_2 = 350 heat_level_3 = 700 + + blurb = "Commonly referred to (erroneously) as 'plant people', the Dionaea are a strange space-dwelling collective \ + species hailing from Epsilon Ursae Minoris. Each 'diona' is a cluster of numerous cat-sized organisms called nymphs; \ + there is no effective upper limit to the number that can fuse in gestalt, and reports exist of the Epsilon Ursae \ + Minoris primary being ringed with a cloud of singing space-station-sized entities.

The Dionaea coexist peacefully with \ + all known species, especially the Skrell. Their communal mind makes them slow to react, and they have difficulty understanding \ + even the simplest concepts of other minds. Their alien physiology allows them survive happily off a diet of nothing but light, \ + water and other radiation." flags = NO_BREATHE | REQUIRE_LIGHT | IS_PLANT | RAD_ABSORB | NO_BLOOD | IS_SLOW | NO_PAIN @@ -532,6 +601,12 @@ flesh_color = "#907E4A" reagent_tag = IS_DIONA + +/datum/species/diona/can_understand(var/mob/other) + var/mob/living/carbon/monkey/diona/D = other + if(istype(D)) + return 1 + return 0 /datum/species/diona/handle_post_spawn(var/mob/living/carbon/human/H) H.gender = NEUTER @@ -561,6 +636,7 @@ icobase = 'icons/mob/human_races/r_machine.dmi' deform = 'icons/mob/human_races/r_machine.dmi' path = /mob/living/carbon/human/machine + default_language = "Galactic Common" language = "Trinary" unarmed_type = /datum/unarmed_attack/punch diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index bad5c10d9e0..51988feaf22 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -1,25 +1,22 @@ var/list/department_radio_keys = list( - ":r" = "right ear", "#r" = "right ear", ".r" = "right ear", "!r" = "fake right ear", - ":l" = "left ear", "#l" = "left ear", ".l" = "left ear", "!l" = "fake left ear", + ":r" = "right ear", "#r" = "right ear", ".r" = "right ear", + ":l" = "left ear", "#l" = "left ear", ".l" = "left ear", ":i" = "intercom", "#i" = "intercom", ".i" = "intercom", ":h" = "department", "#h" = "department", ".h" = "department", + ":+" = "special", "#+" = "special", ".+" = "special", //activate radio-specific special functions ":c" = "Command", "#c" = "Command", ".c" = "Command", ":n" = "Science", "#n" = "Science", ".n" = "Science", ":m" = "Medical", "#m" = "Medical", ".m" = "Medical", ":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering", ":s" = "Security", "#s" = "Security", ".s" = "Security", ":w" = "whisper", "#w" = "whisper", ".w" = "whisper", - ":b" = "binary", "#b" = "binary", ".b" = "binary", - ":d" = "drone", "#d" = "drone", ".d" = "drone", - ":a" = "alientalk", "#a" = "alientalk", ".a" = "alientalk", ":t" = "Syndicate", "#t" = "Syndicate", ".t" = "Syndicate", ":u" = "Supply", "#u" = "Supply", ".u" = "Supply", ":z" = "Service", "#z" = "Service", ".z" = "Service", - ":g" = "changeling", "#g" = "changeling", ".g" = "changeling", + ":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private", - - ":R" = "right ear", "#R" = "right ear", ".R" = "right ear", "!R" = "fake right ear", - ":L" = "left ear", "#L" = "left ear", ".L" = "left ear", "!L" = "fake left ear", + ":R" = "right ear", "#R" = "right ear", ".R" = "right ear", + ":L" = "left ear", "#L" = "left ear", ".L" = "left ear", ":I" = "intercom", "#I" = "intercom", ".I" = "intercom", ":H" = "department", "#H" = "department", ".H" = "department", ":C" = "Command", "#C" = "Command", ".C" = "Command", @@ -28,40 +25,35 @@ var/list/department_radio_keys = list( ":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering", ":S" = "Security", "#S" = "Security", ".S" = "Security", ":W" = "whisper", "#W" = "whisper", ".W" = "whisper", - ":D" = "drone", "#D" = "drone", ".D" = "drone", - ":B" = "binary", "#B" = "binary", ".B" = "binary", - ":A" = "alientalk", "#A" = "alientalk", ".A" = "alientalk", ":T" = "Syndicate", "#T" = "Syndicate", ".T" = "Syndicate", ":U" = "Supply", "#U" = "Supply", ".U" = "Supply", ":Z" = "Service", "#Z" = "Service", ".Z" = "Service", - ":G" = "changeling", "#G" = "changeling", ".G" = "changeling" - - /* //kinda localization -- rastaf0 - //same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding. - ":ê" = "right hand", "#ê" = "right hand", ".ê" = "right hand", - ":ä" = "left hand", "#ä" = "left hand", ".ä" = "left hand", - ":ø" = "intercom", "#ø" = "intercom", ".ø" = "intercom", - ":ð" = "department", "#ð" = "department", ".ð" = "department", - ":ñ" = "Command", "#ñ" = "Command", ".ñ" = "Command", - ":ò" = "Science", "#ò" = "Science", ".ò" = "Science", - ":ü" = "Medical", "#ü" = "Medical", ".ü" = "Medical", - ":ó" = "Engineering", "#ó" = "Engineering", ".ó" = "Engineering", - ":û" = "Security", "#û" = "Security", ".û" = "Security", - ":ö" = "whisper", "#ö" = "whisper", ".ö" = "whisper", - ":è" = "binary", "#è" = "binary", ".è" = "binary", - ":ô" = "alientalk", "#ô" = "alientalk", ".ô" = "alientalk", - ":å" = "Syndicate", "#å" = "Syndicate", ".å" = "Syndicate", - ":é" = "Supply", "#é" = "Supply", ".é" = "Supply", - ":ï" = "changeling", "#ï" = "changeling", ".ï" = "changeling" */ + ":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private" ) + +var/list/channel_to_radio_key = new +proc/get_radio_key_from_channel(var/channel) + var/key = channel_to_radio_key[channel] + if(!key) + for(var/radio_key in department_radio_keys) + if(department_radio_keys[radio_key] == channel) + key = radio_key + break + if(!key) + key = "" + channel_to_radio_key[channel] = key + + return key + /mob/living/proc/binarycheck() + if (istype(src, /mob/living/silicon/pai)) return - if (issilicon(src)) - return 1 + if (!ishuman(src)) return + var/mob/living/carbon/human/H = src if (H.l_ear || H.r_ear) var/obj/item/device/radio/headset/dongle @@ -72,446 +64,78 @@ var/list/department_radio_keys = list( if(!istype(dongle)) return if(dongle.translate_binary) return 1 -/mob/living/proc/hivecheck() - if (isalien(src)) return 1 - if (!ishuman(src)) return - var/mob/living/carbon/human/H = src - if (H.l_ear || H.r_ear) - var/obj/item/device/radio/headset/dongle - if(istype(H.l_ear,/obj/item/device/radio/headset)) - dongle = H.l_ear - else - dongle = H.r_ear - if(!istype(dongle)) return - if(dongle.translate_hive) return 1 - -/mob/living/say(var/message) - - /* - Formatting and sanitizing. - */ - - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - - - /* - Sanity checking and speech failure. - */ - - if (!message) - return - - if(silent) - return - - if (stat == 2) // Dead. - return say_dead(message) - else if (stat) // Unconcious. - return - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "\red You cannot speak in IC (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - // undo last word status. - - if(ishuman(src)) - var/mob/living/carbon/human/H=src - if(H.said_last_words) - H.said_last_words=0 - - // Mute disability - if (sdisabilities & MUTE) - return - - // Muzzled. - if (istype(wear_mask, /obj/item/clothing/mask/muzzle)) - return - - // Emotes. - if (copytext(message, 1, 2) == "*" && !stat) - return emote(copytext(message, 2)) - - /* - Identity hiding. - */ - var/alt_name = "" - if (istype(src, /mob/living/carbon/human) && name != GetVoice()) - var/mob/living/carbon/human/H = src - alt_name = " (as [H.get_id_name("Unknown")])" - - /* - Now we get into the real meat of the say processing. Determining the message mode. - */ - - var/italics = 0 - var/message_range = null - var/message_mode = null - - var/datum/language/speaking = null //For use if a specific language is being spoken. - - var/braindam = getBrainLoss() - if (braindam >= 60) - if(prob(braindam/4)) - message = stutter(message) - if(prob(braindam)) - message = uppertext(message) - - // General public key. Special message handling - var/mmode - var/cprefix = "" - if(length(message) >= 2) - cprefix = copytext(message, 1, 3) - if(cprefix in department_radio_keys) - mmode = department_radio_keys[cprefix] - if (copytext(message, 1, 2) == ";" || (prob(braindam/2) && !mmode)) - message_mode = "headset" - message = copytext(message, 2) - // Begin checking for either a message mode or a language to speak. - else if (length(message) >= 2) - var/channel_prefix = copytext(message, 1, 3) - - //Check if the person is speaking a language that they know. - if(languages.len) - for(var/datum/language/L in languages) - if(lowertext(channel_prefix) == ":[L.key]") - speaking = L - break - message_mode = department_radio_keys[channel_prefix] - if (message_mode || speaking || copytext(message,1,2) == ":") - message = trim(copytext(message, 3)) - if (!(istype(src,/mob/living/carbon/human) && !isAI(src) && !isrobot(src) || istype(src,/mob/living/carbon/monkey) || istype(src, /mob/living/simple_animal/parrot) || isrobot(src) && (message_mode=="department") || isAI(src) && (message_mode=="department") || (message_mode in radiochannels))) - message_mode = null //only humans can use headsets - - if(traumatic_shock > 61 && prob(50)) - if(message_mode) - src << "You try to use your radio, but you are in too much pain." - message_mode = null //people in shock will have a high chance of not being able to speak on radio; needed since people don't instantly pass out at 100 damage. - - message = capitalize(message) - - if (!message) - return - - if (stuttering) - message = stutter(message) - - /////////////////////////////////////////////////////////// - // VIDEO KILLED THE RADIO STAR V2.0 - // - // EXPERIMENTAL CODE BY YOUR PALS AT /vg/ - /////////////////////////////////////////////////////////// - - var/list/obj/item/used_radios = new - - // Actually speaking on the radio? - var/is_speaking_radio = 0 - - // Devices selected - var/list/devices=list() - - // Select all always_talk devices - // Carbon lifeforms - //if(istype(src, /mob/living/carbon)) - for(var/obj/item/device/radio/R in contents) - if(R.always_talk) - devices += R - - //src << "Speaking on [message_mode]: [message]" - if(message_mode) - switch (message_mode) - if ("right ear") - if(iscarbon(src)) - var/mob/living/carbon/C=src - if(C:r_ear) devices += C:r_ear - message_mode="headset" - message_range = 1 - italics = 1 - - if ("left ear") - if(iscarbon(src)) - var/mob/living/carbon/C=src - if(C:l_ear) devices += C:l_ear - message_mode="headset" - message_range = 1 - italics = 1 - - // Select a headset and speak into it without actually sending a message - if ("fake") - if(iscarbon(src)) - var/mob/living/carbon/C=src - if(C:l_ear) used_radios += C:l_ear - if(C:r_ear) used_radios += C:r_ear - if(issilicon(src)) - var/mob/living/silicon/Ro=src - if(Ro:radio) devices += Ro:radio - message_range = 1 - italics = 1 - if ("fake left ear") - if(iscarbon(src)) - var/mob/living/carbon/C=src - if(C:l_ear) used_radios += C:l_ear - message_range = 1 - italics = 1 - if ("fake right ear") - if(iscarbon(src)) - var/mob/living/carbon/C=src - if(C:r_ear) used_radios += C:r_ear - message_range = 1 - italics = 1 - - if ("intercom") - for (var/obj/item/device/radio/intercom/I in view(1, null)) - devices += I - message_mode=null - message_range = 1 - italics = 1 - - //I see no reason to restrict such way of whispering - if ("whisper") - whisper(message) - return - - if ("binary") - if(robot_talk_understand || binarycheck()) - //message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) //seems redundant - robot_talk(message) - return - - if ("alientalk") - if(alien_talk_understand || hivecheck()) - //message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) //seems redundant - alien_talk(message) - return - - if ("pAI") - message_range = 1 - italics = 1 - - if("changeling") - if(mind && mind.changeling) - log_say("[key_name(src)] ([mind.changeling.changelingID]): [message]") - for(var/mob/Changeling in mob_list) - if(istype(Changeling, /mob/living/silicon)) continue //WHY IS THIS NEEDED? - if((Changeling.mind && Changeling.mind.changeling) || istype(Changeling, /mob/dead/observer)) - Changeling << "[mind.changeling.changelingID]: [message]" - else if(istype(Changeling,/mob/dead/observer) && (Changeling.client && Changeling.client.prefs.toggles & CHAT_GHOSTEARS)) - Changeling << "[mind.changeling.changelingID] (: (Follow) [message]" - return - else // headset, department channels. - if(iscarbon(src)) - var/mob/living/carbon/C=src - if(C:l_ear) devices += C:l_ear - if(C:r_ear) devices += C:r_ear - if(issilicon(src)) - if(isAI(src))//for the AI's radio. This can't be with the borg thing above due to typecasting. - var/mob/living/silicon/ai/A = src - if(A.aiRadio) - A.aiRadio.talk_into(src, message, message_mode) - used_radios += A.aiRadio - else - var/mob/living/silicon/Ro=src - if(!isAI(Ro)) - if(Ro:radio) - devices += Ro:radio - else - warning("[src] has no radio!") - message_range = 1 - italics = 1 - if(devices.len>0) - for(var/obj/item/device/radio/R in devices) - if(istype(R)) - R.talk_into(src, message, message_mode) - used_radios += R - is_speaking_radio = 1 - - ///////////////////////////////////////////////////////////////// - // - ///////////////////////////////////////////////////////////////// - - var/datum/gas_mixture/environment = loc.return_air() - if(environment) - var/pressure = environment.return_pressure() - if(pressure < SOUND_MINIMUM_PRESSURE) - italics = 1 - message_range = 1 - - var/list/listening - - listening = get_mobs_in_view(message_range, src) - var/list/onscreen = viewers() - for(var/mob/M in player_list) - if (!M.client) - continue //skip monkeys and leavers - if (istype(M, /mob/new_player)) - continue - if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTEARS) && src.client) // src.client is so that ghosts don't have to listen to mice - listening|=M +/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/italics=0, var/message_range = world.view, var/sound/speech_sound, var/sound_vol) var/turf/T = get_turf(src) - var/list/W = hear(message_range, T) - for (var/obj/O in ((W | contents)-used_radios)) - W |= O + //handle nonverbal and sign languages here + if (speaking) + if (speaking.flags & NONVERBAL) + if (prob(30)) + src.custom_emote(1, "[pick(speaking.signlang_verb)].") - for (var/mob/M in W) - W |= M.contents + if (speaking.flags & SIGNLANG) + return say_signlang(message, pick(speaking.signlang_verb), speaking) - for (var/atom/A in W) - if(istype(A, /mob/living/simple_animal/parrot)) //Parrot speech mimickry - if(A == src) - continue //Dont imitate ourselves + var/list/listening = list() + var/list/listening_obj = list() - var/mob/living/simple_animal/parrot/P = A - if(P.speech_buffer.len >= 10) - P.speech_buffer.Remove(pick(P.speech_buffer)) - P.speech_buffer.Add(message) + if(T) + //make sure the air can transmit speech - speaker's side + var/datum/gas_mixture/environment = T.return_air() + var/pressure = (environment)? environment.return_pressure() : 0 + if(pressure < SOUND_MINIMUM_PRESSURE) + message_range = 1 - if (isslime(A)) - var/mob/living/carbon/slime/S = A - if (src in S.Friends) - S.speech_buffer = list() - S.speech_buffer.Add(src) - S.speech_buffer.Add(lowertext(html_decode(message))) + if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + italics = 1 + sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact - if(istype(A, /obj/)) //radio in pocket could work, radio in backpack wouldn't --rastaf0 - var/obj/O = A - spawn (0) - if(O && !istype(O.loc, /obj/item/weapon/storage)) - O.hear_talk(src, message) + var/list/hear = hear(message_range, T) + var/list/hearturfs = list() + for(var/I in hear) + if(istype(I, /mob/)) + var/mob/M = I + listening += M + hearturfs += M.locs[1] + for(var/obj/O in M.contents) + listening_obj |= O + else if(istype(I, /obj/)) + var/obj/O = I + hearturfs += O.locs[1] + listening_obj |= O - var/list/heard_a = list() // understood us - var/list/heard_b = list() // didn't understand us - - for (var/M in listening) - if(hascall(M,"say_understands")) - if (M:say_understands(src,speaking)) - heard_a += M - else - heard_b += M - else - heard_a += M + for(var/mob/M in player_list) + if(M.stat == DEAD && M.client && (M.client.prefs.toggles & CHAT_GHOSTEARS)) + listening |= M + continue + if(M.loc && M.locs[1] in hearturfs) + listening |= M var/speech_bubble_test = say_test(message) var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]") spawn(30) del(speech_bubble) - for(var/mob/M in hearers(5, src)) - if(M != src && is_speaking_radio) - M:show_message("[src] talks into [used_radios.len ? used_radios[1] : "radio"]") + for(var/mob/M in listening) + M << speech_bubble + M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol) -/* if(message_mode == null) - var/accent = "en-us" - var/voice = "m7" - var/speed = 175 - var/pitch = 0 - var/echo = 10 - if(istype(src, /mob/living/silicon/ai)) - echo = 90 - if(istype(src, /mob/living/silicon/robot)) - echo = 60 - if(src.client && src.client.prefs) - accent = src.client.prefs.accent - voice = src.client.prefs.voice - speed = src.client.prefs.talkspeed - pitch = src.client.prefs.pitch - src:texttospeech(message, speed, pitch, accent, "+[voice]", echo)*/ - - var/rendered = null - - if (length(heard_a)) - var/message_a = say_quote(message,speaking) - - if (italics) - message_a = "[message_a]" - - var/message_ghost = "[message_a]" // bold so ghosts know the person is in view. - rendered = "[GetVoice()][alt_name] [message_a]" - var/rendered2 = null - - for (var/mob/M in heard_a) - //BEGIN TELEPORT CHANGES -/* if(message_mode == null && fexists("sound/playervoices/[src.ckey].ogg")) - if(M.client) - if(M.client.prefs) - if(M.client.prefs.sound & SOUND_VOICES) - M.playsound_local(get_turf(src), "sound/playervoices/[src.ckey].ogg", 70, 0, 5, 1)*/ - if(!istype(M, /mob/new_player)) - if(M && M.stat == DEAD) - if (M.client && M.client.prefs && (M.client.prefs.toggles & CHAT_GHOSTEARS) && M in onscreen) - rendered2 = "[GetVoice()] [alt_name] (Follow) [message_ghost]" - else - rendered2 = "[GetVoice()] [alt_name] (Follow) [message_a]" - M:show_message(rendered2, 2) - continue - //END CHANGES - - if(hascall(M,"show_message")) - var/deaf_message = "" - var/deaf_type = 1 - if(M != src) - deaf_message = "[name][alt_name] talks but you cannot hear them." - else - deaf_message = "You cannot hear yourself!" - deaf_type = 2 // Since you should be able to hear yourself without looking - M:show_message(rendered, 2, deaf_message, deaf_type) - M << speech_bubble - - if (length(heard_b)) - - var/message_b - message_b = stars(message) - message_b = say_quote(message_b,speaking) - - if (italics) - message_b = "[message_b]" - - rendered = "[name][alt_name] [message_b]" //Voice_name isn't too useful. You'd be able to tell who was talking presumably. - var/rendered2 = null - - for (var/M in heard_b) - var/mob/MM - if(istype(M, /mob)) - MM = M - if(!istype(MM, /mob/new_player) && MM) - if(MM && MM.stat == DEAD) - rendered2 = "[voice_name] (Follow) [message_b]" - MM:show_message(rendered2, 2) - continue - if(hascall(M,"show_message")) - M:show_message(rendered, 2) - M << speech_bubble - - /* - if(M.client) - - if(!M.client.bubbles || M == src) - var/image/I = image('icons/effects/speechbubble.dmi', B, "override") - I.override = 1 - M << I - */ /* - - flick("[presay]say", B) - - if(istype(loc, /turf)) - B.loc = loc - else - B.loc = loc.loc - - spawn() - sleep(11) - del(B) - */ + for(var/obj/O in listening_obj) + spawn(0) + if(O) //It's possible that it could be deleted in the meantime. + O.hear_talk(src, message, verb, speaking) log_say("[name]/[key] : [message]") + return 1 + +/mob/living/proc/say_signlang(var/message, var/verb="gestures", var/datum/language/language) + for (var/mob/O in viewers(src, null)) + O.hear_signlang(message, verb, language, src) + return 1 /obj/effect/speech_bubble var/mob/parent /mob/living/proc/GetVoice() return name - - diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 117a2d127d5..a7fb2ada618 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -112,6 +112,20 @@ var/list/ai_list = list() /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ /mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location, /mob/living/silicon/ai/proc/nano_crew_monitor, /mob/living/silicon/ai/proc/ai_cancel_call) + //Languages + add_language("Robot Talk", 1) + add_language("Sol Common", 1) + add_language("Tradeband", 1) + add_language("Sinta'unathi", 0) + add_language("Siik'tajr", 0) + add_language("Skrellian", 0) + add_language("Vox-pidgin", 0) + add_language("Rootspeak", 0) + add_language("Trinary", 1) + add_language("Chittin", 0) + add_language("Bubblish", 0) + add_language("Gutter", 0) + if(!safety)//Only used by AIize() to successfully spawn an AI. if (!B)//If there is no player/brain inside. empty_playable_ai_cores += new/obj/structure/AIcore/deactivated(loc)//New empty terminal. @@ -127,6 +141,7 @@ var/list/ai_list = list() /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \ /mob/living/silicon/ai/proc/toggle_camera_light,/mob/living/silicon/ai/verb/pick_icon,/mob/living/silicon/ai/proc/control_hud, /mob/living/silicon/ai/proc/change_arrival_message, /mob/living/silicon/ai/proc/ai_cancel_call) laws = new /datum/ai_laws/alienmov + add_language("xenocommon", 1) else B.brainmob.mind.transfer_to(src) diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index ec02433c46a..833d08e7cb4 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -5,7 +5,9 @@ /mob/aiEye name = "Inactive AI Eye" - icon = 'icons/obj/status_display.dmi' // For AI friend secret shh :o + icon = 'icons/mob/AI.dmi' + icon_state = "eye" + alpha = 127 var/list/visibleCameraChunks = list() var/mob/living/silicon/ai/ai = null density = 0 diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index b596fd53541..5a4398485ed 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -1,32 +1,8 @@ /mob/living/silicon/ai/say(var/message) if(parent && istype(parent) && parent.stat != 2) - parent.say(message) //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead. - return - - ..(message) - -/mob/living/silicon/ai/say_understands(var/other) - if (istype(other, /mob/living/carbon/human)) - return 1 - if (istype(other, /mob/living/silicon/robot)) - return 1 - if (istype(other, /mob/living/silicon/decoy)) - return 1 - if (istype(other, /mob/living/carbon/brain)) - return 1 - if (istype(other, /mob/living/silicon/pai)) - return 1 - return ..() - -/mob/living/silicon/ai/say_quote(var/text) - var/ending = copytext(text, length(text)) - - if (ending == "?") - return "queries, \"[text]\""; - else if (ending == "!") - return "declares, \"[text]\""; - - return "states, \"[text]\""; + return parent.say(message) + //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead. + return ..(message) /mob/living/silicon/ai/proc/IsVocal() diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 48a34265d43..d62c5f544d4 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -71,6 +71,7 @@ var/obj/item/radio/integrated/signal/sradio // AI's signaller + var/translator_on = 0 // keeps track of the translator module /mob/living/silicon/pai/New(var/obj/item/device/paicard) canmove = 0 @@ -81,6 +82,13 @@ if(!card.radio) card.radio = new /obj/item/device/radio(src.card) radio = card.radio + + //Default languages without universal translator software + add_language("Sol Common", 1) + add_language("Tradeband", 1) + add_language("Gutter", 1) + add_language("Trinary", 1) + //Verbs for pAI mobile form, chassis and Say flavor text verbs += /mob/living/silicon/pai/proc/choose_chassis verbs += /mob/living/silicon/pai/proc/choose_verbs @@ -334,7 +342,7 @@ //I'm not sure how much of this is necessary, but I would rather avoid issues. if(istype(card.loc,/mob)) var/mob/holder = card.loc - holder.unEquip(card) + holder.drop_from_inventory(card) else if(istype(card.loc,/obj/item/clothing/suit/space/space_ninja)) var/obj/item/clothing/suit/space/space_ninja/holder = card.loc holder.pai = null @@ -503,3 +511,7 @@ spawn(1) close_up() return 2 + +// No binary for pAIs. +/mob/living/silicon/pai/binarycheck() + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm index 4f7bd1a1c61..ff9b343a7b1 100644 --- a/code/modules/mob/living/silicon/pai/software.dm +++ b/code/modules/mob/living/silicon/pai/software.dm @@ -268,7 +268,7 @@ src.medHUD = !src.medHUD if("translator") if(href_list["toggle"]) - src.universal_speak = !src.universal_speak + src.translator_toggle() if("doorjack") if(href_list["jack"]) if(src.cable && src.cable.machine) @@ -687,4 +687,36 @@ else dat += addtext("
") dat += "
From", index["owner"],": ", index["message"], "
" - return dat \ No newline at end of file + return dat + +/mob/living/silicon/pai/proc/translator_toggle() + + // Sol Common, Tradeband, Gutter and Trinary are added with New() and are therefore the current default, always active languages + + if(translator_on) + translator_on = 0 + + remove_language("Sinta'unathi") + remove_language("Siik'tajr") + remove_language("Skrellian") + remove_language("Vox-pidgin") + remove_language("Rootspeak") + remove_language("Trinary") + remove_language("Chittin") + remove_language("Bubblish") + + src << "\blue Translator Module toggled OFF." + + else + translator_on = 1 + + add_language("Sinta'unathi") + add_language("Siik'tajr") + add_language("Skrellian") + add_language("Vox-pidgin") + add_language("Rootspeak") + add_language("Trinary") + add_language("Chittin") + add_language("Bubblish") + + src << "\blue Translator Module toggled ON." \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 5817715ff99..e2d6c31e8f6 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -121,6 +121,11 @@ /mob/living/silicon/robot/proc/is_component_functioning(module_name) var/datum/robot_component/C = components[module_name] return C && C.installed == 1 && C.toggled && C.is_powered() + +// Returns component by it's string name +/mob/living/silicon/robot/proc/get_component(var/component_name) + var/datum/robot_component/C = components[component_name] + return C /obj/item/broken_device name = "broken component" diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index e3a04f2cd0f..e83298a68eb 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -13,7 +13,8 @@ lawupdate = 0 density = 1 req_access = list(access_engine, access_robotics) - + local_transmit = 1 + // We need to keep track of a few module items so we don't need to do list operations // every time we need them. These get set in New() after the module is chosen. var/obj/item/stack/sheet/metal/cyborg/stack_metal = null @@ -25,11 +26,13 @@ //Used for self-mailing. var/mail_destination = 0 - //Used for pulling. /mob/living/silicon/robot/drone/New() ..() + + remove_language("Robot Talk") + add_language("Drone Talk", 1) if(camera && "Robots" in camera.network) camera.network.Add("Engineering") @@ -88,79 +91,6 @@ /mob/living/silicon/robot/drone/pick_module() return -//Drones can only use binary and say emotes. NOTHING else. -//TBD, fix up boilerplate. ~ Z -/mob/living/silicon/robot/drone/say(var/message) - if (!message) - return - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "You cannot send IC messages (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - - if (stat == 2) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - return say_dead(message) - - //Must be concious to speak - if (stat) - return - - if(copytext(message,1,2) == "*") - return emote(copytext(message,2)) - - if (length(message) >= 2) - var/prefix = copytext(message, 1, 3) - if (department_radio_keys[prefix] == "drone") - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - - if(istype(src, /mob/living/silicon/robot/drone)) - var/mob/living/silicon/robot/drone/R = src - if(!R.is_component_functioning("comms")) - src << "\red Your drone communications component isn't functional." - return - drone_talk(message) - else - var/list/listeners = hearers(5,src) - listeners |= src - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - for(var/mob/living/silicon/D in listeners) - if(D.client) - D << "[src] transmits, \"[message]\"" - - for (var/mob/M in player_list) - if (!M.client) - continue - if (istype(M, /mob/new_player)) - continue - else if(M.stat == 2 && (M.client.prefs.toggles & CHAT_GHOSTEARS) && src.client) - M << "[src] (Follow) transmits, \"[message]\"" - else if(M.stat == 2 && src.client && M in listeners) - M << "[src] (Follow) transmits, \"[message]\"" - -/mob/living/proc/drone_talk(var/message) - log_say("[key_name(src)] : [message]") - message = trim(message) - - if (!message) - return - - var/message_a = say_quote(message) - var/rendered = "Drone Talk, [name] [message_a]" - - for (var/mob/living/S in living_mob_list) - if(istype(S, /mob/living/silicon/robot/drone)) - S.show_message(rendered, 2) - - for (var/mob/S in dead_mob_list) - if(!istype(S,/mob/new_player) && !istype(S,/mob/living/carbon/brain)) - var/rendered2 = "Drone Talk, [name] (Follow) [message_a]" - S.show_message(rendered2, 2) - //Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). /mob/living/silicon/robot/drone/attackby(obj/item/weapon/W as obj, mob/user as mob) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index e28f9ac8b7d..ae42fbc4697 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -80,6 +80,8 @@ spark_system = new /datum/effect/effect/system/spark_spread() spark_system.set_up(5, 0, src) spark_system.attach(src) + + add_language("Robot Talk", 1) robot_modules_background = new() robot_modules_background.icon_state = "block" @@ -174,6 +176,13 @@ rbPDA.set_name_and_job(custom_name,braintype) if(hiddenborg) rbPDA.hidden = 1 + +/mob/living/silicon/robot/binarycheck() + if(is_component_functioning("comms")) + var/datum/robot_component/RC = get_component("comms") + use_power(RC.energy_consumption) + return 1 + return 0 //If there's an MMI in the robot, have it ejected when the mob goes away. --NEO //Improved /N @@ -197,7 +206,6 @@ modtype = input("Please, select a module!", "Robot", null, null) in modules designation = modtype var/module_sprites[0] //Used to store the associations between sprite names and sprite index. - var/channels = list() if(module) return @@ -205,14 +213,14 @@ switch(modtype) if("Standard") module = new /obj/item/weapon/robot_module/standard(src) - channels = list("Service" = 1) + module.channels = list("Service" = 1) module_sprites["Basic"] = "robot_old" module_sprites["Android"] = "droid" module_sprites["Default"] = "robot" if("Service") module = new /obj/item/weapon/robot_module/butler(src) - channels = list("Service" = 1) + module.channels = list("Service" = 1) module_sprites["Waitress"] = "Service" module_sprites["Kent"] = "toiletbot" module_sprites["Bro"] = "Brobot" @@ -221,7 +229,7 @@ /* if("Clerical") module = new /obj/item/weapon/robot_module/clerical(src) - channels = list("Service" = 1) + module.channels = list("Service" = 1) module_sprites["Waitress"] = "Service" module_sprites["Kent"] = "toiletbot" module_sprites["Bro"] = "Brobot" @@ -230,7 +238,7 @@ */ if("Miner") module = new /obj/item/weapon/robot_module/miner(src) - channels = list("Supply" = 1) + module.channels = list("Supply" = 1) if(camera && "Robots" in camera.network) camera.network.Add("MINE") module_sprites["Basic"] = "Miner_old" @@ -239,7 +247,7 @@ if("Medical") module = new /obj/item/weapon/robot_module/medical(src) - channels = list("Medical" = 1) + module.channels = list("Medical" = 1) if(camera && "Robots" in camera.network) camera.network.Add("Medical") module_sprites["Basic"] = "Medbot" @@ -249,7 +257,7 @@ if("Security") module = new /obj/item/weapon/robot_module/security(src) - channels = list("Security" = 1) + module.channels = list("Security" = 1) module_sprites["Basic"] = "secborg" module_sprites["Red Knight"] = "Security" module_sprites["Black Knight"] = "securityrobot" @@ -257,7 +265,7 @@ if("Engineering") module = new /obj/item/weapon/robot_module/engineering(src) - channels = list("Engineering" = 1) + module.channels = list("Engineering" = 1) if(camera && "Robots" in camera.network) camera.network.Add("Engineering") module_sprites["Basic"] = "Engineering" @@ -266,14 +274,15 @@ if("Janitor") module = new /obj/item/weapon/robot_module/janitor(src) + module.channels = list("Service" = 1) module_sprites["Basic"] = "JanBot2" module_sprites["Mopbot"] = "janitorrobot" module_sprites["Mop Gear Rex"] = "mopgearrex" if("Combat") module = new /obj/item/weapon/robot_module/combat(src) + module.channels = list("Security" = 1) module_sprites["Combat Android"] = "droidcombat" - channels = list("Security" = 1) if("Hunter") updatename(module) @@ -283,7 +292,9 @@ icon_state = "xenoborg-state-a" modtype = "Xeno-Hu" feedback_inc("xeborg_hunter",1) - + + //languages + module.add_languages(src) //Custom_sprite check and entry if (custom_sprite == 1) @@ -297,7 +308,7 @@ status_flags &= ~CANPUSH choose_icon(6,module_sprites) - radio.config(channels) + radio.config(module.channels) notify_ai(2) /mob/living/silicon/robot/proc/updatename(var/prefix as text) @@ -1467,6 +1478,16 @@ laws = new /datum/ai_laws/syndicate_override() Namepick() + +/mob/living/silicon/robot/syndicate/canUseTopic(atom/movable/M) + if(stat || lockcharge || stunned || weakened) + return + if(z in config.admin_levels) + return 1 + /*if(istype(M, /obj/machinery)) + var/obj/machinery/Machine = M + return Machine.emagged*/ + return 1 /mob/living/silicon/robot/proc/notify_ai(var/notifytype, var/oldname, var/newname) if(!connected_ai) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index a2c1fcb7347..a6b9d46f19a 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -10,6 +10,7 @@ var/obj/item/emag = null var/obj/item/borg/upgrade/jetpack = null var/list/stacktypes + var/channels = list() emp_act(severity) @@ -55,6 +56,20 @@ for(var/obj/O in temp_list) if(O) modules += O + +/obj/item/weapon/robot_module/proc/add_languages(var/mob/living/silicon/robot/R) + //full set of languages + R.add_language("Sol Common", 1) + R.add_language("Tradeband", 1) + R.add_language("Sinta'unathi", 0) + R.add_language("Siik'tajr", 0) + R.add_language("Skrellian", 0) + R.add_language("Vox-pidgin", 0) + R.add_language("Rootspeak", 0) + R.add_language("Trinary", 1) + R.add_language("Chittin", 0) + R.add_language("Bubblish", 0) + R.add_language("Gutter", 0) /obj/item/weapon/robot_module/standard name = "standard robot module" @@ -248,6 +263,20 @@ if(src.emag) var/obj/item/weapon/reagent_containers/food/drinks/cans/beer/B = src.emag B.reagents.add_reagent("beer2", 2) + +/obj/item/weapon/robot_module/butler/add_languages(var/mob/living/silicon/robot/R) + //full set of languages + R.add_language("Sol Common", 1) + R.add_language("Tradeband", 1) + R.add_language("Sinta'unathi", 1) + R.add_language("Siik'tajr", 1) + R.add_language("Skrellian", 1) + R.add_language("Vox-pidgin", 1) + R.add_language("Rootspeak", 1) + R.add_language("Trinary", 1) + R.add_language("Chittin", 1) + R.add_language("Bubblish", 1) + R.add_language("Gutter", 1) /* /obj/item/weapon/robot_module/clerical //Whyyyyy? @@ -341,6 +370,10 @@ src.emag = new /obj/item/weapon/reagent_containers/spray/alien/acid(src) src.emag.reagents.add_reagent("pacid", 125) src.emag.reagents.add_reagent("sacid", 125) + +/obj/item/weapon/robot_module/butler/add_languages(var/mob/living/silicon/robot/R) + ..() + R.add_language("xenocommon", 1) /obj/item/weapon/robot_module/drone name = "drone module" diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 35a31a8dbe0..ba5b0ad4f82 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -2,79 +2,154 @@ var/ending = copytext(text, length(text)) if (ending == "?") - return "[speak_query], \"[text]\""; + return speak_query else if (ending == "!") - return "[speak_exclamation], \"[text]\""; + return speak_exclamation - return "[speak_statement], \"[text]\""; + return speak_statement + +#define IS_AI 1 +#define IS_ROBOT 2 +#define IS_PAI 3 + +/mob/living/silicon/say_understands(var/other,var/datum/language/speaking = null) + //These only pertain to common. Languages are handled by mob/say_understands() + if (!speaking) + if (istype(other, /mob/living/carbon)) + return 1 + if (istype(other, /mob/living/silicon)) + return 1 + if (istype(other, /mob/living/carbon/brain)) + return 1 + return ..() /mob/living/silicon/say(var/message) if (!message) - return + return 0 if (src.client) if(client.prefs.muted & MUTE_IC) src << "You cannot send IC messages (muted)." - return + return 0 if (src.client.handle_spam_prevention(message,MUTE_IC)) - return + return 0 + + message = trim_strip_html_properly(message) if (stat == 2) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) return say_dead(message) + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + var/bot_type = 0 //Let's not do a fuck ton of type checks, thanks. + if(istype(src, /mob/living/silicon/ai)) + bot_type = IS_AI + else if(istype(src, /mob/living/silicon/robot)) + bot_type = IS_ROBOT + else if(istype(src, /mob/living/silicon/pai)) + bot_type = IS_PAI + + var/mob/living/silicon/ai/AI = src //and let's not declare vars over and over and over for these guys. + var/mob/living/silicon/robot/R = src + var/mob/living/silicon/pai/P = src + //Must be concious to speak if (stat) - return + return 0 - if (length(message) >= 2) - var/prefix = copytext(message, 1, 3) - if (department_radio_keys[prefix] == "binary") - if(istype(src, /mob/living/silicon/pai)) - return ..(message) - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + var/verb = say_quote(message) - // TODO: move the component system up to silicon so we don't have to use this ugly hack.. - if(istype(src, /mob/living/silicon/robot)) - var/mob/living/silicon/robot/R = src - if(!R.is_component_functioning("comms")) - src << "\red Your binary communications component isn't functional." - return - robot_talk(message) - - else if (department_radio_keys[prefix] == "alientalk") - if(!alien_talk_understand) return - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - - alien_talk(message) - else if (department_radio_keys[prefix] == "department") - if(isAI(src)&&client) //For patching directly into AI holopads. - var/mob/living/silicon/ai/U = src - message = copytext(message, 3) - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - U.holopad_talk(message) - else //Will not allow anyone by an active AI to use this function. - src << "This function is not available to you." - return + //parse radio key and consume it + var/message_mode = parse_message_mode(message, "general") + if (message_mode) + if (message_mode == "general") + message = trim(copytext(message,2)) else - var/mob/living/silicon/ai/AI = src - if (isAI(src) && AI.aiRadio.disabledAi) - src << "\red System Error - Transceiver Disabled" - return - else - return ..(message) - else - var/mob/living/silicon/ai/AI = src - if (isAI(src) && AI.aiRadio.disabledAi) - src << "\red System Error - Transceiver Disabled" - return + message = trim(copytext(message,3)) + + //parse language key and consume it + var/datum/language/speaking = parse_language(message) + if (speaking) + verb = speaking.speech_verb + message = trim(copytext(message,2+length(speaking.key))) + + if(speaking.flags & HIVEMIND) + speaking.broadcast(src,trim(message)) + return 1 + + // Currently used by drones. + if(local_transmit) + var/list/listeners = hearers(5,src) + listeners |= src + + for(var/mob/living/silicon/D in listeners) + if(D.client && istype(D,src.type)) + D << "[src] transmits, \"[message]\"" + + for (var/mob/M in player_list) + if (istype(M, /mob/new_player)) + continue + else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS) + if(M.client) M << "[src] transmits, \"[message]\"" + return 1 + + if(message_mode && bot_type == IS_ROBOT && !R.is_component_functioning("radio")) + src << "\red Your radio isn't functional at this time." + return 0 + + switch(message_mode) + if("department") + switch(bot_type) + if(IS_AI) + return AI.holopad_talk(message, verb, speaking) + if(IS_ROBOT) + log_say("[key_name(src)] : [message]") + return R.radio.talk_into(src,message,message_mode,verb,speaking) + if(IS_PAI) + log_say("[key_name(src)] : [message]") + return P.radio.talk_into(src,message,message_mode,verb,speaking) + return 0 + + if("general") + switch(bot_type) + if(IS_AI) + if (AI.aiRadio.disabledAi || AI.aiRestorePowerRoutine || AI.stat) + src << "\red System Error - Transceiver Disabled" + return 0 + else + log_say("[key_name(src)] : [message]") + return AI.aiRadio.talk_into(src,message,null,verb,speaking) + if(IS_ROBOT) + log_say("[key_name(src)] : [message]") + return R.radio.talk_into(src,message,null,verb,speaking) + if(IS_PAI) + log_say("[key_name(src)] : [message]") + return P.radio.talk_into(src,message,null,verb,speaking) + return 0 + else - return ..(message) + if(message_mode) + switch(bot_type) + if(IS_AI) + if (AI.aiRadio.disabledAi || AI.aiRestorePowerRoutine || AI.stat) + src << "\red System Error - Transceiver Disabled" + return 0 + else + log_say("[key_name(src)] : [message]") + return AI.aiRadio.talk_into(src,message,message_mode,verb,speaking) + if(IS_ROBOT) + log_say("[key_name(src)] : [message]") + return R.radio.talk_into(src,message,message_mode,verb,speaking) + if(IS_PAI) + log_say("[key_name(src)] : [message]") + return P.radio.talk_into(src,message,message_mode,verb,speaking) + return 0 + + return ..(message,speaking,verb) //For holopads only. Usable by AI. -/mob/living/silicon/ai/proc/holopad_talk(var/message) +/mob/living/silicon/ai/proc/holopad_talk(var/message, verb, datum/language/speaking) log_say("[key_name(src)] : [message]") @@ -84,18 +159,23 @@ return var/obj/machinery/hologram/holopad/T = src.holo - if(istype(T) && T.hologram && T.master == src)//If there is a hologram and its master is the user. - var/message_a = say_quote(message) + if(T && T.hologram && T.master == src)//If there is a hologram and its master is the user. //Human-like, sorta, heard by those who understand humans. - var/rendered_a = "[name] [message_a]" - + var/rendered_a //Speach distorted, heard by those who do not understand AIs. - message = stars(message) - var/message_b = say_quote(message) - var/rendered_b = "[voice_name] [message_b]" + var/message_stars = stars(message) + var/rendered_b + + if(speaking) + rendered_a = "[name] [speaking.format_message(message, verb)]" + rendered_b = "[voice_name] [speaking.format_message(message_stars, verb)]" + src << "Holopad transmitted, [real_name] [speaking.format_message(message, verb)]"//The AI can "hear" its own message. + else + rendered_a = "[name] [verb], \"[message]\"" + rendered_b = "[voice_name] [verb], \"[message_stars]\"" + src << "Holopad transmitted, [real_name] [verb], \"[message]\""//The AI can "hear" its own message. - src << "Holopad transmitted, [real_name] [message_a]"//The AI can "hear" its own message. for(var/mob/M in hearers(T.loc))//The location is the object, default distance. if(M.say_understands(src))//If they understand AI speak. Humans and the like will be able to. M.show_message(rendered_a, 2) @@ -105,79 +185,37 @@ This is another way of saying that we won't bother dealing with them.*/ else src << "No holopad connected." - return + return + return 1 -/mob/living/proc/robot_talk(var/message) +/mob/living/silicon/ai/proc/holopad_emote(var/message) //This is called when the AI uses the 'me' verb while using a holopad. - log_say("[key_name(src)] : [message]") - - var/desig = "Unknown" //ezmode for taters - if(isrobot(src)) - var/mob/living/silicon/S = src - if(S.designation) - desig = trim_left(S.designation) - else - desig = "Default" - else if(isAI(src)) - desig = "AI" + log_emote("[key_name(src)] : [message]") message = trim(message) if (!message) return - var/message_a = say_quote(message) - var/rendered = "Robotic Talk, [name] ([desig]) [message_a]" + var/obj/machinery/hologram/holopad/T = src.holo + if(T && T.hologram && T.master == src) + var/rendered = "[name] [message]" + src << "Holopad action relayed, [real_name] [message]" - for (var/mob/living/S in living_mob_list) - if(S.robot_talk_understand && (S.robot_talk_understand == robot_talk_understand)) // This SHOULD catch everything caught by the one below, but I'm not going to change it. - if(istype(S , /mob/living/silicon/ai)) - var/renderedAI = "Robotic Talk, [name] ([desig]) [message_a]" - S.show_message(renderedAI, 2) - else if(istype(S , /mob/dead/observer) && S.stat == DEAD) - var/rendered2 = "Robotic Talk, [name] ([desig]) (Follow) [message_a]" - S.show_message(rendered2, 2) - else - S.show_message(rendered, 2) - - - else if (S.binarycheck()) - if(istype(S , /mob/living/silicon/ai)) - var/renderedAI = "Robotic Talk, [name] [message_a]" - S.show_message(renderedAI, 2) - else if(istype(S , /mob/dead/observer) && S.stat == DEAD) - var/rendered2 = "Robotic Talk, [name] (Follow) [message_a]" - S.show_message(rendered2, 2) - else - S.show_message(rendered, 2) - - var/list/listening = hearers(1, src) - listening -= src - listening += src - - var/list/heard = list() - for (var/mob/M in listening) - if(!istype(M, /mob/living/silicon) && !M.robot_talk_understand) - heard += M - - if (length(heard)) - var/message_b - - message_b = "beep beep beep" - message_b = say_quote(message_b) - message_b = "[message_b]" - - rendered = "[voice_name] [message_b]" - - for (var/mob/M in heard) + for(var/mob/M in viewers(T.loc)) M.show_message(rendered, 2) + else //This shouldn't occur, but better safe then sorry. + src << "No holopad connected." + return + return 1 - message = say_quote(message) +/mob/living/silicon/ai/emote(var/act, var/type, var/message) + var/obj/machinery/hologram/holopad/T = src.holo + if(T && T.hologram && T.master == src) //Is the AI using a holopad? + src.holopad_emote(message) + else //Emote normally, then. + ..() -// rendered = "Robotic Talk, [name] [message_a]" - rendered = null - - for (var/mob/M in dead_mob_list) - if(!istype(M,/mob/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping - rendered = "Robotic Talk, [name] (Follow) [message_a]" - M.show_message(rendered, 2) \ No newline at end of file +#undef IS_AI +#undef IS_ROBOT +#undef IS_PAI diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 6f88c99c71e..86da14df0e7 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -8,6 +8,7 @@ var/list/alarms_to_clear = list() immune_to_ssd = 1 var/list/hud_list[10] + var/list/speech_synthesizer_langs = list() //which languages can be vocalized by the speech synthesizer var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0) var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0) var/designation = "" @@ -20,6 +21,7 @@ var/sensor_mode = 0 //Determines the current HUD. #define SEC_HUD 1 //Security HUD mode #define MED_HUD 2 //Medical HUD mode + var/local_transmit //If set, can only speak to others of the same type within a short range. /mob/living/silicon/proc/cancelAlarm() return @@ -205,6 +207,37 @@ show_emergency_shuttle_eta() show_system_integrity() show_malf_ai() + +//Silicon mob language procs + +/mob/living/silicon/can_speak(datum/language/speaking) + return universal_speak || (speaking in src.speech_synthesizer_langs) //need speech synthesizer support to vocalize a language + +/mob/living/silicon/add_language(var/language, var/can_speak=1) + if (..(language) && can_speak) + speech_synthesizer_langs.Add(all_languages[language]) + return 1 + +/mob/living/silicon/remove_language(var/rem_language) + ..(rem_language) + + for (var/datum/language/L in speech_synthesizer_langs) + if (L.name == rem_language) + speech_synthesizer_langs -= L + +/mob/living/silicon/check_languages() + set name = "Check Known Languages" + set category = "IC" + set src = usr + + var/dat = "Known Languages

" + + for(var/datum/language/L in languages) + if(!(L.flags & NONGLOBAL)) + dat += "[L.name] (:[L.key])
Speech Synthesizer: [(L in speech_synthesizer_langs)? "YES":"NOT SUPPORTED"]
[L.desc]

" + + src << browse(dat, "window=checklanguage") + return // this function displays the stations manifest in a separate window /mob/living/silicon/proc/show_station_manifest() @@ -257,6 +290,9 @@ set category = "IC" flavor_text = copytext(sanitize(input(usr, "Please enter your new flavour text.", "Flavour text", null) as text), 1) + +/mob/living/silicon/binarycheck() + return 1 /mob/living/silicon/proc/toggle_sensor_mode() var/sensor_type = input("Please select sensor type.", "Sensor Integration", null) in list("Security", "Medical","Disable") diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm index 8dae4be093b..50334dbdf27 100644 --- a/code/modules/mob/living/simple_animal/borer.dm +++ b/code/modules/mob/living/simple_animal/borer.dm @@ -100,51 +100,12 @@ /mob/living/simple_animal/borer/New(var/by_gamemode=0) ..() + add_language("Cortical Link") truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]" if(!by_gamemode) request_player() - -/mob/living/simple_animal/borer/say(var/message) - - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) - message = capitalize(message) - - if(!message) - return - - if (stat == 2) - return say_dead(message) - - if (stat) - return - - if (src.client) - if(client.prefs.muted & MUTE_IC) - src << "\red You cannot speak in IC (muted)." - return - if (src.client.handle_spam_prevention(message,MUTE_IC)) - return - - if (copytext(message, 1, 2) == "*") - return emote(copytext(message, 2)) - - if (copytext(message, 1, 2) == ";") //Brain borer hivemind. - return borer_speak(message) - - if(!host) - src << "You have no host to speak to." - return //No host, no audible speech. - - src << "You drop words into [host]'s mind: \"[message]\"" - host << "Your own thoughts speak: \"[message]\"" - - for(var/mob/M in mob_list) - if(M.mind && (istype(M, /mob/dead/observer))) - M << "Thought-speech, [truename] -> [host]: [copytext(message, 2)]" - - /mob/living/simple_animal/borer/Stat() ..() statpanel("Status") diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 48fd6943658..a62f0640a54 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -48,6 +48,7 @@ response_disarm = "gently moves aside the" response_harm = "swats the" stop_automated_movement = 1 + universal_speak = 1 var/parrot_state = PARROT_WANDER //Hunt for a perch when created var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. @@ -61,7 +62,7 @@ var/list/available_channels = list() //Headset for Poly to yell at engineers :) - var/obj/item/device/radio/headset/l_ear = null + var/obj/item/device/radio/headset/ears = null //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, //mobs it wants to attack or mobs that have attacked it @@ -84,13 +85,13 @@ /mob/living/simple_animal/parrot/New() ..() - if(!l_ear) + if(!ears) var/headset = pick(/obj/item/device/radio/headset/headset_sec, \ /obj/item/device/radio/headset/headset_eng, \ /obj/item/device/radio/headset/headset_med, \ /obj/item/device/radio/headset/headset_sci, \ /obj/item/device/radio/headset/headset_cargo) - l_ear = new headset(src) + ears = new headset(src) parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var @@ -100,7 +101,7 @@ /mob/living/simple_animal/parrot/proc/perch_player) -/mob/living/simple_animal/parrot/Die() +/mob/living/simple_animal/parrot/death() if(held_item) held_item.loc = src.loc held_item = null @@ -119,10 +120,10 @@ if(user.stat) return var/dat = "
Inventory of [name]

" - if(l_ear) - dat += "
Headset: [l_ear] (Remove)" + if(ears) + dat += "
Headset: [ears] (Remove)" else - dat += "
Headset: Nothing" + dat += "
Headset: Nothing" user << browse(dat, text("window=mob[];size=325x500", name)) onclose(user, "mob[real_name]") @@ -134,21 +135,21 @@ if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) return - //Is the usr's mob type able to do this? (lolaliens) - if(ishuman(usr) || ismonkey(usr) || isrobot(usr) || isalienadult(usr)) + //Is the usr's mob type able to do this? + if(ishuman(usr) || ismonkey(usr) || isrobot(usr)) //Removing from inventory if(href_list["remove_inv"]) var/remove_from = href_list["remove_inv"] switch(remove_from) - if("l_ear") - if(l_ear) + if("ears") + if(ears) if(available_channels.len) src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") else src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - l_ear.loc = src.loc - l_ear = null + ears.loc = src.loc + ears = null for(var/possible_phrase in speak) if(copytext(possible_phrase,1,3) in department_radio_keys) possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) @@ -163,8 +164,8 @@ usr << "\red You have nothing in your hand to put on its [add_to]." return switch(add_to) - if("l_ear") - if(l_ear) + if("ears") + if(ears) usr << "\red It's already wearing something." return else @@ -180,7 +181,7 @@ usr.drop_item() headset_to_add.loc = src - src.l_ear = headset_to_add + src.ears = headset_to_add usr << "You fit the headset onto [src]." clearlist(available_channels) @@ -214,7 +215,7 @@ /mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob) ..() if(client) return - if(!stat && M.a_intent == "harm") + if(!stat && M.a_intent == "hurt") icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks @@ -231,25 +232,6 @@ drop_held_item(0) return -/mob/living/simple_animal/parrot/attack_paw(mob/living/carbon/monkey/M as mob) - attack_hand(M) - -/mob/living/simple_animal/parrot/attack_alien(mob/living/carbon/monkey/M as mob) - attack_hand(M) - -//Simple animals -/mob/living/simple_animal/parrot/attack_animal(mob/living/simple_animal/M as mob) - if(client) return - - - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - if(M.melee_damage_upper > 0) - parrot_interest = M - parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless - icon_state = "parrot_fly" - //Mobs with objects /mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob) ..() @@ -335,7 +317,7 @@ if(speak.len) var/list/newspeak = list() - if(available_channels.len && src.l_ear) + if(available_channels.len && src.ears) for(var/possible_phrase in speak) //50/50 chance to not use the radio at all @@ -496,11 +478,11 @@ var/datum/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone))) H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1) - emote(pick("pecks [H]'s [affecting]", "cuts [H]'s [affecting] with its talons")) + emote(pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons.")) else L.adjustBruteLoss(damage) - emote(pick("pecks at [L]", "claws [L]")) + emote(pick("pecks at [L].", "claws [L].")) return //Otherwise, fly towards the mob! @@ -700,6 +682,71 @@ speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE") /mob/living/simple_animal/parrot/Poly/New() - l_ear = new /obj/item/device/radio/headset/headset_eng(src) + ears = new /obj/item/device/radio/headset/headset_eng(src) available_channels = list(":e") ..() + +/mob/living/simple_animal/parrot/say(var/message) + + if(stat) + return + + var/verb = "says" + if(speak_emote.len) + verb = pick(speak_emote) + + var/message_mode = null + if(copytext(message,1,2) == ";") + message_mode = "headset" + message = copytext(message,2) + + if(copytext(message,1,2) == ":") + var/channel_prefix = copytext(message, 1 ,3) + message_mode = department_radio_keys[channel_prefix] + var/positioncut = 3 + message = trim(copytext(message,positioncut)) + + message = capitalize(trim_left(message)) + if(message_mode) + if(message_mode in radiochannels) + if(ears && istype(ears,/obj/item/device/radio)) + ears.talk_into(src, message, message_mode, verb, null) + + ..(message) + + +/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) + if(prob(50)) + parrot_hear(message) + ..(message,verb,language,alt_name,italics,speaker) + + + +/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0) + if(prob(50)) + parrot_hear("[pick(available_channels)] [message]") + ..(message,verb,language,part_a,part_b,speaker,hard_to_hear) + + +/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="") + if(!message || stat) + return + speech_buffer.Add(message) + +/mob/living/simple_animal/parrot/attack_paw(var/mob/user, var/damage, var/attack_message) + + var/success = ..() + + if(client) + return success + + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + if(!success) + return 0 + + parrot_interest = user + parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless + icon_state = "parrot_fly" + return success diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 800d9967ca7..6d0694c3073 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -269,6 +269,7 @@ for(var/mob/O in viewers(src, null)) if ((O.client && !( O.blinded ))) O.show_message("\blue [M] [response_help] [src].") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if("grab") if (M == src || anchored) @@ -288,12 +289,14 @@ for(var/mob/O in viewers(src, null)) if ((O.client && !( O.blinded ))) O.show_message(text("\red [] has grabbed [] passively!", M, src), 1) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if("harm", "disarm") adjustBruteLoss(harm_intent_damage) for(var/mob/O in viewers(src, null)) if ((O.client && !( O.blinded ))) O.show_message("\red [M] [response_harm] [src]!") + playsound(loc, "punch", 25, 1, -1) return @@ -537,3 +540,22 @@ if (S.occupant || S.occupant2) return 0 return 1 + +/mob/living/simple_animal/say(var/message) + if(stat) + return + + if(copytext(message,1,2) == "*") + return emote(copytext(message,2)) + + if(stat) + return + + var/verb = "says" + + if(speak_emote.len) + verb = pick(speak_emote) + + message = capitalize(trim_left(message)) + + ..(message, null, verb) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 7b197aafcb2..a3d5932e10b 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -93,6 +93,7 @@ return 0 /mob/proc/Life() + handle_typing_indicator() // if(organStructure) // organStructure.ProcessOrgans() return diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index e23014f9f52..d3abbfc1776 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -446,3 +446,49 @@ var/list/intents = list("help","disarm","grab","harm") /proc/get_both_hands(mob/living/carbon/M) var/list/hands = list(M.l_hand, M.r_hand) return hands + + +//Direct dead say used both by emote and say +//It is somewhat messy. I don't know what to do. +//I know you can't see the change, but I rewrote the name code. It is significantly less messy now +/proc/say_dead_direct(var/message, var/mob/subject = null) + var/name + var/keyname + if(subject && subject.client) + var/client/C = subject.client + keyname = (C.holder && C.holder.fakekey) ? C.holder.fakekey : C.key + if(C.mob) //Most of the time this is the dead/observer mob; we can totally use him if there is no better name + var/mindname + var/realname = C.mob.real_name + if(C.mob.mind) + mindname = C.mob.mind.name + if(C.mob.mind.original && C.mob.mind.original.real_name) + realname = C.mob.mind.original.real_name + if(mindname && mindname != realname) + name = "[realname] died as [mindname]" + else + name = realname + + for(var/mob/M in player_list) + if(M.client && ((!istype(M, /mob/new_player) && M.stat == DEAD) || (M.client.holder && M.client.holder.rights == R_MOD)) && (M.client.prefs.toggles & CHAT_DEAD)) + var/follow + var/lname + if(subject) + if(subject != M) + follow = "(follow) " + if(M.stat != DEAD && M.client.holder) + follow = "(JMP) " + var/mob/dead/observer/DM + if(istype(subject, /mob/dead/observer)) + DM = subject + if(M.client.holder) // What admins see + lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])" + else + if(DM && DM.anonsay) // If the person is actually observer they have the option to be anonymous + lname = "Ghost of [name]" + else if(DM) // Non-anons + lname = "[keyname] ([name])" + else // Everyone else (dead people who didn't ghost yet, etc.) + lname = name + lname = "[lname] " + M << "[lname][follow][message]" diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 6ecdfdc4e67..4810c0b10f7 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -444,46 +444,22 @@ proc/create_character() spawning = 1 close_spawn_windows() + var/mob/living/carbon/human/new_character + var/datum/species/chosen_species if(client.prefs.species) chosen_species = all_species[client.prefs.species] if(chosen_species) // Have to recheck admin due to no usr at roundstart. Latejoins are fine though. if(is_species_whitelisted(chosen_species) || has_admin_rights()) - switch(chosen_species.name) - if("Slime People") - new_character = new /mob/living/carbon/human/slime(loc) - if("Tajaran") - new_character = new /mob/living/carbon/human/tajaran(loc) - if("Unathi") - new_character = new /mob/living/carbon/human/unathi(loc) - if("Skrell") - new_character = new /mob/living/carbon/human/skrell(loc) - if("Diona") - new_character = new /mob/living/carbon/human/diona(loc) - if("Vox") - new_character = new /mob/living/carbon/human/vox(loc) - if("Vox Armalis") - new_character = new /mob/living/carbon/human/voxarmalis(loc) - if("Kidan") - new_character = new /mob/living/carbon/human/kidan(loc) - if("Grey") - new_character = new /mob/living/carbon/human/grey(loc) - if("Machine") - new_character = new /mob/living/carbon/human/machine(loc) - if("Plasmaman") - new_character = new /mob/living/carbon/human/plasma(loc) - if("Human") - new_character = new /mob/living/carbon/human/human(loc) -// new_character.set_species(client.prefs.species) - if(chosen_species.language) - new_character.add_language(chosen_species.language) - else - new_character = new /mob/living/carbon/human(loc) + new_character = new(loc, client.prefs.species) + + if(!new_character) + new_character = new(loc) + new_character.lastarea = get_area(loc) - var/datum/language/chosen_language if(client.prefs.language) chosen_language = all_languages[client.prefs.language] @@ -529,6 +505,8 @@ if(client.prefs.disabilities & DISABILITY_FLAG_DEAF) new_character.dna.SetSEState(DEAFBLOCK,1,1) new_character.sdisabilities |= DEAF + + chosen_species.handle_dna(new_character) domutcheck(new_character) new_character.dna.UpdateSE() diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 41612819446..38328b16bb7 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -9,114 +9,97 @@ /mob/verb/say_verb(message as text) set name = "Say" set category = "IC" + + //Let's try to make users fix their errors - we try to detect single, out-of-place letters and 'unintended' words + /* + var/first_letter = copytext(message,1,2) + if((copytext(message,2,3) == " " && first_letter != "I" && first_letter != "A" && first_letter != ";") || cmptext(copytext(message,1,5), "say ") || cmptext(copytext(message,1,4), "me ") || cmptext(copytext(message,1,6), "looc ") || cmptext(copytext(message,1,5), "ooc ") || cmptext(copytext(message,2,6), "say ")) + var/response = alert(usr, "Do you really want to say this using the *say* verb?\n\n[message]\n", "Confirm your message", "Yes", "Edit message", "No") + if(response == "Edit message") + message = input(usr, "Please edit your message carefully:", "Edit message", message) + if(!message) + return + else if(response == "No") + return + */ + + set_typing_indicator(0) usr.say(message) /mob/verb/me_verb(message as text) set name = "Me" set category = "IC" - message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN)) + message = strip_html_properly(message) + set_typing_indicator(0) if(use_me) usr.emote("me",usr.emote_type,message) else usr.emote(message) /mob/proc/say_dead(var/message) - var/name = src.real_name - var/alt_name = "" - - if(!src.client.holder) if(!dsay_allowed) - src << "\red Deadchat is globally muted" + src << "Deadchat is globally muted." return if(client && !(client.prefs.toggles & CHAT_DEAD)) - usr << "\red You have deadchat muted." + usr << "You have deadchat muted." return - if(mind && mind.name) - name = "[mind.name]" - else - name = real_name - if(name != real_name) - alt_name = " (died as [real_name])" - - message = src.say_quote(message) - //var/rendered = "DEAD: [name][alt_name] [message]" - var/rendered2 = null//edited - for(var/mob/M in player_list) - rendered2 = "DEAD: [name][alt_name] (Follow) [message]"//edited - if(istype(M, /mob/new_player)) - continue - if(M.client && M.client.holder && (M.client.holder.rights & R_ADMIN|R_MOD) && (M.client.prefs.toggles & CHAT_DEAD)) // Show the message to admins/mods with deadchat toggled on - M << rendered2 //Admins can hear deadchat, if they choose to, no matter if they're blind/deaf or not. - - else if(M.client && M.stat == DEAD && (M.client.prefs.toggles & CHAT_DEAD)) // Show the message to regular ghosts with deadchat toggled on. - M.show_message(rendered2, 2) //Takes into account blindness and such. - return + say_dead_direct("[pick("complains","moans","whines","laments","blubbers")], \"[message]\"", src) /mob/proc/say_understands(var/mob/other,var/datum/language/speaking = null) - if(!other) - return 1 - //Universal speak makes everything understandable, for obvious reasons. - if(other.universal_speak || src.universal_speak || src.universal_understand) - return 1 - if (src.stat == 2) + if (src.stat == 2) //Dead return 1 - if(!speaking) //Handle languages later - if(other.universal_speak || src.universal_speak) + //Universal speak makes everything understandable, for obvious reasons. + else if(src.universal_speak || src.universal_understand) + return 1 + + //Languages are handled after. + if (!speaking) + if(!other) + return 1 + if(other.universal_speak) return 1 if(isAI(src) && ispAI(other)) return 1 if (istype(other, src.type) || istype(src, other.type)) return 1 - if (istype(other, /mob/living/carbon/human) && (istype(src, /mob/living/carbon/human) || istype(src, /mob/living/silicon/pai))) - return 1 - if(istype(other, /mob/living/carbon/alien) && istype(src, /mob/living/carbon/alien)) - return 1 return 0 - for(var/datum/language/L in src.languages) //Handling languages + if(speaking.flags & INNATE) + return 1 + + //Language check. + for(var/datum/language/L in src.languages) if(speaking.name == L.name) return 1 return 0 -/mob/proc/say_quote(var/text,var/datum/language/speaking) +/* + ***Deprecated*** + let this be handled at the hear_say or hear_radio proc + This is left in for robot speaking when humans gain binary channel access until I get around to rewriting + robot_talk() proc. + There is no language handling build into it however there is at the /mob level so we accept the call + for it but just ignore it. +*/ - if(!text) - return "says, \"...\""; //not the best solution, but it will stop a large number of runtimes. The cause is somewhere in the Tcomms code - //tcomms code is still runtiming somewhere here - var/ending = copytext(text, length(text)) +/mob/proc/say_quote(var/message, var/datum/language/speaking = null) + var/verb = "says" + var/ending = copytext(message, length(message)) + if(ending=="!") + verb=pick("exclaims","shouts","yells") + else if(ending=="?") + verb="asks" - var/speechverb = "" + return verb - if (speaking) - speechverb = "[speaking.speech_verb], \"" - else if(speak_emote && speak_emote.len) - speechverb = "[pick(speak_emote)], \"" - else if (src.stuttering) - speechverb = "stammers, \"" - else if (src.slurring) - speechverb = "slurrs, \"" - else if (ending == "?") - speechverb = "asks, \"" - else if (ending == "!") - speechverb = "exclaims, \"" - else if(isliving(src)) - var/mob/living/L = src - if (L.getBrainLoss() >= 60) - speechverb = "gibbers, \"" - else - speechverb = "says, \"" - else - speechverb = "says, \"" - - return "[speechverb][text]\"" /mob/proc/emote(var/act, var/type, var/message) if(act == "me") @@ -133,21 +116,34 @@ /mob/proc/say_test(var/text) var/ending = copytext(text, length(text)) if (ending == "?") - if(isalien(src)) - return "A1" - if(isrobot(src)) - return "R1" - else - return "1" + return "1" else if (ending == "!") - if(isalien(src)) - return "A2" - if(isrobot(src)) - return "R2" - else - return "2" - else if(isalien(src)) - return "A0" - else if(isrobot(src)) - return "R0" + return "2" return "0" + +//parses the message mode code (e.g. :h, :w) from text, such as that supplied to say. +//returns the message mode string or null for no message mode. +//standard mode is the mode returned for the special ';' radio code. +/mob/proc/parse_message_mode(var/message, var/standard_mode="headset") + if(length(message) >= 1 && copytext(message,1,2) == ";") + return standard_mode + + if(length(message) >= 2) + var/channel_prefix = copytext(message, 1 ,3) + return department_radio_keys[channel_prefix] + + return null + +//parses the language code (e.g. :j) from text, such as that supplied to say. +//returns the language object only if the code corresponds to a language that src can speak, otherwise null. +/mob/proc/parse_language(var/message) + if(length(message) >= 1 && copytext(message,1,2) == "!") + return all_languages["Noise"] + + if(length(message) >= 2) + var/language_prefix = lowertext(copytext(message, 1 ,3)) + var/datum/language/L = language_keys[language_prefix] + if (can_speak(L)) + return L + + return null diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm new file mode 100644 index 00000000000..c104aa839a4 --- /dev/null +++ b/code/modules/mob/typing_indicator.dm @@ -0,0 +1,85 @@ +#define TYPING_INDICATOR_LIFETIME 30 * 10 //grace period after which typing indicator disappears regardless of text in chatbar + +mob/var/hud_typing = 0 //set when typing in an input window instead of chatline +mob/var/typing +mob/var/last_typed +mob/var/last_typed_time + +var/global/image/typing_indicator + +/mob/proc/set_typing_indicator(var/state) + + if(!typing_indicator) + typing_indicator = image('icons/mob/talk.dmi',null,"typing") + + if(client) + if(client.prefs.toggles & SHOW_TYPING) + overlays -= typing_indicator + else + if(state) + if(!typing) + overlays += typing_indicator + typing = 1 + else + if(typing) + overlays -= typing_indicator + typing = 0 + return state + +/mob/verb/say_wrapper() + set name = ".Say" + set hidden = 1 + + set_typing_indicator(1) + hud_typing = 1 + var/message = input("","say (text)") as text + hud_typing = 0 + set_typing_indicator(0) + if(message) + say_verb(message) + +/mob/verb/me_wrapper() + set name = ".Me" + set hidden = 1 + + set_typing_indicator(1) + hud_typing = 1 + var/message = input("","me (text)") as text + hud_typing = 0 + set_typing_indicator(0) + if(message) + me_verb(message) + +/mob/proc/handle_typing_indicator() + if(client) + if(!(client.prefs.toggles & SHOW_TYPING) && !hud_typing) + var/temp = winget(client, "input", "text") + + if (temp != last_typed) + last_typed = temp + last_typed_time = world.time + + if (world.time > last_typed_time + TYPING_INDICATOR_LIFETIME) + set_typing_indicator(0) + return + if(length(temp) > 5 && findtext(temp, "Say \"", 1, 7)) + set_typing_indicator(1) + else if(length(temp) > 3 && findtext(temp, "Me ", 1, 5)) + set_typing_indicator(1) + + else + set_typing_indicator(0) + +/client/verb/typing_indicator() + set name = "Show/Hide Typing Indicator" + set category = "Preferences" + set desc = "Toggles showing an indicator when you are typing emote or say message." + prefs.toggles ^= SHOW_TYPING + prefs.save_preferences(src) + src << "You will [(prefs.toggles & SHOW_TYPING) ? "no longer" : "now"] display a typing indicator." + + // Clear out any existing typing indicator. + if(prefs.toggles & SHOW_TYPING) + if(istype(mob)) mob.set_typing_indicator(0) + + feedback_add_details("admin_verb","TID") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! \ No newline at end of file diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 98726004ea4..7beff751760 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -21,8 +21,6 @@ var/list/alldepartments = list() var/department = "Unknown" // our department var/destination = "Central Command" // the department we're sending to - - var/data[0] /obj/machinery/photocopier/faxmachine/New() ..() @@ -51,6 +49,7 @@ var/list/alldepartments = list() user << "You swipe the card through [src], but nothing happens." /obj/machinery/photocopier/faxmachine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] if(scan) data["scan_name"] = scan.name else @@ -142,8 +141,7 @@ var/list/alldepartments = list() else if(istype(copyitem, /obj/item/weapon/photo)) copyitem.name = "[(n_name ? text("[n_name]") : "photo")]" else if(istype(copyitem, /obj/item/weapon/paper_bundle)) - copyitem.name = "[(n_name ? text("[n_name]") : "paper")]" - data["name"] = copyitem.name + copyitem.name = "[(n_name ? text("[n_name]") : "paper")]" nanomanager.update_uis(src) diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 4567d00bfde..ab5653e0d1a 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -62,7 +62,7 @@ build_path = /obj/item/weapon/circuitboard/bodyscanner category = list("Medical Machinery") -/datum/design/sleep_console +/datum/design/bodyscanner_console name = "Machine Board (Body Scanner Console)" desc = "Allows for the construction of circuit boards used to build a Body Scanner Console." id = "bodyscanner_console" diff --git a/code/modules/surgery/headreattach.dm b/code/modules/surgery/headreattach.dm index 3c49a9e8c0a..c493607c52c 100644 --- a/code/modules/surgery/headreattach.dm +++ b/code/modules/surgery/headreattach.dm @@ -196,7 +196,7 @@ user.visible_message("\blue [user] has attached [target]'s head to the body.", \ "\blue You have attached [target]'s head to the body.") affected.status = 0 - if(istype(target,/mob/living/carbon/human/machine)) + if(target.species && (target.species.flags & IS_SYNTHETIC)) affected.status = 128 affected.amputated = 0 affected.destspawn = 0 diff --git a/code/setup.dm b/code/setup.dm index ca1c664815a..c2981325856 100644 --- a/code/setup.dm +++ b/code/setup.dm @@ -711,11 +711,12 @@ var/list/TAGGERLOCATIONS = list("Disposals", #define CHAT_GHOSTEARS 4 #define CHAT_GHOSTSIGHT 8 #define CHAT_PRAYER 16 -//#define CHAT_RADIO 32 +#define CHAT_RADIO 32 #define CHAT_ATTACKLOGS 64 #define CHAT_DEBUGLOGS 128 #define CHAT_LOOC 256 #define CHAT_GHOSTRADIO 512 +#define SHOW_TYPING 1024 #define SOUND_ADMINHELP 1 #define SOUND_MIDI 2 @@ -843,12 +844,15 @@ var/list/restricted_camera_networks = list( //Those networks can only be accesse #define HAS_SKIN_TONE 16 #define HAS_SKIN_COLOR 32 - //Language flags. -#define WHITELISTED 1 // Language is available if the speaker is whitelisted. -#define RESTRICTED 2 // Language can only be accquired by spawning or an admin. -#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight -#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. +#define WHITELISTED 1 // Language is available if the speaker is whitelisted. +#define RESTRICTED 2 // Language can only be accquired by spawning or an admin. +#define NONVERBAL 4 // Language has a significant non-verbal component. Speech is garbled without line-of-sight +#define SIGNLANG 8 // Language is completely non-verbal. Speech is displayed through emotes for those who can understand. +#define HIVEMIND 16 // Broadcast to all mobs with this language. +#define NONGLOBAL 32 // Do not add to general languages list +#define INNATE 64 // All mobs can be assumed to speak and understand this language (audible emotes) +#define NO_TALK_MSG 128 // Do not show the "\The [speaker] talks into \the [radio]" message //Flags for zone sleeping #define ZONE_ACTIVE 1 diff --git a/code/stylesheet.dm b/code/stylesheet.dm index 441ffc17000..b7111e1e5a1 100644 --- a/code/stylesheet.dm +++ b/code/stylesheet.dm @@ -67,9 +67,18 @@ h1.alert, h2.alert {color: #000000;} .noticealien {color: #00c000;} .alertalien {color: #00c000; font-weight: bold;} .tajaran {color: #803B56;} +.tajaran_signlang {color: #941C1C;} .skrell {color: #00CED1;} .soghun {color: #228B22;} +.solcom {color: #22228B;} +.changeling {color: #800080;} .vox {color: #AA00AA;} +.diona {color: #007200;} +.trinary {color: #727272;} +.kidan {color: #664205;} +.slime {color: #0077AA;} +.rough {font-family: "Trebuchet MS", cursive, sans-serif;} +.say_quote {font-family: Georgia, Verdana, sans-serif;} .say_quote {font-family: Georgia, Verdana, sans-serif;} diff --git a/config/example/config.txt b/config/example/config.txt index a26aa4575d6..454dcca2d0c 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -256,7 +256,7 @@ ADMIN_LEVELS 2 CONTACT_LEVELS 1;5 ## Defines all Z-levels a character can typically reach -PLAYER_LEVELS 1;3;4;5;6 +PLAYER_LEVELS 1;3;4;5;6;7 ## Expected round length in minutes EXPECTED_ROUND_LENGTH 120 diff --git a/icons/mob/human_races/r_golem.dmi b/icons/mob/human_races/r_golem.dmi new file mode 100644 index 0000000000000000000000000000000000000000..f9cfb8e157c7b5440b2ee7135e888a9c4ac2b446 GIT binary patch literal 11595 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 GfA}}yDYV%D literal 0 HcmV?d00001 diff --git a/icons/mob/human_races/r_shadow.dmi b/icons/mob/human_races/r_shadow.dmi new file mode 100644 index 0000000000000000000000000000000000000000..70450af690243fd20f537d6b1d6606549b15265a GIT binary patch literal 1760 zcmYLKc{rQt7XQ91MMA|@bmD3((-zfGTQ?%Hv`jmp#HF3qI@T&FVHA;2OY4rCblTf% ztJ0}@YKWFv5~^t#OHt}h)e>7!)oY183;8BGf86JJpL5>xd(Ziu<^AK__8^~CLt#+> z0I0dSI(q^DsJMav09_GtN`;1j$PP| zpm~zL0OF^iP=(QwMDe9Lhr|WPMo?)HG0^~!Sd=^Pd~do1X3r#-p0g*x=*yQN{VbAS zX~e)yTkS}WmT(lEpih3eh?htqJr-hnMxEf=5YGCI-@GvKF@38r8El+WtrY% zc@`D-!r~sv1Ueo$kU{<~@7GMp#^WNX>)PHvvs8l~?fYZi49>pqeW0avbaqUef#6We zT>wBD3#{1E~Fd z{jco_#N^;%RVw=D#Q{`j)y`?KJ4#R?A(plL_M>jKr;cM!CqM`O#0|W z3f3S;G-r#E@9M82uD1-mzI5q8JN$9cH`!bLYEB(l1>WJoN=fY_ykfsQg8D?4h5jb* ztqk=3WE0!ZSomxe2!@8=MR~Xc&-WSXG7i$B^pFAO^-GN$AIlmTqdc-1MziQs)to#7 zn#lO#BWXAeRtbOVUZ|dC|6%Qtj_25F;9nG;ov_ohY4Q4hJo(&OHLXd}!%X}SpN;&8 zg%swZ2-S#s=NrS?bXBXbkMc@zBw-M{N4$7LyzQu*@6VPXcSYs|Bh>&W1(&A8NQ;`f zgSuTkEW`PsNZsVp5TA{S2=21~`{}^Tp4qKu9=`MCBpJ^Q-QJ;X9efHX*rwJrpjTq( zcj(ms1W_I3j9sku&Mxy`*>+{dhZ%H-^-u=Qd(L@3B=}=}+bBu)XW?cIr!xmTnC>H~hZHVEeRf z@RIXHb(oaRwBs@{rlOPQHKJ~=zOf0q@iaR5gw>`c0SsdwFK_cg6echV*&Z&(AgL-U zI}@9(ul&ZIg5%U?bq|oFZ5McD*se|;Bs;sUM^#-bKpU6d<>XVmt%A8Ims)9w`WeNN zRVOj`pv{3J0mCNw69@iiWzGNAzagArkolL^1tGJ;r<(k?q;^)BuU&!0#bGbuA>?1*9$0&WxD8t3s45@Hy8cw*rlIEM#cQ?^ z(`d5b6MR7l(KG1FnX^47x-);v>?N}SlZ7i#?;0?VqZc0Pum0(OSCHQ>!=*f$xE4`a z*8DE+$8HCVU7jsr%9$Qd$Di2IM!e`k-t(#U9yCMo_u$wN@uiLIPWbl@^7t#RyW^jz zwIvudutKh-I7Z`oN5mNd!hOLhog8;%_lmHe-8-js<>}1$6%{Vs?&`E=tSo%6{qW4@ zbLTl+z%FP#IET|ex=w(AYsc6O=4glIW@*}{p}lw;{w#GeS`J3za<401^Kn##ti&}I zDxA&+CqHB`d(>(FhdO>~daGbsgID!A5I?F5dL8(S(@2_^9JF+>n8lSW$(kfejdW{X z@v1sol4b${TGZnZ&;TL9GDXDrGFrhXhRV0$f9R-v^{l9-%fZ!De?=v2vxHe(0BmF| zdGq~`@$+ly>@C?FMK(EP0`ZqZOZ62*tnxe|`j;)4NsImpq$EVg$`WHo1KN>3Q+&-^ z=ADXS8a2(9AF3#~>C9}dz!t0~{4uv2nB6iiy&2f*+0sD>)h)mt0yd;rB8MGdFje?F zNC5#mwjlm$j=|upC;`EbNS~6S6Su)}B@dvM^`!FE>JFGD28|V?6HY6McEDOOD5`jo uxdSSk`KgR489a0a9#AsYDhHx*t^TE2K0U%K$KNV85a8xQcIG$+r2h$`%}*x) literal 0 HcmV?d00001 diff --git a/icons/mob/human_races/r_slime.dmi b/icons/mob/human_races/r_slime.dmi new file mode 100644 index 0000000000000000000000000000000000000000..287779d3c7bb250e720f0d911f83869ed0c319f4 GIT binary patch literal 4614 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 H?8E*AS~;BP literal 0 HcmV?d00001 diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi index 2cd0b40bb1887a9d2031eb9e4b7e675875e809ce..86534d162d0435461c00231259931f7fee7b91da 100644 GIT binary patch literal 2403 zcmb7Gc{Cf?8c(8jUQksjYAHrrW$dLz5Np*|TU8rs39STGDMljJw$^GbRY9~3I<#n7 zt(ugsQ9&q!BuztWi6v5E3#yYjZ_YdKocGR~^ZvNs?>pza-*>*{-rv2~y*!*{rS?ey z003E67nqL_34bmLF`>+(A&v-vmf{WK4ML3Yrhf}EG4^1*o#34$_WRqV$!pi&k1#Q8bp`@e{bN5ovFu(i6;g=!Sb3KU$oj=bxwK5T{FI_e?lon z>X*Xyb~3!hBo?)X(Z2kN)g4RYx6`Xw^kx#eL$>lbP5S5)Cbt*Uw>Ob$NL4B2HF8Iv zH0O$LxmM3OddtK*mqj>ANY34Xmqka2M{k*N8wsI1CUfOrJaWvGeIr)0Zd;!!hMmw{ zre3O#w&j`XT0Bs9^d{)#j;r

Oxm1m70J^u`2h=zOLQv5b1&1Vm+b>%ji}0hP{cD9r5z;u{gY#3)e#~68?Zs(RBtrhe zus&l(@A>%4khCF^zKW&Es-qeoF`EQOQk{~v_*)DS8A%Sxw;>@ev9E^s74uZ>8S;6%6Y=+xLt2sRP(ZTY47G=YLXLrXil%; zAR`NYpUoA63UwNy{uO_Zq+Wvy)Gh)z{z$DOaef54_GGX&Nl@AsE*^4MWW^ zX_eq}wd<3*EsxV_>b3w@+P8LrwFdydpNkm^54rQDM3{L~;&Z=^Zt)FimwS3%(IKPL zB3@RKMhfSG>0KYbDC}#f7YpzChkM^ijeAb`Ogc@F;l7X^=^ zHGuCgZf_qF5rs?kQ{_m9sMHx+0gn8WMJUaN8}^9WcNoq{L?0>#C|7^a>Gv$bxmgm9JOXR zG?Oxg8lc~brFOQkV+#YZYGl%92hZt@BKl~Ln^9T4%_4&V6yq=LD^|yZ0VNzE+)n%Fb@}r+_ZHwHEqAn2 zA3`gpeDFovzSnn-Yk0lXdLc7ZH|HiAarmyobbW8Igha@KJ#FZoHD0&6=Fm#z&EP<@ z&9SM${VdGp;u2{qKwYTxV`#taY|y_qKA2h;4Znh;=g6CFM$t8&O$@T?c_Yp2r1_US z+kNvFZKlGe!3!A`tFytt1(lBuBb>w3^#Vwu`wY+e$9#RkD$}s<>*lIT>`4`Mt&%B` zuJ@bV^65ml-~i&4(Rb_C;fl6Xm;(DXn%T!nLtOD-0QO0J=os-spkR@Mkd_0P%+a+r zd-MFEYZ9u)Y@2TuYKt~6xT#YCgD54Z>KsXH(Czas5fQJH(?Sd(XZONjgEr9$-U~&BK5=&=m40Qj2WpmTko?fjyci7=1 zqYx+Pm|0Kbfh1C-Q6hTHU~w6xhIl5ihw-Mb+<)ve)4o$M;_zoPE&X1{3IhC)^daD3!yf{_}}CMW9%T%ReIA!O(U zNc^>mmSaOEq}OsJuSm2zQ|?YJwCO? zgWM`WFM082fDs|!Tj2bFncYLMTz1(;TW%S{h@?hfvKSEXP^Sq8!Vc zj3|f5##Rn1I?$X~%xMmNd*AE3zW49%`u=#H-}5~8eLwee-`92D*OTJvY$v-{X|ITg zh^&J>+D*t};fRxx6wdbo{2@a88SQZnkH%gPhzPxk4-F3!5g`=RX4L=Ic~}O`oicD< z^rq?51s%MUXx?P=OU+HRPoyeSibMsJI)9e=bY-@X5jfFVEGFmkwu$c zm_8NhYIbt4U=>cWI`!84{6UZX!QDOL60gQg=UR6@7)>=L$w-XBtYQAFmNm*H8}St8 zu^dqAcj{yJ3tzq_#3|g((#f#4y$zcF!!|=>)S&a&x1S5+Nrju_;C86qIN|0L zuZBDS9AUL~e13h)Ka(4!_xldXs&Reu5l&##rXP#JwwJ}Y8|E4>TNw98G^l#zWUD(d z&&E>9X)2`)&$Ghg$-C~WU+xy1xsns!yDs;Dl!Fa`5~N}&ONP_n!a=^qVu_)nUjI>o zSP4GE>42-t#6*&4ZTN?hrOd26qf}|JxjqiZwRm-C;5yyXGM@?X4eTJbQ_rMey}q~U zD&^D1TGaWcYIXVtFINhMHQ?;o6huW~~P80`Gq_pR+?M4g1!s3Pt$_{*ma>cs$Q z#oy2h2Tjy&TZ_s61vi9@&9*{+G*Z#TSNwH@svN-h73kG!ocP`mF?q9Sfj+^Q=*Qal_E%!uf?`{f?4SK(4=3@db&_qt9YrMWXWkZf3*^{1s)jRi`JQmjX+9^5j z5Wm3hlYY9fW7f+*UJc4t=BYQGVxmN7R({Avb^rVp*sMxen!aZZ&tz?OAbOY1Kf|eU zd~3#y&-m_+BVHaxd^BopYsFx|9P9&~hi_smSHap+CMbN{=g|H;3*BJQ?Aj99wzPci zvql2l9xx5Bzy-Mb(DQOdxmuIv~NpI2N zNLCChIxqUAgTlk_HZv8@d`XX_H%l}0`S!1j`T&7or3ZM_F!BN0CA(6#a)?K$GuF_c zN+v1;*QPtiYwIJxAHw>6`eH0)_kuvjRTtp$i6#OXpMzvedRWS))yD(r~&2N-k2+(wA{DhJ6Qt7j8nUH+ag+FFGH=^CY-g2lWiCJwt4R%-h0kB(xY zCYcmO6X~R3DPTXo6g6MbVGT()wEU-L8V*acr#DzXnnkfiRc25@mHdubaWc`iY2P6h zzFc%9btYY)*C;2cm@%GMBy=B<*Fvi9fSznXP0!c}_XKWVtDOtaha_AewjM6s;`1k_ z*?c=mG(7GDO~VfAga}koorqcvTbXNqzP1}2e$nS=sAcKysP=(e>L4s`6B*sB9BULi z8Nwdwo+PfV8=udIV`d`%Qupq@1G*s4(D?g=gb`%7eSS!CF}x9k^T3?$jlr0o83-PRAyq zOu}Zn<6`g1h$Ez0;p;H`KF{5%nuvVI@}xkSy1mLN<^w+$-aR%D1Vdd;Tjfbr4rFS) zd;Y|6@}@XU^PYjmrfL#uc7!Z8F1;5N+Ue%v0+XE-V}|UE=gO(%-(9pLJD9WA;sdr5 zahbmly_0wl30gE$3*GZi;{VgL{x_6xF`!Uc!8{((r- zTmw^dWw1LO2GdVdQC8M^tm3X>-KgbO2z8z^v`gk~gh!5zBa+ke8kuLo2=$EXj=7uOYPYAkl zpnKOUkYqk`z_WcQyVRQls>R}~`cjyGheQ_q$QY;1#i=F-Mb_l}3#P`6msV6t iN796S{{KVPFM#zVtm#HTxw!CyA>v@`jDBM68~<;n5)jJ( diff --git a/icons/obj/robot_storage.dmi b/icons/obj/robot_storage.dmi index 5a996c01e7e7678414e5f90f6559d1b22c0e90e9..2382586eee7febdb948c65d6b85c47bee84fb94e 100644 GIT binary patch delta 4978 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 delta 5060 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

hZ*Cr-Dn>ny~;;r|MjJghXLoZFEJ)aB$p#b{u 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

Ty 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%0A)bTtT9TMvJ#~igs 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 diff --git a/nano/images/uiTitleFluff-Syndicate.png b/nano/images/uiTitleFluff-Syndicate.png index b2a32013f862ef583e38c39b6583e009970c8f3f..b09f5ba6b29ca06a13e7972b84295dd7d8997f11 100644 GIT binary patch literal 1429 zcmV;G1#0??>1o_^z`)DLqb9_gb;S`g{rDHMMp>X_4f8=3n9X0)zyW~I(v4} zjNaY_LHF*3NpAPtpy6Q~Fc+{H+a3bLT1bdnv)kR8-G1v)c=$C>Mn=!@mM!g3QBkgc z1k~kntqKYX%J#KT)3l}~F)=}-DJdU?c6Uc1g!U*R;@7dr$h%{U7Y{y)j2zZ&wzJP{ z-(F(?!~i^ZV9%Z%LHF;+hV=G69diBpycvCc&k9A+q>+&dpi)5NR6v8R16|i$s;XvK zJOaQxSx%bcaBKzo$HK#h28)Z^JS$fY`LMU7yQ^zXTwL6!F&+g*T^l#v1SH@mbKw)G zPIfgP)Z6q;qNL5vQbs*3C5JgcYtaE2(4gmX&CB;Cx4p(%@pVFfM2?+^qpmZcY{zOQB z|MG#Nq7y>}1=lo9>!Pd-MNy`TQdmbvM`l7o!Wk=2As)*zmdD2*7LTW1s}5^`PjpBZ z@U~x%{+$Bwlv-Bt#(U(KlXlke7xLo>C!eI z1=9c|0Z-}h#iSn9;Zr~p@CGR#$G2I}?iu(izW@ICCyJIr)c{mX?Qr-3()ZEuy8RWmRfwYFlDb(qVJ5t+iDq zFdM}{mk!ken!P<*1nd>yu}-F@rn)SA8Zb$xrKh**#`Aa0&9Y%2P~P|&GiP20Y(iBdy!Hfww-)%oSB{1OwYJkRu2HEmuODzI0U7)uOOcQ|q2807QrsL7ISy`t6zOAo+53u0luzB<5HdR&oCd*HAk5yhHYHJr|7Z<-Z z6dfJ*)sZ9nCY4Yx&*lOj8&fI%=*bt=Jb3V+CNwm3*Hk&GC<+nh&Mklo~k|bsLvc2&9dAkm~MoUUcfH}8TtoZ(fELZwdFEO3}7UM3k0eIDzx(IX{7vh`1 zU0~Szh7ZgK76388^T0|V2sjBG4djMDEudbY7Xd4bgJXc_fO*E{W!Cr-Jis5u2iydH j2Ce|@05|(FS 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 diff --git a/paradise.dme b/paradise.dme index fa33cb1324b..3b01e089723 100644 --- a/paradise.dme +++ b/paradise.dme @@ -239,6 +239,7 @@ #include "code\defines\procs\AStar.dm" #include "code\defines\procs\dbcore.dm" #include "code\defines\procs\hud.dm" +#include "code\defines\procs\radio.dm" #include "code\defines\procs\sd_Alert.dm" #include "code\defines\procs\statistics.dm" #include "code\game\asteroid.dm" @@ -959,6 +960,7 @@ #include "code\modules\clothing\masks\breath.dm" #include "code\modules\clothing\masks\gasmask.dm" #include "code\modules\clothing\masks\miscellaneous.dm" +#include "code\modules\clothing\masks\voice.dm" #include "code\modules\clothing\shoes\colour.dm" #include "code\modules\clothing\shoes\magboots.dm" #include "code\modules\clothing\shoes\miscellaneous.dm" @@ -1159,6 +1161,7 @@ #include "code\modules\mob\abilities.dm" #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" +#include "code\modules\mob\hear_say.dm" #include "code\modules\mob\holder.dm" #include "code\modules\mob\inventory.dm" #include "code\modules\mob\language.dm" @@ -1172,6 +1175,7 @@ #include "code\modules\mob\mob_transformation_simple.dm" #include "code\modules\mob\say.dm" #include "code\modules\mob\transform_procs.dm" +#include "code\modules\mob\typing_indicator.dm" #include "code\modules\mob\update_icons.dm" #include "code\modules\mob\camera\camera.dm" #include "code\modules\mob\dead\death.dm"