Модератор форума: КсюXa, ApeX  
Форум » Fallout: New Vegas » Мастерская » Скрипты (Вопросы и ответы)

Скрипты
a3apbi4  Offline  Сообщение №1 написано: 7 декабря 2010, 18:01



11
Скрипты - неотъемлемая часть GECK. При написании возникает очень много казусов. Данная тема должна помочь не наступать на "грабли" новичкам и делиться опытом с другими более продвинутых мододелов.




KAIN48  Offline  Сообщение №1051 написано: 21 октября 2013, 17:56


Шаманистый шаман


Привет всем!
Подскажите пожалуйста реально ли сделать такое:
Один знакомый на другом сайте попросил помочь!
Он хочет
Создал список и добавил в него стимуляторы, назначил этот список как патроны для оружия "Ракетка" (такая система в оружии с названием "ракетка"),
Если у оружия урон нулевой - получаются холостые выстрелы. А если ненулевой то идет повреждение и агрессия NPC!

Мы вышли из дома, когда во всех... Поздно вышли!
Artem13  Offline  Сообщение №1052 написано: 22 октября 2013, 03:32


Mercenaries. Со смертью на ты.


KAIN48, про зарядку сделано всё верно. Работает для любого оружия, а не только для Ракетки. Про попадания - пусть посмотрит как реализован Архимед. Т.е. простое попадание стимулятором эффекта не даст, нужно рисовать скрипт, в котором реализовывать лечение. Как наложить эффект на цель пусть в Архимеде и смотрит. Я давненько не занимался фоллом и не скажу точнее.

