Модостроение. Редактирование и создание скриптов
|
|
denis2000 | Дата: Пн, 10.10.2011, 21:17 | Сообщение # 1 |
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
| Редактирование и создание скриптов Редактирование и создание скриптов на языке LUA Если у вас появились вопросы по применению скриптов в игре. Задавайте их в этой теме - умные головы, модосторители и просто разбирающиеся в программировании люди вам ответят.
Много интересного материала здесь (wiki), Lua_help.script, Help из SDK 0.7
Сборник модостроения ЗП v10.10.11 (автор: XOBAH): *.CHM, *.HTML [cut noguest=Если у вас не открывается файл CHM]Если у вас не открывается файл: 1. Запустите [Пуск]=>[Выполнить] (либо хот-кей [WIN]+[R]) 2. Введите команду (без кавычек) "regsvr32 %windir%\system32\hhctrl.ocx" 3. Если вылезло окно об успешном завершении вы все сделали правильно и можете перезагружать компьютер (а может и не надо) Также: файлы МОГУТ не открываться если в пути к файлу есть: символы кириллицы, "_", "#" Также: есть не стандартные программы-просмоторщики CHM файлов. Например: FBReader[/cut]
[cut=Где найти лог игры после вылета]Что такое LOG ошибки, и как мне его найти? Это система отладки происходивших вылетов, которая подается игрой в форме текста, хотя не всегда. Для того чтоб найти LOG необходимо зайти вот сюда:
В Win хр лог находится:
C:\Documents and Settings\All Users\Документы\S.T.A.L.K.E.R. - Зов Припяти\logs
Затем открываете первый файл в формате TXT, и в нем отбираете с низу 25 строчек. После кидаете эти 25 строчек в сообщение на форум.
В Win7 лог находится C:\Users\Public\Documents\S.T.A.L.K.E.R. - Зов Припяти\logs
Путь к папке с логом можно найти открыв файл fsgame.ltx который находится в корневой директории ЗП, за это отвечает строка: ... $app_data_root$ = true | false| $fs_root$| users\(тут мы указываем что папка пользователя, будет хранится рядом с Fsgame.ltx) ... $logs$ = true| false| $app_data_root$| logs\(а тут мы указываем что в папке пользователя, в подпапке Logs будут храниться наши логи) ... [/cut][cut=Получение более подробной информации о вылете (ХОВАН)] Открываем файл _g.script и ищем такую функцию: function abort(fmt, ...) Там есть заккомментированная строчка "--error_log(reason)", ее и надо расскомментировать, должно получиться вот так: Code function abort(fmt, ...) local reason = string.format(fmt, ...) error_log(reason) end Вот для примера два одинаковых вылета, первый с функцией по умолчанию, второй - с поправленной функцией
Первый: Code Expression : !m_error_code Function : raii_guard::~raii_guard File : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp Line : 748 Description : ....a.l.k.e.r. - Зов Припяти\gamedata\scripts\_g.script:478: bad argument #2 to 'format' (string expected, got nil) Второй: Code Expression : 0 Function : ErrorLog File : D:\prog_repository\sources\trunk\xrServerEntities\script_engine_script.cpp Line : 49 Description : 'Attempt to read a non-existant string field 'path_walk' in section 'walker@mechanic' [/cut]
Перед тем, как задать вопрос в этой теме, прочтите все предыдущие страницы, статьи в wiki по ссылке из шапки и соседнюю тему "Курс молодого бойца", возможно Ваш вопрос уже рассматривался.
Если произошел вылет - выкладываем лог! Вопрос ставим четко, не забываем указывать версию игры, установленные моды их версии, установленные фиксы модов и подробно ваши правки. Помните чем подробнее вопрос, тем точнее ответ.
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
|
|
|
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение: |
|
|
stalex | Дата: Вт, 31.01.2012, 17:15 | Сообщение # 46 |
Гражданский
Пользователи
Сообщений: 15
| Не пашет Может я что-то не правильно сделал? Вызвал функцию через диалог.
Code function set_spot_choose_dok_chert(dokuments_chertezh,zaton,show,zat_b30_owl_stalker_vovka_small_quest_title_1) if type=="hide" and obj_id~=nil then remove_spot_on_map(dokuments_chertezh,zaton) elseif type=="show" and obj_id~=nil then add_spot_on_map(dokuments_chertezh,zaton,zat_b30_owl_stalker_vovka_small_quest_title_1) end end
В функциях диалогов не передаются аргументы (dokuments_chertezh,zaton,show,zat_b30_owl_stalker_vovka_small_quest_title_1), поэтому Ваша писанина ни к чему хорошему не приведет. Передавать параметры в функциях (add|remove)_spot_map следует в кавычках! XOBAH
XOBAH а можешь наглядный пример сделать как правильно?
А может вы зря с этим связались? Если вы делаете указатель на квестовый предмет то делайте через параметр target своего квеста. denis2000
Не получается через target. Вот пишу квест, метка ни на объект ни на НПС не ставится.
[cut noguest=Квест][zat_b30_owl_quest_vovka] icon = ui_inGame2_Sdelka prior = 2 storyline = false title = {=actor_has_item(dokuments_chertezh) =actor_has_item(dokuments_plan)} zat_b30_owl_stalker_vovka_small_quest_title_3, {=actor_has_item(dokuments_chertezh) !actor_has_item(dokuments_plan)} zat_b30_owl_stalker_vovka_small_quest_title_2, {!actor_has_item(dokuments_chertezh) =actor_has_item(dokuments_plan)} zat_b30_owl_stalker_vovka_small_quest_title_1, zat_b30_owl_stalker_vovka_small_quest_title_0 descr = {=actor_has_item(dokuments_chertezh) =actor_has_item(dokuments_plan)} zat_b30_owl_stalker_vovka_small_quest_text_3, {=actor_has_item(dokuments_chertezh) !actor_has_item(dokuments_plan)} zat_b30_owl_stalker_vovka_small_quest_text_2, {!actor_has_item(dokuments_chertezh) =actor_has_item(dokuments_plan)} zat_b30_owl_stalker_vovka_small_quest_text_1, zat_b30_owl_stalker_vovka_small_quest_text_0 target = {=actor_has_item(dokuments_chertezh) =actor_has_item(dokuments_plan)} vovka_id, {+zat_b30_owl_stalker_vovka_quest_init} dokuments_chertezh condlist_0 = {+zat_b30_owl_stalker_vovka_quest_end} complete[/cut]
Сообщение отредактировал stalex - Ср, 01.02.2012, 13:25 |
|
|
Эти 0 пользователя(ей) поблагодарили stalex за это полезное сообщение: |
|
|
denis2000 | Дата: Ср, 01.02.2012, 14:31 | Сообщение # 47 |
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
| stalex, А ты в курсе, что параметр target - это story_id предмета/НПС?
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
|
|
|
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение: |
|
|
stalex | Дата: Ср, 01.02.2012, 16:12 | Сообщение # 48 |
Гражданский
Пользователи
Сообщений: 15
| denis2000, разобрался, надо было в объекте story_id прописать.
Сообщение отредактировал stalex - Ср, 01.02.2012, 16:44 |
|
|
Эти 0 пользователя(ей) поблагодарили stalex за это полезное сообщение: |
|
|
maxibon | Дата: Сб, 11.02.2012, 13:41 | Сообщение # 49 |
Отмычка
Пользователи
Сообщений: 36
| доброе время суток. как не банально - нужна помощь. у меня сталкер ЗП, с сигероуз мод 2.0 плюс адон сверху. а проблемма такая - в лаборатории под железным лесом лежат документы о изделии 62 и их надо найти только после разговора с ковальским в припяти. но я зашел туда еще задолго до перехода в припять. доки на руках, кардан хочет о них поговорить (диалог появился). я не говорил, понимая что это должно быть позже. и вот я пришел в припять, вышел из путепровода - и тут же начинается диалог с ковальским. после основного разговора появляется задание - рассказать о неизвестном оружие. и других квестов нельзя получить. соотвественно логика квестов поломалась. я пытался выкинуть эти документы из рюкзака (изменил файл в папке гэймдата) перед разговором с ним, но это не помогло. на этом форуме мне сказали что сработал скрипт (при взятии этих доков). у меня появилась идея изменить скрипт этот. я так понял скрипты эти находятся в папке с игрой, я их нашел. так же скачал прогу (IRScriptEditor) которая открывает скрипты. но я не знаю какой именно скрипт нужен и что в нем менять. помогите пожалуйста, а то советы переигрывать с начала для меня совершенно не подходят. (скопировал свой (этот) пост с соседней темы, а то вдруг там не туда ниписал.)
AMD Athlon II X4 631 Quad-core Processor 2.60 Ghz, ОЗУ - 8 ГБ, GeForce GTX 650 2 ГБ, Windows 7 64bit
|
|
|
Эти 0 пользователя(ей) поблагодарили maxibon за это полезное сообщение: |
|
|
denis2000 | Дата: Сб, 11.02.2012, 17:50 | Сообщение # 50 |
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
| maxibon, Перед заходом на локацию Припять удали документы из инвентаря: [cut] Открываем файл scripts\ui_main_menu.script
Ищем:
Code elseif db.actor~=nil and dik==DIK_keys.DIK_F5 then self:mod_options()
добавляем ниже:
Code elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then check_actor_item_to_remove("zat_a23_gauss_rifle_docs") В игре жмем ESC=>F6=>ESC Предмет удален. [/cut] , после разговора с Карданом верни: [cut]Открываем файл scripts\ui_main_menu.script после уже добавленного пишешь:
Code elseif db.actor~=nil and dik==DIK_keys.DIK_F7 then give_object_to_actor("zat_a23_gauss_rifle_docs") В игре жмем ESC=>F7=>ESC и у нас в рюкзаке будет лежать Предмет. [/cut]
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
|
|
|
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение: |
|
|
maxibon | Дата: Вт, 14.02.2012, 07:57 | Сообщение # 51 |
Отмычка
Пользователи
Сообщений: 36
| denis2000, это конешно здорово. но давай те по порядку - я выкидывал все доки сто у меня были, но диалог с ковальским не менялся. что с ними что без. соответсвенно он меня пошлет к кардану и т.д. и тем самым я выполню квест скорее всего. но дальше что? я не знаю. вдруг предшествующие квесты пропадут. если я что то не понял, обьясните плиз.
Если расклад такой то только быстрее будет переиграть, причем даже с новой игры, чем лечить канитель с инфопорциями. denis2000
Добавлено (11.02.2012, 18:21) --------------------------------------------- denis2000, ну я токо что проверил - выкинул док по твоему коду, говорю с ковальским, тут же в диалогах появляется надпись "рассказать о неизвестном оружии". когда с ним говоришь - задание выполенно и все. больше он ничего не говорит. ну должен же быть вариат какой то.
Свои предложения я высказал выше, если у кого-то есть другие то он их озвучит. denis2000Добавлено (13.02.2012, 06:34) --------------------------------------------- denis2000, надеюсь "другие" зайдут сюда. не удаляй посты мои плиз. а то в топе помощи сигероуз токо так удаляют все подряд. Добавлено (14.02.2012, 07:57) --------------------------------------------- вроде нашел решение - кавальский же сразу дает это же задание (я думал что этим сообщением мы его завершили(ну так и написано было)) - соответственно идем вниз к группе и выносим монолит, забираем гауску сломанную, и дальше по цепочке квесты идут.
AMD Athlon II X4 631 Quad-core Processor 2.60 Ghz, ОЗУ - 8 ГБ, GeForce GTX 650 2 ГБ, Windows 7 64bit
|
|
|
Эти 0 пользователя(ей) поблагодарили maxibon за это полезное сообщение: |
|
|
InvuL | Дата: Ср, 22.02.2012, 18:24 | Сообщение # 52 |
Отмычка
Пользователи
Сообщений: 25
| Люди помоги плиз, я это вопрос уже задавал, но найти уже не могу Stalker CoP 1.6.02 + SGM 2.1 + NO BUMP v1.0 ну так вот вопрос: Я сделал так что бы сквады отображались в ПДА ну и при наводе на них курсором появляется пустое окошко, т.е. там должно быть написано кому принадлежит этот сквад(бандиты, сталкеры и т.д.), ну и куда он направляется, вот как это исправить, а то я забыл.
|
|
|
Эти 0 пользователя(ей) поблагодарили InvuL за это полезное сообщение: |
|
|
denis2000 | Дата: Ср, 22.02.2012, 22:16 | Сообщение # 53 |
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
| InvuL, Для того чтобы в хинте сквада отображалась информация нужно в скрипте sim_squad_scripted.script в функции sim_squad_scripted:get_squad_props() сделать переменную dev_debug равной true. Однако при этом будет выводиться отладочная информация о скваде. Для того чтобы там выводилась нужная тебе - скрипт нужно переписать, для примера можно взять аналогичную функцию из ЧН и на базе нее сделать свою.
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
|
|
|
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение: |
|
|
Lazur | Дата: Пн, 19.03.2012, 10:01 | Сообщение # 54 |
Новичок
Пользователи
Сообщений: 82
| Здравствуйте головы просветлённые. Назрел вопрос: "Как создать скрипт, что если ГГ обыскивает NPC, то есть вероятность, что он(ГГ) найдёт наводку на тайник?" Попробовал сделать на основе урока по "сдиранию" денег с трупов, но опыта нет, решил посоветоваться. Заранее спасибо!
Выдача случайного тайника функция - treasure_manager.get_treasure_manager():give_random(). denis2000
Благодарю, попробую...
На пыльных тропинках аномальных полей Заспавнятся наши следы...
Сообщение отредактировал Lazur - Пн, 19.03.2012, 11:37 |
|
|
Эти 0 пользователя(ей) поблагодарили Lazur за это полезное сообщение: |
|
|
Михалыч_с_ПК | Дата: Сб, 24.03.2012, 05:09 | Сообщение # 55 |
Удаленные
| Здравствуйте уважаемые. Просветите пожалуйста "свеженького", как влезть в логику обработки действий пользователя на уровне "объект в фокусе", "объект выбран", "нажата клавиша Х". Очень хочется доработать интерфейс на предмет расширения действий в выпадающих меню (по ПКМ при работе с инвентарём) и в подсказках (при выборе "тела"). Честно пытался найти описание взаимодействия движок-скрипты (объект = движок, свойства и методы), но увы, вынужден грузить Вас. Заранее спасибо.
AMK Team > S.T.A.L.K.E.R. > Школа моддинга > Справочник по функциям и классам. denis2000
|
|
|
Эти 0 пользователя(ей) поблагодарили Михалыч_с_ПК за это полезное сообщение: |
|
|
InvuL | Дата: Сб, 31.03.2012, 17:44 | Сообщение # 56 |
Отмычка
Пользователи
Сообщений: 25
| Niafa, Я прописал в файле ui_main_menu.script: [cut] Code elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then local p=vector(),lv,gv p.x=db.actor:position().x+3 p.y=db.actor:position().y p.z=db.actor:position().z lv=db.actor:level_vertex_id() gv=db.actor:game_vertex_id() math.random(5) if math.random() == 1 alife():create("zat_stalker_elbrus_friend1",p,lv,gv) elseif math.random() == 2 alife():create("zat_stalker_elbrus_friend2",p,lv,gv) elseif math.random() == 3 alife():create("zat_stalker_elbrus_friend3",p,lv,gv) elseif math.random() == 4 alife():create("zat_stalker_elbrus_friend4",p,lv,gv) elseif math.random() == 5 alife():create("zat_stalker_elbrus_friend5",p,lv,gv) [/cut] И получаю вылет без лога при попытке зайти в игру. А поставил вот так: [cut] Code elseif db.actor~=nil and dik==DIK_keys.DIK_F6 then local p=vector(),lv,gv p.x=db.actor:position().x+3 p.y=db.actor:position().y p.z=db.actor:position().z lv=db.actor:level_vertex_id() gv=db.actor:game_vertex_id() math.random(5) alife():create("zat_stalker_elbrus_friend5",p,lv,gv) [/cut] И всё нормально, сталкер спавнится.И как я думаю это из-за не правильного условия
Сообщение отредактировал InvuL - Сб, 31.03.2012, 18:13 |
|
|
Эти 0 пользователя(ей) поблагодарили InvuL за это полезное сообщение: |
|
|
denis2000 | Дата: Сб, 31.03.2012, 19:30 | Сообщение # 57 |
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
| InvuL, if условие_1 then действие_1 elseif условие_2 then действие_2 elseif условие_3 then действие_3 else действие_при_невыполнении_ни_одного_ из_условий end
if, then, end - обязательны!!!
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
|
|
|
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение: |
|
|
InvuL | Дата: Вс, 01.04.2012, 10:05 | Сообщение # 58 |
Отмычка
Пользователи
Сообщений: 25
| А как сделать так, точнее что написать надо после else, что бы ничего не происходило?
Неписать само else. Доп. информация по ветвлению. XOBAH
И ещё вопрос: Я в файле sim_squad_scripted.script добавил пару строк и закоментил другие: [cut] Code function sim_squad_scripted:show() if self.show_disabled then self:hide() return end
if(level.map_has_object_spot(self:commander_id(), "ui_pda2_trader_location")~=0) or (level.map_has_object_spot(self:commander_id(), "ui_pda2_mechanic_location")~=0) or (level.map_has_object_spot(self:commander_id(), "ui_pda2_scout_location")~=0) or (level.map_has_object_spot(self:commander_id(), "ui_pda2_quest_npc_location")~=0) or (level.map_has_object_spot(self:commander_id(), "ui_pda2_medic_location")~=0) then self.show_disabled = true return end
if self.current_spot_id ~= self:commander_id() then self:hide() self.current_spot_id = self:commander_id() self:show() return end local spot = ""
if not(is_squad_monster[self.player_id]) then local relation = game_relations.get_squad_relation_to_actor_by_id(self.id) if(relation=="friends") then spot = "alife_presentation_squad_friend" elseif(relation=="neutral") then spot = "alife_presentation_squad_neutral" elseif(relation=="enemy") then <--- spot = "alife_presentation_squad_enemy" <--- Вот эти две добавил. end end if(spot~="") then if spot == self.spot_section then level.map_change_spot_hint(self.current_spot_id, self.spot_section, self:get_squad_props()) return end if self.spot_section == nil then level.map_add_object_spot(self.current_spot_id, spot, self:get_squad_props()) else --' level.map_remove_object_spot(self.current_spot_id, self.spot_section) <--- Вот эту строку закоментил. level.map_add_object_spot(self.current_spot_id, spot, self:get_squad_props()) end self.spot_section = spot elseif(self.spot_section~=nil) then level.map_remove_object_spot(self.current_spot_id, self.spot_section) self.spot_section = nil end end [/cut] Что я получил: у меня в ПДА теперь отображаются все отряды, все даже на других локациях, прописал что бы показывалось из какой они группировки, даже поставил что бы показывало не только командиров отряда, а и обычных сталкеров, но у меня они в ПДА помечены все как враги, т.е. друзья, нейтралы, и враги они в ПДА отображаются все красным, хотя в файле map_spots.xml и map_spots_16.xml стоят нормальные цвета. И если убираю мною добавленные строчки, то сталкеры в ПДА отображаются не по всей зоне, а только как раньше.
Сообщение отредактировал InvuL - Пн, 02.04.2012, 11:15 |
|
|
Эти 0 пользователя(ей) поблагодарили InvuL за это полезное сообщение: |
|
|
IAmS | Дата: Пн, 02.04.2012, 14:19 | Сообщение # 59 |
Гражданский
Пользователи
Сообщений: 10
| Вопросик по адаптации. Пытаюсь прикрутить Atmosfear3 к SGM22. Все вроде получилось, но только на новой игре. При попытке загрузки сейва без AF3 ругается:
[cut=лог]FATAL ERROR
[error]Expression : !m_error_code [error]Function : raii_guard::~raii_guard [error]File : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp [error]Line : 748 [error]Description : ...mes\stalker_cop\gamedata\scripts\bind_stalker.script:20: attempt to index global 'level_weathers' (a nil value)[/cut]
Соответственно убираю "level_weathers.script" - часть AF3, все грузится нормально но погода, ессно, не меняется. Я так понял, что в старых сейвах нет инфы о новом (атмосферном) состоянии погоды. Если это так, можно каким-то образом явно указать в скрипте состояние погоды, если не находит правильного?
P.S. может быть уже кто-то сделал эту адаптацию? Поделитесь, пожалуйста, уж очень хочется красот погодных...
В скрипт level_weathers.script затесалась ошибка синтаксиса, вот и ругань. denis2000
Спасибо, denis2000, но с новой игрой - всё работает на ура (проверял с ускорением времени - прикольно (тени бегают, солнце и луна на местах, небо меняется)) да и в скрипте ничего не менял - как есть из AF3. Может есть еще какой-то вариант?
Погоди не понял, ты с адаптацией Атмосфера 3 пытаешся грузить сейв из чистого SGM2.2? Брось неблагодарное занятие, начинай новую игру и вперед. denis2000
Так точно, из чистого SGM22. Да, с новой игрой всё ОК. Значит, как я понял, в скрипте этом - level_weathers.script поправить ничего не удасться для проверки состояния погоды (с AF3 / без AF3) в загружаемом сейве и явного указания какого-то состояния (из возможных в AF3)? Переигрывать - не очень вариант.
Вполне вероятно, что запустить не получиться, к стати а что в 10-30 строке bind_stalker.script. denis2000
[cut=bind_stalker.script (строки 15-45)] ------------------------------------> class "actor_binder" (object_binder) ------------------------------------> function actor_binder:__init (obj) super(obj) self.bCheckStart = false self.weather_manager = level_weathers.get_weather_manager() self.surge_manager = surge_manager.get_surge_manager() self.last_level_name = nil self.deimos_intensity = nil self.loaded_active_slot = 3 self.loaded_slot_applied = false self.last_detective_achievement_spawn_time = nil self.last_mutant_hunter_achievement_spawn_time = nil end ------------------------------------> function actor_binder:net_spawn(data) level.show_indicators() self.bCheckStart = true self.weapon_hide = false self.weapon_hide_in_dialog = false weapon_hide = {} if object_binder.net_spawn(self,data) == false then return false end db.add_actor(self.object) db.actor.deimos_intensity = self.deimos_intensity self.deimos_intensity = nil if self.st.disable_input_time == nil then level.enable_input() end xr_s.on_game_load() [/cut]
Ошибочка по логу в этой строке: self.weather_manager = level_weathers.get_weather_manager()
[cut=А вот функция из level_weathers.script] function get_weather_manager () if weather_manager == nil then weather_manager = WeatherManager() end return weather_manager end [/cut]
Почему то подозрение на: function WeatherManager:set_state_as_string(ss) (в комменте написано - <<-- Устанавливаем состояние менеджера, распарсивая строку состояния>>)
Все понятно - новая игра обязательна! denis2000
Спасибо, denis2000, а жаль....
Сообщение отредактировал IAmS - Вт, 03.04.2012, 20:00 |
|
|
Эти 0 пользователя(ей) поблагодарили IAmS за это полезное сообщение: |
|
|
denis2000 | Дата: Пн, 02.04.2012, 15:40 | Сообщение # 60 |
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
| InvuL, В файле game_relations.script в функции get_squad_relation_to_actor_by_id в самом конце вместо ставь Code return get_squad_goodwill_to_actor_by_id(squad_id)
"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..." (Чугунный всадник)
|
|
|
Эти 0 пользователя(ей) поблагодарили denis2000 за это полезное сообщение: |
|
|
|