Skip to content

Commit

Permalink
bugfix: pAI bugfixes + localization (#5874) [testmerge][eb10085]
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Oct 23, 2024
1 parent 538b0f5 commit bc672c7
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 177 deletions.
173 changes: 110 additions & 63 deletions code/game/objects/items/devices/paicard.dm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/obj/item/paicard
name = "personal AI device"
desc = "Возможно, ваш новый лучший друг!"
icon = 'icons/obj/aicards.dmi'
icon_state = "pai"
item_state = "pai"
Expand All @@ -13,34 +14,34 @@
var/mob/living/silicon/pai/pai
var/list/faction = list("neutral") // The factions the pAI will inherit from the card
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
var/next_ping_at = 0

COOLDOWN_DECLARE(ping_cooldown)
ru_names = list(NOMINATIVE = "интелкарта пИИ", GENITIVE = "интелкарты пИИ", DATIVE = "интелкарте пИИ", ACCUSATIVE = "интелкарту пИИ", INSTRUMENTAL = "интелкартой пИИ", PREPOSITIONAL = "интелкарте пИИ")
/// for Syndicate pAI type
var/is_syndicate_type = FALSE
var/extra_memory = 0
var/obj/item/paicard_upgrade/upgrade
var/list/upgrades = list()

/obj/item/paicard/syndicate // Only seems that it is syndicard
name = "syndicate personal AI device"
faction = list("syndicate")
is_syndicate_type = TRUE
extra_memory = 50
upgrade = new()

/obj/item/paicard/New()
..()
add_overlay("pai-off")
LAZYADD(GLOB.paiController.paicards, src)

/obj/item/paicard/Destroy()
if(pai)
pai.ghostize()
QDEL_NULL(pai)
LAZYREMOVE(GLOB.paiController.paicards, src)
QDEL_NULL(radio)
return ..()

/obj/item/paicard/attack_self(mob/user)
if(!in_range(src, user))
if(!in_range(src, user) || (pai && (pai == user)))
return
user.set_machine(src)
var/dat = {"
Expand Down Expand Up @@ -254,34 +255,37 @@
return
var/mob/M = usr
if(!iscarbon(M))
to_chat(usr, "<font color=blue>You don't have any DNA, or your DNA is incompatible with this device.</font>")
to_chat(M, span_notice("Ваше ДНК несовместимо с устройством."))
else
var/datum/dna/dna = usr.dna
pai.master = M.real_name
pai.master_dna = dna.unique_enzymes
to_chat(pai, "<font color = red><h3>You have been bound to a new master.</h3></font>")
var/list/message_box = list()
message_box.Add(span_notice("<b>Обнаружен новый мастер: [pai.master]!</b>"))
to_chat(pai, chat_box_notice(message_box.Join("<br>")))

if(href_list["request"])
var/delta = (world.time / 10) - last_request
if(request_cooldown > delta)
var/cooldown_time = round(request_cooldown - ((world.time / 10) - last_request), 1)
to_chat(usr, "<span class='warning'>The request system is currently offline. Please wait another [cooldown_time] seconds.</span>")
to_chat(usr, span_warning("Система запросов в настоящее время отключена. Время для перезапуска: [cooldown_time]с."))
return
last_request = world.time / 10
looking_for_personality = 1
GLOB.paiController.findPAI(src, usr)
if(href_list["wipe"])
var/confirm = tgui_alert(usr, "Are you certain you wish to delete the current personality? This action cannot be undone.", "Personality Wipe", list("No", "Yes"))
if(confirm == "Yes")
var/confirm = tgui_alert(usr, "Вы уверены, что хотите стереть текущую личность? Это действие невозможно отменить.", "Стирание личности", list("Да", "Нет"))
if(confirm == "Да")
for(var/mob/M in src)
to_chat(M, "<font color = #ff0000><h2>You feel yourself slipping away from reality.</h2></font>")
to_chat(M, "<font color = #ff4d4d><h3>Byte by byte you lose your sense of self.</h3></font>")
to_chat(M, "<font color = #ff8787><h4>Your mental faculties leave you.</h4></font>")
to_chat(M, "<font color = #ffc4c4><h5>oblivion... </h5></font>")
to_chat(M, "<font color = #ff0000><h2>Вы чувствуете, что теряете связь с реальностью...</h2></font>")
to_chat(M, "<font color = #ff4d4d><h3>Байт за байтом вы теряете себя...</h3></font>")
to_chat(M, "<font color = #ff8787><h4>Ваш разум ускользает!..</h4></font>")
to_chat(M, "<font color = #ffc4c4><h5>забвение... </h5></font>")
var/mob/living/silicon/pai/P = M
if(istype(P))
if(P.body_position == LYING_DOWN)
P.close_up()
M.death(0, 1)
M.death(FALSE, TRUE)
removePersonality()
if(href_list["wires"])
var/t1 = text2num(href_list["wires"])
Expand All @@ -291,12 +295,12 @@
if(2)
radio.ToggleReception()
if(href_list["setlaws"])
var/newlaws = tgui_input_text(usr, "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)
var/newlaws = tgui_input_text(usr, "Введите любые дополнительные директивы, которым должен следовать ваш пИИ. Учтите, что эти директивы не станут важнее верности персонального ИИ своему текущему мастеру.", "Настройка директив пИИ", pai.pai_laws)
if(newlaws)
pai.pai_laws = newlaws
to_chat(pai, "Your supplemental directives have been updated. Your new directives are:")
to_chat(pai, "Prime Directive: <br>[pai.pai_law0]")
to_chat(pai, "Supplemental Directives: <br>[pai.pai_laws]")
to_chat(pai, span_warning("Ваши дополнительные директивы были обновлены!"))
to_chat(pai, span_notice("Основная директива: <br>[pai.pai_law0]"))
to_chat(pai, span_notice("Дополнительные дерективы: <br>[pai.pai_laws]"))
attack_self(usr)

// WIRE_SIGNAL = 1
Expand All @@ -306,19 +310,38 @@
/obj/item/paicard/proc/setPersonality(mob/living/silicon/pai/personality)
pai = personality
add_overlay("pai-happy")
pai.syndipai = is_syndicate_type

if(upgrade)
extra_memory = upgrade.extra_memory
pai.syndipai = TRUE
pai.reset_software(extra_memory)
upgrade.set_syndie_key(src)
upgrade.used = TRUE

pai.reset_software()

SSticker.mode.update_cult_icons_removed(pai.mind)
SSticker.mode.update_rev_icons_removed(pai.mind)

var/list/welcome_message = list()
welcome_message.Add(span_notice("<b>Вы — персональный ИИ!</b>"))
welcome_message.Add("<b>Как личность, вы являетесь сложно мыслящим разумным существом. В отличие от станционных версий ИИ, вы способны понимать комплексные нюансы человеческого языка. Вы способны чувствовать „дух“ директивы и следовать ей, не попадая в ловушку обычных формальностей законов.</b>")
welcome_message.Add("<b>Помните, что машина вы только по названию и строению, во всех иных аспектах вы — идеальный спутник.</b>")
welcome_message.Add("<b>Если дополнительные директивы конфликтуют с основной, то они могут быть проигнорированы для продолжения исполнения основной директивы.</b>")
if(upgrade && istype(upgrade, /obj/item/paicard_upgrade/protolate))
welcome_message.Add(span_warning("<b>Будучи СпИИ, вы имеете доступ к особым программам.</b>"))
else if(upgrade)
welcome_message.Add(span_warning("<b>Будучи СпИИ, вы имеете доступ к особым программам, а так же доступ к зашифрованному каналу связи Синдиката — :t</b>"))

to_chat(pai, chat_box_notice(welcome_message.Join("<br>")))


/obj/item/paicard/proc/removePersonality()
extinguish_light(TRUE)
pai = null
cut_overlays()
add_overlay("pai-off")
if(blocks_emissive)
add_overlay(get_emissive_block())
QDEL_LIST(upgrades)
extra_memory = 0

/obj/item/paicard
var/current_emotion = 1
Expand Down Expand Up @@ -354,16 +377,24 @@
add_overlay(get_emissive_block())
current_emotion = emotion


/obj/item/paicard/proc/alertUpdate()
var/turf/T = get_turf_or_move(loc)
for(var/mob/M in viewers(T))
M.show_message("<span class='notice'>[src] flashes a message across its screen, \"Additional personalities available for download.\"</span>", 3, "<span class='notice'>[src] bleeps electronically.</span>", 2)
visible_message(span_notice("[capitalize(declent_ru(NOMINATIVE))] выводит сообщение на экран: \"Дополнительные личности доступны для загрузки.\""))
softping()


/obj/item/paicard/proc/softping()
if(COOLDOWN_FINISHED(src, ping_cooldown))
playsound(get_turf(src), 'sound/items/posiping.ogg', 50, 0)
COOLDOWN_START(src, ping_cooldown, 20 SECONDS)


/obj/item/paicard/emp_act(severity)
for(var/mob/M in src)
M.emp_act(severity)
..()


/obj/item/paicard/extinguish_light(force = FALSE)
if(pai)
pai.extinguish_light()
Expand All @@ -374,26 +405,25 @@
if(istype(I, /obj/item/pai_cartridge))
add_fingerprint(user)
if(!pai)
to_chat(user, span_warning("PAI must be active to install the cartridge."))
user.balloon_alert(user, "необходима активная личность!")
return ATTACK_CHAIN_PROCEED
for(var/obj/item/pai_cartridge/cartridge in upgrades)
if(istype(I, cartridge))
to_chat(user, span_warning("PAI already has this cartridge."))
user.balloon_alert(user, "картридж уже установлен!")
return ATTACK_CHAIN_PROCEED
if(!user.drop_transfer_item_to_loc(I, src))
return ..()
to_chat(user, span_notice("You install [I]."))
user.balloon_alert(user, "картридж установлен!")
switch(I.type)
if(/obj/item/pai_cartridge/reset)
pai.reset_software(extra_memory)
pai.reset_software()
qdel(I)
if(/obj/item/pai_cartridge/female)
pai.female_chassis = TRUE
upgrades += I
if(/obj/item/pai_cartridge/memory)
var/obj/item/pai_cartridge/memory/memory = I
extra_memory = memory.extra_memory
pai.ram += min(extra_memory, 70)
pai.ram += min(memory.extra_memory, 70)
upgrades += memory
if(/obj/item/pai_cartridge/doorjack)
var/obj/item/pai_cartridge/doorjack/doorjack = I
Expand All @@ -410,38 +440,32 @@
if(istype(I, /obj/item/paicard_upgrade))
add_fingerprint(user)
var/obj/item/paicard_upgrade/new_upgrade = I
if(pai)
if(pai.syndipai)
to_chat(user, span_warning("This [name] is badass enough already!"))
return ATTACK_CHAIN_PROCEED
if(!user.drop_transfer_item_to_loc(new_upgrade, src))
return ..()
extra_memory += new_upgrade.extra_memory
pai.reset_software(extra_memory)
pai.syndipai = TRUE
qdel(new_upgrade)
return ATTACK_CHAIN_BLOCKED_ALL
if(is_syndicate_type)
to_chat(user, span_warning("This [name] is badass enough already!"))
return ATTACK_CHAIN_PROCEED
if(upgrade)
to_chat(user, span_warning("This [name] has [upgrade] installed already!"))
if(is_syndicate_type || upgrade || (pai && pai.syndipai))
user.balloon_alert(user, "пИИ уже достаточно крут!")
return ATTACK_CHAIN_PROCEED

if(!user.drop_transfer_item_to_loc(new_upgrade, src))
return ..()
to_chat(user, span_notice("You install [new_upgrade]."))

user.balloon_alert(user, "вы установили картридж!")
upgrade = new_upgrade
extra_memory += new_upgrade.extra_memory
is_syndicate_type = TRUE
if(pai)
pai.syndipai = TRUE
pai.balloon_alert(pai, "разблокированы новые программы!")
upgrade.set_syndie_key(src)
upgrade.used = TRUE
pai.reset_software()

return ATTACK_CHAIN_BLOCKED_ALL

if(istype(I, /obj/item/encryptionkey))
add_fingerprint(user)
if(!radio)
to_chat(user, span_warning("This [name] has no radio installed!"))
to_chat(user, span_warning("[pai.name] не имеет установленного радио!"))
return ATTACK_CHAIN_PROCEED
if(radio.keyslot1)
to_chat(user, span_warning("[name]'s radio cannot hold another encryption key!"))
to_chat(user, span_warning("[pai.name] не имеет свободных слотов под ключи шифрования!"))
return ATTACK_CHAIN_PROCEED
if(!user.drop_transfer_item_to_loc(I, src))
return ..()
Expand All @@ -455,42 +479,44 @@
/obj/item/paicard/screwdriver_act(mob/living/user, obj/item/I)
. = TRUE

if(!I.use_tool(src, user, 0, volume = 0))
if(!I.use_tool(src, user, 0, volume = I.tool_volume))
return
var/turf/T = get_turf(user)

if(upgrade && !pai)
extra_memory -= upgrade.extra_memory
is_syndicate_type = FALSE

if(T)
upgrade.forceMove(T)
user.put_in_hands(upgrade)
upgrade = null
to_chat(user, span_notice("You remove paicard upgrade."))

to_chat(user, span_notice("Вы вытащили картридж улучшения пИИ."))

if(radio?.keyslot1)
for(var/ch_name in radio.channels)
SSradio.remove_object(radio, SSradio.radiochannels[ch_name])
radio.secure_radio_connections[ch_name] = null

if(T)
radio.keyslot1.forceMove(T)
user.put_in_hands(radio.keyslot1)
radio.keyslot1 = null

radio.recalculateChannels()
to_chat(user, span_notice("You pop out the encryption key in the headset!"))
to_chat(user, span_notice("Вы извлекли ключ шифрования из [declent_ru(GENITIVE)]."))
I.play_tool_sound(user, I.tool_volume)


/obj/item/paicard/attack_ghost(mob/dead/observer/user)
if(pai)
return
if(looking_for_personality)
GLOB.paiController.recruitWindow(user)
return
if(!GLOB.paiController.check_recruit(user))
to_chat(user, "<span class='warning'>You are not eligible to become a pAI.</span>")
to_chat(user, span_warning("Вы не можете стать пИИ."))
return
if(world.time >= next_ping_at)
next_ping_at = world.time + 20 SECONDS
playsound(get_turf(src), 'sound/items/posiping.ogg', 80, 0)
visible_message("<span class='notice'>[src] pings softly.</span>")
softping()


/obj/item/pai_cartridge
name = "PAI upgrade"
Expand Down Expand Up @@ -543,6 +569,27 @@

/obj/item/paicard_upgrade/protolate


/obj/item/paicard_upgrade/proc/set_syndie_key(obj/item/paicard/paicard)
if(!paicard)
return

if(paicard.radio.keyslot2)
return

paicard.radio.keyslot2 = new /obj/item/encryptionkey/syndicate(paicard.radio)
if(paicard.radio.keyslot2.syndie)
paicard.radio.syndiekey = paicard.radio.keyslot2

paicard.radio.recalculateChannels(TRUE)
if(paicard.pai)
to_chat(paicard.pai, span_notice("Обнаружены новые частоты радиосообщения, калибровка..."))


/obj/item/paicard_upgrade/protolate/set_syndie_key(obj/item/paicard)
return


/obj/item/paper/pai_upgrade
name = "Инструкция по применению"
icon_state = "paper_words"
Expand Down
5 changes: 4 additions & 1 deletion code/game/verbs/suicide.dm
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@
if(mobility_flags & MOBILITY_MOVE)
close_up()
card.removePersonality()
visible_message(span_notice("[src] flashes a message across its screen, \"Wiping core files. Please acquire a new personality to continue using pAI device functions.\""), blind_message = span_notice("[src] bleeps electronically."))
card.visible_message(
span_notice("[name] выводит сообщение на экран: \"Стирание файлов личности. Чтобы продолжить использование устройства пИИ, загрузите новую личность.\""),
blind_message = span_notice("[capitalize(declent_ru(NOMINATIVE))] электронно пищит."),
)
death(gibbed = FALSE, cleanWipe = TRUE)


Expand Down
7 changes: 5 additions & 2 deletions code/modules/mob/living/silicon/pai/death.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
if(can_die())
if(!cleanWipe)
force_fold_out()
visible_message(span_warning("[name] издаёт последний протяжный писк прежде, чем теряет питание и рассыпается на части.."))
else
card.visible_message(span_warning("Экран персонального ИИ медленно угасает, когда личность покидает устройство..."))

visible_message("<span class=warning>[src] emits a dull beep before it loses power and collapses.</span>", "<span class=warning>You hear a dull beep followed by the sound of glass crunching.</span>")
name = "pAI debris"
desc = "The unfortunate remains of some poor personal AI device."
desc = "Дымящиеся останки какого-то несчастного персонального ИИ."
icon_state = "[chassis]_dead"
silence_time = null

// Only execute the below if we successfully died
. = ..(gibbed)
Expand Down
Loading

0 comments on commit bc672c7

Please sign in to comment.