<a class="link" href="http://nick-name.ru/sertificates/278209/" rel="nofollow" target="_blank"> border="0" alt=""/</a>
Да, мы бандиты и бродяги, как злословит молва,
Мы попадаем в передряги, помня эти слова.
Смотри вперед и не сдавайся ты на милость судьбе!
Предай их всех, останься верен себе. (Канцлер Ги - Кантри Бреган Д'Эрт)
JupiterJour  Offline  Сообщение №1053 написано: 22 октября 2013, 21:22


_


Цитата KAIN48

Подскажите пожалуйста реально ли сделать такое


В Фоллаутах NPC очень обидчивые - даже если хочешь их облагодетельствовать, если эффект исходит от оружия - хоть от безвредной пушки, хоть от безвредного взрыва - принимают это за нападение и сразу злятся.
Помнится, было обсуждение (отсюда и досюда), может быть пригодится.
И про зарядку хламом в Нью-Вегасе (неутешительно).

KAIN48  Offline  Сообщение №1054 написано: 23 октября 2013, 04:06 | Отредактировано: KAIN48 - 24 октября 2013, 02:19


Шаманистый шаман


JoopeeterArtem13 Привет!
Спасибо за советы!
Собрал из того обсуждения такое!

scn AAATestHealthScript
Ref Self

Begin ScriptEffectStart

Set Self to GetSelf
Self.StopCombat

player.pushactoraway Self 5
ClearActorsFactionsPlayerEnemyFlag

Self.additem stimpak 1
Self.equipitem stimpak
Self.EVP

End

Begin ScriptEffectFinish
restoreAV aggression 3
End

Не знаю правильно или нет!
Работает интересно - после выстрела обычным оружием, непись краснеет и бросается в бой.
После смены оружия на винтовку-усмирялку, личилку и выстрела по неписю. Он падает, затем встаёт и идёт себе дальше грядки тяпать!
Конечно не видно вылечился он или нет - шкалы здоровья не видно (только через VATS), но если снова стрелять из обычной винтовки - шкала здоровья убавляется с полной.

А вот интересно!?
Есть какая нибудь функция, что бы после падения, непись не вставал а засыпал?
Как нибудь подкладывать под него "скрытый" активатор - маркер подстилки(матрасик) и делать доступным обмен в инвентаре.
Или как нибудь задержать анимацию вставания таймером.

Получалось бы смешно! Такой грабитель с винтовкой снаряжённой патронами шприцами со снотворным!

Мы вышли из дома, когда во всех... Поздно вышли!
Artem13  Offline  Сообщение №1055 написано: 23 октября 2013, 05:02


Mercenaries. Со смертью на ты.


Цитата KAIN48

А вот интересно!?

Да мне кажется можно. По тому же архимедовскому принципу.

<a class="link" href="http://nick-name.ru/sertificates/278209/" rel="nofollow" target="_blank"> border="0" alt=""/</a>
Да, мы бандиты и бродяги, как злословит молва,
Мы попадаем в передряги, помня эти слова.
Смотри вперед и не сдавайся ты на милость судьбе!
Предай их всех, останься верен себе. (Канцлер Ги - Кантри Бреган Д'Эрт)
tundruck73  Offline  Сообщение №1056 написано: 23 октября 2013, 05:12 | Отредактировано: tundruck73 - 23 октября 2013, 05:13



Может быть, повесить эффект с таймером секунд на тридцать, в Begin ScriptEffectStart написать что-нибудь вроде:
npcreference.PushActorAway npcreference -1
npcreference.setRestrained 1
npcreference.IgnoreCrime 1

а в "финише" соответственно:

npcreference.setRestrained 0
npcreference.IgnoreCrime 0

Мосье, же не манж па сис жур...
Умер 23.04.2019
Hellraiser  Offline  Сообщение №1057 написано: 24 октября 2013, 08:14 | Отредактировано: Hellraiser - 24 октября 2013, 08:27


Dr. Moreau


Подскажите такую вещь, пожалуйста.
Сделал терминал, через который хочу телепортироваться в разные локации. В результ-скрипте нужной строки терминала пишу Player.moveto xmarker(такой-то). xmarker(такой-то), естественно, уже расположен в нужной локации.
Нажимаю строку в терминале - начинается загрузка и виснет намертво... Xmarker находится в интерьерной локации, а не в миру.
Возможно, нужна другая команда?

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
Artem13  Offline  Сообщение №1058 написано: 24 октября 2013, 09:15 | Отредактировано: Artem13 - 24 октября 2013, 09:34


Mercenaries. Со смертью на ты.


Hellraiser,
1. Попробуй маркер поставить "в мир". Чтобы определиться - из-за этого ли косяк. Хотя я сомневаюсь.
2. На обломовском вики сказано, что при использовании в резалт-скриптах есть скрытый баг. И рекомендуют делать телепорт во внешнем скрипте через переменную-флаг, которая взводится в резалт-скрипте.
3. Попробуй ф-цию SetPos

Код
float xPos
float yPos
float zPos

...
set xPos to xmarker(такой-то).GetPos X
set yPos to xmarker(такой-то).GetPos Y
set zPos to xmarker(такой-то).GetPos Z

player.SetPos X xPos
player.SetPos Y yPos
player.SetPos Z zPos


Но она скорее всего не работает для перемещения между интерьерами. Тогда останется только способы 2 и 4.

4. Разделить выбор точки назначения и момент отправки. Например так - на терминале выбираешь пункт назначения, а собственно перемещение производится по кнопке-активатору , например имеющего символьную ссылку TeleportButtonREF и скрипт на ней TeleportBtnScript:
Код
scn TeleportBtnScript
short sDestPoint

begin OnActivate player

       if sDestPoint == 1
          player.MoveTo MyMarker1
       elseif sDestPoint == 2
          player.MoveTo MyMarker2
       ...
       endif

       set sDestPoint to 0
end

В синтаксисе могу немного ошибиться - не помню точно как именно строится скрипт. Могу потерять какой-нибудь end.

В резалт-скрипте соотв. строки пишешь set TeleportButtonREF.sDestPoint to X (где X - номер точки назначения). Внимание, сначала должен быть написан скрипт телепорта и повешен на маркер. Иначе резалт-скрипт не скомпилируется.

<a class="link" href="http://nick-name.ru/sertificates/278209/" rel="nofollow" target="_blank"> border="0" alt=""/</a>
Да, мы бандиты и бродяги, как злословит молва,
Мы попадаем в передряги, помня эти слова.
Смотри вперед и не сдавайся ты на милость судьбе!
Предай их всех, останься верен себе. (Канцлер Ги - Кантри Бреган Д'Эрт)
Hellraiser  Offline  Сообщение №1059 написано: 24 октября 2013, 09:50


Dr. Moreau


Artem13, спасибо, поиграюсь.  :)

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
Spalny_Vagon  Offline  Сообщение №1060 написано: 24 октября 2013, 10:05


Мастер


Цитата Hellraiser

Нажимаю строку в терминале - начинается загрузка и виснет намертво... Xmarker находится в интерьерной локации, а не в миру.
Возможно, нужна другая команда?


Прежде, чем телепортироваться, нужно выйти из меню терминала:
Код
forceterminalback
player.moveto [куда ID]

Если в результ-скриптах и в самом деле бывают скрытые баги, как пишет Artem13, то в этом случае действительно, лучше использовать внешний скрипт, на том же терминале, в частности. То есть вначале в результ-скрипте меняется переменная внешнего скрипта, потом выход из терминала, и только потом внешний скрипт выполняет перемещение.

======================
Мод "Нью-Йорк" на русском: https://modgames.net/load/fallout3/addon/new-york-bolshoe-yabloko/34-1-0-1294
Мод "Нью-Йорк" на английском: https://modgames.net/load/fallout3/kvesty/the-big-apple/23-1-0-19771
Artem13  Offline  Сообщение №1061 написано: 24 октября 2013, 10:47


Mercenaries. Со смертью на ты.


Цитата Spalny_Vagon

лучше использовать внешний скрипт, на том же терминале, в частности.


Ага, что то я ступил, не сообразил, что внешний скрипт можно собственно на терминал повесить... Хотя идея с кнопкой мне всё-равно нравится больше...

<a class="link" href="http://nick-name.ru/sertificates/278209/" rel="nofollow" target="_blank"> border="0" alt=""/</a>
Да, мы бандиты и бродяги, как злословит молва,
Мы попадаем в передряги, помня эти слова.
Смотри вперед и не сдавайся ты на милость судьбе!
Предай их всех, останься верен себе. (Канцлер Ги - Кантри Бреган Д'Эрт)
Hellraiser  Offline  Сообщение №1062 написано: 24 октября 2013, 11:07


Dr. Moreau


Spalny_Vagon, "форсированный" выход из терминала помогает, но срабатывает 1 раз из 5-ти. Видимо, придется действительно делать через внешний скрипт...

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
djsave  Offline  Сообщение №1063 написано: 24 октября 2013, 14:33


=TMG= TeamModingGames


505
Hellraiser, если это принципиально важно то могу придя домой трухнуть познаниями скриптинга фола и сделать тебе рабочий скелет. 
Но это будет только часа через 4, я еще на работе и потом домой ехать. 
Я правильно понял что тебе надо перемещаться в разные места, а выбор места происходит в терминале, перемещение сразу после выбора.

=TMG= Team Moding Games
Hellraiser  Offline  Сообщение №1064 написано: 24 октября 2013, 16:28 | Отредактировано: Hellraiser - 24 октября 2013, 16:30


Dr. Moreau


djsave, был бы очень благодарен.
Именно так - перемещаться нужно в четыре разных локации на маркеры через "нажатие" строки в терминале.

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
djsave  Offline  Сообщение №1065 написано: 24 октября 2013, 17:51


=TMG= TeamModingGames


505
В общем я делаю и кидаю ссылку сюда - до полуночи сегодня попробую все сделать чинно.

=TMG= Team Moding Games
Hellraiser  Offline  Сообщение №1066 написано: 24 октября 2013, 18:20


Dr. Moreau


djsave, да не спешите вы. Это не срочно! Лучше отдохните после работы.

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
djsave  Offline  Сообщение №1067 написано: 24 октября 2013, 19:55


=TMG= TeamModingGames


505
В принципе я сделал. Но там просто перемещение и все. Если надо там эффект добавить или что еще сразу говори. добавлю.
Реализация простая, но работать будет на все 100% - глюков быть не может, там нечему просто глючить.
Сейчас скину плаг.

Добавлено (24 Октября 2013, 23:54)
---------------------------------------------
Вот собственно сам файлик.
скачать
В любом месте игры открываем консоль и набираем

Код
coc 1ARoomMain

Вас перенесет в комнату, где на стене в левом углу будет висеть терминал. В этом терминале необходимо выбрать комнату куда будете телепортироваться. Комнаты все похожи но названия в Пип-Бое у всех свои, тем самым можно удостовериться в правильном перемещении. Обратно в основную комнату можно вернуться только через код в консоле.

Добавлено (24 Октября 2013, 23:55)
---------------------------------------------
Hellraiser, проверяй то что надо или чего изменить нужно.


=TMG= Team Moding Games
Hellraiser  Offline  Сообщение №1068 написано: 24 октября 2013, 20:04 | Отредактировано: Hellraiser - 24 октября 2013, 20:45


Dr. Moreau


djsave, Cпасибо.

UPD

Работает как швейцарские часы! Как же всё просто и как я сам не допер сделать это через квест, вот я чайник... :(
Ещё раз спасибо, менять ничего не нужно - дальше сам доделаю. Мне было главное принцип понять.  good

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
djsave  Offline  Сообщение №1069 написано: 24 октября 2013, 20:31


=TMG= TeamModingGames


505
Ну и ладненько. Если что стучи. ;)

=TMG= Team Moding Games
Hellraiser  Offline  Сообщение №1070 написано: 24 октября 2013, 20:44


Dr. Moreau


djsave, обязательно.  :)

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
ross  Offline  Сообщение №1071 написано: 28 октября 2013, 16:16



25
люди, а как повесить скрипт на light, movable, static?

к примеру:
"Тип: объектный - так как "вешается" на объект "луковица" (лампочка) 

scn AAATestLampScript 

Begin GameMode 
If GetCurrentTime >= 21.00 || GetCurrentTime <= 10.00 
AAATestLampRef. Enable 
else 
GetCurrentTime >=10.00 || GetCurrentTime <= 21.00 
AAATestLampRef. Disable 
endif 
end
 "

ross  Offline  Сообщение №1072 написано: 28 октября 2013, 16:37



25
Galko, я всё прочитал, но "В нашем случае выключатель (активатор) не нужен. Нужен светильник, "луковица" (лампочка) и скрипт задающий временной интервал на включение и отключение лампочки." и "Скрипт "вешается" на любой объект, который можно активировать." противоречат же друг другу!
то есть скрипт в любом случае вешать на активатор и потом прятать его(если он, например работает в зависимости от времени)?

Добавлено (28 Октября 2013, 20:37)
---------------------------------------------
Galko, спасибо, опять меня невнимательность подводит.


Galko  Offline  Сообщение №1073 написано: 28 октября 2013, 16:38 | Отредактировано: Galko - 28 октября 2013, 16:39


GALAктическая мартышка


ross, луковица, как было сказано - это объект. На нее вешается объектный скрипт в том поле, что я указала на скриншоте.
В скрипте блок Begin GameMode
Это значит, что скрипт работает, когда происходит игровой режим. т.е. игрок находится в игре (не в паузе. не в меню) Пошла игра - работает скрипт и включает\выключает заскриптованный объект

Ваше счастье, что я не ваше счастье
KAIN48  Offline  Сообщение №1074 написано: 30 октября 2013, 11:12 | Отредактировано: KAIN48 - 30 октября 2013, 11:18


Шаманистый шаман


Привет всем!
Помогите пожалуйста разобраться с таким скриптом
Short doonce
Short button
Begin OnActivate
If ( doonce == 0 )
MessageBox "Вы видите.. и решили..." "Взять доспехи" "Уйти"
Set doonce  to 1
EndIf
End

Begin GameMode
if ( doonce == 1 )
set Button to GetButtonPressed
if ( button == 0 ); если нажата первая кнопка
Activate ; выполнить стандартное открытие контейнера
AAASkyrimBladesBarrelSkellRef.disable ; скрыл контейнер (сундук)
AAASkyrimSkellStaticRef.enable ; открыл статический скелет
elseif ( button == 1 ) ; иначе если нажата вторая кнопка
Set doonce  to 0 ; установить переменную в 0 что бы можно было открыть контейнер снова при выборе "Уйти", без открытия контейнера
endif
endif
endif
End

Скрипт работает как написан! То есть не так как нужно!
Выбираю первую кнопку - открывается контейнер. Если забрать всё и закрыть, то происходит подмена активатора на статику. Это нормально!
Но вот если ничего не брать, а просто закрыть, то происходит подмена на статическую модель. Игрок ничего не взял и повторить открытие и взять вещи если передумал, уже не может.
А нужно, что бы контейнер повторно открывался, но подмена на статику происходила только когда контейнер пустой (все вещи у игрока). 
Вещей 6
Иначе при закрытии игрок оставив шлем в контейнере увидит статику без шлема. Будет не достоверно!
Если можно

Я сам могу сделать простое добавление в инвентарь сразу всего содержимого, а как сделать повторную активацию, если в контейнере остались вещи не знаю.

Мы вышли из дома, когда во всех... Поздно вышли!
Hellraiser  Offline  Сообщение №1075 написано: 30 октября 2013, 11:40 | Отредактировано: Hellraiser - 30 октября 2013, 12:34


Dr. Moreau


KAIN48,
я бы создал дополнительный квест(такой-то) и написал такой объектный скрипт на контейнер:

short awaitingInput
short buttonVar

Begin OnActivate Player

if (GetStage квест.такой-то == 5)
MessageBox "Вы видите.. и решили..." "Взять доспехи" "Уйти"
set awaitingInput to 1

endif

end

begin gamemode

if awaitingInput == 1
set buttonVar to getbuttonpressed

if buttonVar > -1
set awaitingInput to 0

if ( buttonvar == 0 ); если нажата первая кнопка
Activate ; выполнить стандартное открытие контейнера
elseif ( buttonvar == 1 ) ; иначе если нажата вторая кнопка
SetStage квест.такой-то == 5; переходим на стадию квеста такого-то

endif
endif
endif
end

И еще нужно добавить блок проверки на наличие всех нужных предметов в инвентаре у ГГ и переходить на следующую стадию квеста, чтобы сундук больше не активировался и вставить туда твою строку на подмену AAASkyrimSkellStaticRef.enable, что-то типа этого:

begin gamemode

if player.GetItemCount a01 == 1 && player.GetItemCount a02 == 1 && player.GetItemCount a03 == 1 .... && player.GetItemCount a06 == 1 && (GetStage квест(такой-то)== 5)
SetStage квест.такой-то to 10
AAASkyrimBladesBarrelSkellRef.disable ; скрыл контейнер (сундук)
AAASkyrimSkellStaticRef.enable; открыл статическую модель
endif

end

UPD
Естественно, последний блок должен идти, как отдельный квестовый скрипт и висеть на твоем новом квесте.

Death is the old debt, which sooner or later will have to pay.
This is as good a day to die as any, but at your funeral nobody will come.
Your way in hell you'll have to do yourself... Happy journey!
Alright, guys, all will be there, but you before...
JupiterJour  Offline  Сообщение №1076 написано: 30 октября 2013, 12:24 | Отредактировано: Joopeeter - 30 октября 2013, 12:31


_


Цитата KAIN48

нужно, что бы контейнер повторно открывался, но подмена на статику происходила только когда контейнер пустой (все вещи у игрока).  Вещей 6



Код
if AAASkyrimBladesBarrelSkellRef.GetItemCount [Вещь 1]==0 && AAASkyrimBladesBarrelSkellRef.GetItemCount [Вещь 2]==0 && ...     
AAASkyrimBladesBarrelSkellRef.disable
     AAASkyrimSkellStaticRef.enable
endif

или перетащить все вещи в форм-лист (если в Обливионе есть форм-листы) и тогда

Код
if AAASkyrimBladesBarrelSkellRef.GetItemCount [форм-лист]==0
AAASkyrimBladesBarrelSkellRef.disable
     AAASkyrimSkellStaticRef.enable
endif


Добавлено (30 Октября 2013, 16:24)
---------------------------------------------
А, ещё. Надо бы вынести это из блока if ( button == 0 ). То есть в итоге:
Код
Begin GameMode
   if ( doonce == 1 )
    set Button to GetButtonPressed
    if ( button == 0 )
     Activate
    elseif ( button == 1 )
     Set doonce  to 0
    endif
    if AAASkyrimBladesBarrelSkellRef.GetItemCount [Вещь 1]==0 ...
     AAASkyrimBladesBarrelSkellRef.disable
     AAASkyrimSkellStaticRef.enable
     set DoOnce to -1
    endif
   endif
  End

KAIN48  Offline  Сообщение №1077 написано: 30 октября 2013, 12:50 | Отредактировано: KAIN48 - 30 октября 2013, 12:51


Шаманистый шаман


Hellraiser, Joopeeter спасибо!
Мне больше подходит вариант Joopeeter - он проще, но и вариант Hellraiser не отбрасывается!
Квест будет чуть позже, и из предложенного Hellraiser часть решений будет задействована.
Я пока отдал мод для теста шмоток, двум любителям Обливион и отдал с неправильным скриптом.
Один уже отписался, что всё здорово! Видимо забрал все шмотки сразу.
Второй пока молчит! Всё таки тестировать нужно иметь особый склад характера!
Я уже писал, как в тесте магазина, с разложенным на прилавках оружием - человек выстрелил из "Толстяка" и всё оружие улетело под столы!
Пришлось делать оружие на столах активаторами, скрывать при взятии с прилавка, добавлять в инвентарь, экипировать.
Потом ещё раз заменять изношенное после пристрелки в тире, на новое и только потом покупка!
Вот так одним выстрелом тестер - всё простое, сделал сложным!
Ещё раз спасибо! Наверное только завтра попробую скрипт Joopeeter - сегодня хочу помочь человеку сделать плеер (радио) из "Вопросов по Моддингу".
Есть скрипт IgorRa для Обливион


Попробую! Вдруг в FalloutNV это тоже работает.
Правда есть ещё функция PlaySoundSoundID. Попробую и то и то. Самому интересно!
Если есть желание подсказывайте там чуть позже - я по быстрому создам элемент брони плеер, при экипировки которого будет выводится сообщение с выбором mp3 файлов из Data.
Не знаю получиться или нет!

Мы вышли из дома, когда во всех... Поздно вышли!
djsave  Offline  Сообщение №1078 написано: 30 октября 2013, 13:51


=TMG= TeamModingGames


505
ЭЭЭЭЭЭ ..... а не проще ли музыку через радио сделать ? Ведь там можно много чего напихать. Да и вообще....

=TMG= Team Moding Games
KAIN48  Offline  Сообщение №1079 написано: 30 октября 2013, 13:57


Шаманистый шаман


djsave привет!
Да! Скорее всего придётся делать как радиостанцию, с квестом и тп.
Но вдруг сработает скриптовое решение - запускать mp3 файлы функцией.

Мы вышли из дома, когда во всех... Поздно вышли!
djsave  Offline  Сообщение №1080 написано: 30 октября 2013, 14:06


=TMG= TeamModingGames


505
есть такая функция как PlaySound, но ей можно запускать только музыку прописанную в ГЕКК, опять же кто мешает прописать ее как Трэк1, Трэк1+n ... и потом там есть возможность указать даже не сам файл а только папку с файлами. Вообще это довольно обширная тема и все зависит от конкретной задачи.
Там человек насколько я понял хочет приемник который можно поставить где необходимо и он - приемник должен играть там где стоит, а не когда его носят, тут задачка немного другая. Есть мысля как это сделать, но образная. надо проверить это на деле.

=TMG= Team Moding Games
Форум » Fallout: New Vegas » Мастерская » Скрипты (Вопросы и ответы)
Поиск:





Ответ на жалобу смотрите в разделе жалоб