Название: Создание квестов L2j_Mobius [Версия для печати] Автор: admin Время: 2024-9-24 00:52 Название: Создание квестов L2j_Mobius Сборка: L2l_Monius % H8 g) b6 _+ E. D0 M H r( ~
Следующие квесты можно использовать в качестве шаблонов для создания практически любого простого квеста go kill или go talk. ( t' C' K& B D1 g ' j. N! v, Z) L/ m( r, ^& S & f/ ?8 V: k$ r1 b& j; iИди и убей X монстров / Возвращение - награда.7 P0 J9 B; |0 C4 D
Q00529_RegularBarrierMaintenance6 D1 W1 s2 d0 N* W* \
\0 m: z: ~8 X4 |
Получите квест от любого из двух разных NPC / Убейте X монстров / Вернитесь с наградой.3 M( n' `8 f, ^ k( K( j
Q00683_AdventOfKrofinSubspecies ! ?9 S% g4 m: t/ _7 T9 B6 O ) z" @( u3 r3 m4 r( ?Поговори с NPC 1 / Поговори с NPC 2 / Поговори с завершающим NPC / Награда.9 ^5 @! J4 Y0 S5 f: L9 M! R& y
Q10516_UnveiledFafurionTemple , n n& q, B0 @7 x! N7 }: A0 L8 e9 a: e+ h3 j9 A4 }6 n
Убейте X монстров, а также соберите X предметов / Возврат - награда. # _* C. v+ ^, i1 M# A! \. J5 }Q10517_FafurionsMinions / n4 W! E4 H. g . r' J+ l) p/ q7 {) M% sИди собери X капель монстров / Вернись - убей X монстров / Вернись - награда.( m5 J( S" }, Z0 q/ H) o0 S
Q10529_IvoryTowersResearchFloatingSeaJournal5 Z! i* W" N' A! X, N/ U& S
- f% O3 g5 O- w/ r* o
Иди убей X монстров, а также собери X предметов / Возвращение - иди собери X предметов / Возвращение - награда.% C" C( h0 ]& h6 [2 `
Q10518_SucceedingThePriestess, X, ?5 `7 |4 a8 |* T& \+ `0 ^
; F$ n! n+ N( c4 P! K7 h i
Участвуйте в убийстве рейдбосса / Возврат - награда. * }+ j2 a. c- w) X+ ]Q10519_контролирование вашей температуры $ @; ` W4 b, E8 n$ y8 R7 z8 }& v4 }
Поговорите с NPC 1 / Примите участие в убийстве рейдбосса / Возвращение - награда.- `) u0 @) m6 {2 E8 t1 `8 ^
Q10533_OrfensAmbition" q) [, `+ Q/ Z2 d
' @) e: q' g( T) C9 W : z1 u& R4 p4 y; g) Y4 T 6 c; A' U' l, ?% g' ^" |4 d |Руководство требует обновления. И, к сожалению, с самыми последними хрониками вы не сможете избежать модификаций клиента. Поэтому, исключительно в образовательных целях, я предлагаю свой опыт по добавлению нового квеста! / ^+ G Q2 R5 Q. ]2 i/ E0 Q8 Y9 a/ g+ v" W
Шаг 1: Создайте свой квест с уникальным ID. В этом примере я буду ссылаться на квест как "Q98765_NewQuest".# t t' f3 E: P# R) D
! g# U3 e6 G8 y Шаг 2: Когда вы успешно создали свой квест и Eclipse не выдает ошибок, добавьте название квеста и импортируйте его в файл "QuestMasterHandler.java". 1 Z7 A4 _' e! s) A! h; {3 V" W& S1 C! |! F6 L6 i, f: d r! ? Шаг 3: Перейдите в клиент и с помощью редактора клиента добавьте квест в следующие файлы .dat: "questname-ru.dat" и "QuestMarkConditionData.dat". ) z7 x2 q! ?. S0 J6 P, n8 I4 T % @% T1 J1 r) k$ c8 `4 oСледующие шаги относятся к любым новым хроникам, которые используют всплывающие окна квестов. 8 n5 R) p9 e( k8 |5 S: |/ M! E& |/ _6 q$ m5 J v) W Шаг 4: Найдите в серверных файлах файл с названием "NewQuestData.xml" и добавьте туда свой квест. / S" t& ]( i/ k# z. _1 A + W$ w3 f2 V+ [, y$ u6 w; `: gШаг 5: Найдите в клиенте следующие файлы и добавьте туда свой квест: "NewQuestData-ru.dat", "NewQuestDialog-ru.dat" и "NewQuestNpcPortrait.dat". - z, R6 M/ E9 D! @4 ?+ a& ^3 X: M" i( w
Если я что-то забыл, не стесняйтесь исправить меня. Это руководство создано исключительно в образовательных целях. / D( v8 H. E" j7 j& i* d ( h5 C, Q, J5 tШаг 2: * T2 s. h/ z( R* k& n& a" R# @% K7 f$ g& i* v: ]1 c! W
Следующий шаг заключается в добавлении вашего квеста в QuestMasterHandler.java. Вот общий план:9 O8 H5 C$ N0 z- j& w
/ b: J) h l; @: p3 D. V& |1. Импорт вашего квеста: В начале файла после всех существующих импортов добавьте строку, которая будет импортировать ваш квест. " e1 O# u" @! n' ^% O: M1 O6 o
Например:9 o! H% l! Y1 f# m; k( y. G
* _* s9 v; x6 @+ U6 E3 M
1. Регистрация квеста: Найдите метод, который отвечает за регистрацию всех квестов. Обычно это делается в статическом блоке или методе init, где происходит инициализация квестов. В этом блоке добавьте строку, которая будет регистрировать ваш квест:* W, x, f8 n1 j% C- b5 c6 v& N: f
l. ^5 E, t& u# F* n; `
/** O/ ]. R9 O* C. J( q
* @author NosBit2 b+ G4 q8 ]$ r I7 f0 \+ q
*/ \* ^2 W: w# n+ R+ o" l
public class QuestMasterHandler+ n$ X# E& \, v% p
{$ O! d/ t6 F! d; Z C
private static final Logger LOGGER = Logger.getLogger(QuestMasterHandler.class.getName()); / h# P/ ]3 M% A0 N9 f: j' S; }2 e7 T0 s. M
% C* Q/ X S1 ?) n, }- M
private static final Class<?>[] QUESTS =$ D3 L3 O9 [1 r/ i1 P4 p
{
Скопировать код
Проверка: Убедитесь, что идентификатор вашего квеста (в данном случае Q98765_NewQuest.class) уникален и не конфликтует с уже существующими квестами.& E; J1 }# m! c# J
* X5 x; |' H: a. |0 x& x6 ?
9 K X, K4 p0 ?$ zШаг 3:2 l3 K9 q/ x0 G+ r
! `7 Y/ P" i/ _6 \7 mФайл QuestName-ru.dat используется для описания квестов и содержит различные параметры, которые задают характеристики квеста, его цели, награды, ограничения и т.д. # R9 R' E. y3 n( D z& iДавайте разберем все поля на основе примера:; ~9 p; q# k' U7 \1 [2 U8 |0 G( ~
! w, D. i+ a/ L+ \
quest_begin tag=1 id=10811 level=1 title=[Узнай свой предел] sub_name=[Бремя силы] desc=[Если готовы, то еще раз поговорите с Рыцарем-Хранителем Евы Леонелом Хантером в Хейне.\n] goal_id={} goal_type={} goal_num={} target_loc={111382.0;220905.0;-3544.0} add_target_locs={} q_level={} lvl_min=100 lvl_max=0 journal_disp=3 entity_name=[Рыцарь-Хранитель Евы Леонел Хантер] get_item_in_quest=0 unk1=1 unk2=1 start_npc_id={33907} start_npc_loc={111382.0;220905.0;-3544.0} q_requirement=[Дворянин] quest_intro=[Рыцарь-Хранитель Евы Леонел Хантер из Хейна посоветовал прийти к нему, если Вы желаете узнать предел Ваших возможностей...] class_limit={} have_item={} clan_pet_quest=1 cleared_quest=1 mark_type=-1 category_id=0 priority_level=0 search_zoneid=121 iscategory=3 reward_id={45922;15625} reward_num={1;0} pre_level={0} faction_id=0 faction_level_min=0 faction_level_max=0 quest_end* T1 b! }3 o5 m0 d2 `3 |: L
Скопировать код
Поля данных:
quest_begin — начало записи для квеста.
tag — идентификатор типа данных. Может использоваться для группировки квестов или идентификации квестов по определённым категориям.
id — уникальный идентификатор квеста. Должен быть уникален для каждого квеста.
level — уровень сложности квеста. Используется для группировки и показа квестов, подходящих по уровню.
title — название квеста, которое отображается в интерфейсе. Заключено в квадратные скобки.
sub_name — подзаголовок квеста, используется для дополнительного описания. Заключен в квадратные скобки.
desc — описание квеста, которое появляется при его принятии или выполнении. Здесь также используется разметка с символами переноса строки (\n).
goal_id — идентификатор цели квеста. Может содержать ID объекта или персонажа, который нужно достичь.
goal_type — тип цели. Указывает, какого типа задача ставится перед игроком (например, убить монстров, собрать предметы).
goal_num — количество необходимых действий для завершения цели. Например, количество монстров для убийства или предметов для сбора.
target_loc — координаты (X, Y, Z), куда должен отправиться игрок для выполнения задачи. Координаты указываются в формате {X;Y;Z}.
add_target_locs — дополнительные целевые локации, если квест предполагает несколько мест назначения.
q_level — уровень сложности или рекомендованный уровень для выполнения квеста.
lvl_min — минимальный уровень персонажа, с которого квест доступен.
lvl_max — максимальный уровень персонажа для выполнения квеста. Если не указан, то квест доступен на любом уровне выше минимального.
journal_disp — параметр, определяющий отображение квеста в журнале квестов (например, на каком этапе он должен отображаться).
entity_name — имя NPC или объекта, который связан с выполнением квеста (например, кто выдаёт квест или с кем нужно взаимодействовать).
get_item_in_quest — указывает, должен ли игрок получать предметы в ходе выполнения квеста. 0 — нет, 1 — да.
unk1 — неизвестное поле, возможно зарезервировано для будущих функций или модификаций.
unk2 — аналогично, поле с неизвестным назначением.
start_npc_id — ID NPC, который выдаёт квест. ID указан в фигурных скобках {}.
start_npc_loc — координаты NPC, который выдаёт квест. Используется формат {X;Y;Z}.
q_requirement — дополнительные требования к выполнению квеста, например, наличие определённого статуса или ранга (например, "Дворянин").
quest_intro — вводное описание квеста, которое отображается при первом контакте с NPC.
class_limit — ограничения по классам персонажа. Указываются ID классов, которым доступен квест.
have_item — список предметов, которые должны быть у игрока для выполнения квеста.
clan_pet_quest — указывает, является ли квест клановым или петом. 1 — да, 0 — нет.
cleared_quest — указывает, выполнен ли квест или нет. 1 — выполнен, 0 — не выполнен.
mark_type — тип метки, связанной с квестом. Используется для отображения различных иконок или маркеров на карте.
category_id — ID категории, к которой относится квест. Может использоваться для фильтрации квестов по категориям.
priority_level — уровень приоритета квеста. Чем выше значение, тем приоритетнее квест для отображения и выполнения.
search_zoneid — ID зоны, в которой происходит действие квеста. Определяет область, в которой игрок должен выполнять задание.
iscategory — указывает, является ли квест частью категории квестов (например, кампаний или цепочек заданий).
reward_id — ID награды за квест. Может быть несколько наград, указываются через точку с запятой.
reward_num — количество каждой награды, соответствующее полю reward_id.
pre_level — предварительный уровень или дополнительные условия, которые должны быть выполнены до начала квеста.
faction_id — ID фракции, к которой относится квест. Может быть использован для фракционных квестов.
faction_level_min — минимальный уровень фракции, необходимый для выполнения квеста.
faction_level_max — максимальный уровень фракции, при котором квест доступен.
quest_end — завершение записи для квеста. - M1 a9 y9 H( D
) h' n G! ^( a5 L, d( U5 k! u; p
Файл клиента QuestMarkConditionData.dat содержит информацию о квестах, связанных с условиями, необходимыми для активации или завершения определённых действий в игре. 3 B. h" r, |* |. z
Пример соодержания ; ?* o5 M |2 x4 M- zВот описание структуры строки: ! ~8 I" H q- @( b( v
Давайте разберем все поля на основе примера:( v; k* @( I7 S& Y* P6 ~
- J ^ l: F. s
questmark_begin: Указывает на начало записи о квесте.
quest_id=10331: Идентификатор квеста. В данном случае, квест с ID 10331.
npc_id=32153: Идентификатор NPC (неигрового персонажа), с которым игрок должен взаимодействовать для начала или выполнения условий квеста.
race_filter={0}: Фильтр по расе. Указывает, какие расы могут участвовать в квесте. В данном примере {0} может означать, что квест доступен для всех рас или для определённой расы (например, 0 - для всех) .
class_filter={0;10}: Фильтр по классу. Указывает, какие классы могут участвовать в квесте. В этом случае {0;10} может означать, что квест доступен для классов с ID 0 и 10.
start_npc_loc={-118017.0;255965.0;-1320.0}: Координаты начала взаимодействия с NPC. Эти координаты определяют место, где находится NPC в игровом мире (X, Y, Z).
questmark_end: Указывает на конец записи о квесте.) d7 h/ v; M" P1 g) N' n R4 ]; B- L9 @* v
Эта структура помогает клиенту определять условия, при которых игрок может начать или выполнить квест, а также идентифицировать необходимые взаимодействия с NPC.9 z8 a1 o5 U! l$ X( _" l
( S1 S! X6 J% M s' V
$ J5 Z# C* v1 S; N, h% k4 t( I2 p2 }; G. v; b: W# ~1 E: z- y
Следующие шаги относятся к любым новым хроникам, которые используют всплывающие окна квестов.1 _2 k" Q) h* Z, R- n8 d# }$ @) i! Q
- V3 Y' o8 M$ L' }! z& s Шаг 4 , A' M, q; G. r; W6 G5 T) mДля того чтобы добавить свой квест в файл NewQuestData.xml, нужно следовать структуре, аналогичной приведенному вами примеру. Вот как это может выглядеть:5 Q# h! n g, d: [; S; j! O
Пример добавления нового квеста:. i$ A( a3 P3 f( g. s! E
<quest id="20001" type="1" name="Mystery of the Lost Relic" startNpcId="30050" endNpcId="30051">3 r5 ]: O# Y1 R8 m6 Z8 s) ^5 V9 M
<param name="preQuestId">20000</param>3 b/ }6 a0 K; ]- P& r
<param name="classIds">0;1;2;3;4;5;6</param> <!-- доступ для всех рас -->- i- R" G' c/ h1 K# o9 _
</conditions> 6 ^ W. u x7 H
<rewards>' M) [0 k" g3 _8 W- j
<param name="rewardLevel">50</param> G' ~" v1 e. ~8 X) v9 J6 Z* O+ f
<param name="rewardSp">5000</param>1 _9 r! J" D* v% k
<param name="rewardItemId">57</param> <!-- Adena -->! y* e# M; Y+ a
<param name="rewardItemCount">10000</param>" m9 v9 J' n: Y1 [4 i1 C. M
</rewards>, ]/ B/ X* N& @' A
<goals># Z9 L W, [1 o/ @* Q* M8 d9 x
<param name="goalCount">10</param>: r# c1 w, m; Z. m, i
<param name="goalString">Defeat monsters in the Ancient Forest</param> , z9 K( o# B* h, f8 a5 |: _, \
<param name="goalItemId">92000</param> <!-- некий квестовый предмет --> . X( P" K C% Z- T3 ^! T
<param name="goalItemCount">1</param> \, h* }( K/ B, K' I
</goals> 3 Y: r; c8 k: k* i
</quest> ) w7 y5 w. B6 A0 b/ c4 p5 d
Скопировать код
Описание структуры:: i! `& W3 V# x. b$ p7 ?+ Y( M
quest: Основной элемент квеста, содержащий атрибуты: 4 i: J, n5 x3 O% {( L1 |; j5 \
id: ID квеста, уникальный для каждого квеста.
type: Тип квеста (1 – обычный квест).
name: Название квеста.
startNpcId: ID NPC, с которого начинается квест.
endNpcId: ID NPC, у которого квест заканчивается.4 b# B2 t- i' w8 y( u1 B' u
locations: Указывает места начала, окончания и квестовой активности. 9 q, H5 q, B* g8 I9 K- e6 y
startLocationId: ID места, где начинается квест.
endLocationId: ID места, где квест заканчивается.
questLocationId: ID квестовой зоны. 0 R2 L$ _; N# q5 k, a
conditions: Условия для начала квеста. % W7 ~2 X8 A' Z4 [# Z4 b2 i
preQuestId: ID предварительного квеста (если есть).
classIds: ID классов или рас, которым доступен квест. 7 @7 N, f7 w3 f1 `' l
rewards: Награды за выполнение квеста.: a# o5 n' [9 G- E
rewardLevel: Минимальный уровень для получения награды.
rewardSp: Количество опыта (SP).
rewardItemId: ID предмета (например, Adena).
rewardItemCount: Количество предметов.7 n# | X0 W! l) A
goals: Цели квеста. ( w: {- a" f* T
goalCount: Количество монстров, которых нужно убить или предметов, которые нужно собрать.
goalString: Описание цели.
goalItemId: ID квестового предмета (если требуется).
goalItemCount: Количество квестовых предметов для завершения цели.! ?* T% K( A v- ]
После того как вы добавите квест в файл NewQuestData.xml, нужно перезапустить сервер, чтобы изменения вступили в силу.0 V$ X) r) w: g; a9 \' [+ n
1 |: n" B, \) Y# t1 I5 g Шаг 5 7 Z% l9 @: J% c+ v) i' L d, YФайл NewQuestDialog-ru.dat используется для хранения диалогов, связанных с квестом. Он определяет тексты, которые отображаются в окнах диалогов с NPC во время выполнения квеста. Вот разбор ключевых элементов строки и структура файла: " V. X* w) R }4 m+ [6 l7 c; BСтруктура данных
NewQuestDialog_begin — начало записи квеста в файле диалогов.
QuestId=10001 — идентификатор квеста (должен соответствовать ID, который ты используешь в других файлах).
Text0=... — первый диалог, который обычно отображается при старте квеста.
Text1=... — дополнительный текст, который отображается на различных этапах квеста.
Text2=... — текст, который отображается после выполнения определенных действий (например, после выполнения части задания).
Text3=... — дополнительный диалог, например, при встрече с NPC на следующем этапе квеста.
Text4=... — финальный текст или инструкции по следующему шагу для игрока.
NewQuestDialog_end — завершение записи для этого квеста. 6 l3 _; H1 s$ Q$ ~, F6 w
! `. r! N* D, y7 J8 @% v3 }Пример записи для нового квеста (ID 98765) Если ты хочешь создать диалоги для нового квеста с ID 98765, твой файл может выглядеть так: 7 I/ [# p; |2 x1 Y
NewQuestDialog_begin QuestId=98765 Text0=[Вы готовы принять новый вызов и доказать свою силу?] Text1=[Как вы себя чувствуете? Вы выглядите уверенно. Это хороший знак, но не расслабляйтесь — впереди много испытаний. Примите это задание, если готовы.] Text2=[Пора приступить к тренировкам. Идите за мной в тренировочную зону.] Text3=[Следуйте моим указаниям, и вы раскроете весь свой потенциал.] Text4=[Поговорите с Дарти. Кликните на него и начните диалог.] NewQuestDialog_end * ?8 Y0 e8 Q. I! W7 M
Скопировать код
Разъяснение полей:' |( t3 H- b1 b
QuestId=98765 — уникальный идентификатор нового квеста.
Text0 — вводный текст квеста. Отображается при первом контакте с NPC.
Text1 — дополнительный диалог, который дается игроку для создания контекста.
Text2 — текст, который отображается на следующем этапе квеста, например, после выполнения части задания.
Text3 — описание следующего шага или инструкции для игрока.
Text4 — финальный диалог или текст с указанием цели (встреча с другим NPC). & T* g3 F4 ]$ w P: _
9 Y5 w+ _2 u& P1 v
& D6 u' g4 U% M8 _Что можно изменить:
Тексты диалогов (Text0, Text1 и так далее) можно адаптировать под конкретные ситуации в квесте.
Количество текстов можно варьировать в зависимости от сложности квеста. 6 m( [6 z" ]8 E* ^
( _4 Q8 M2 l1 d5 a6 G/ UФайл NewQuestData-ru.dat содержит параметры, связанные с квестом в игре Lineage II, и описывает условия, NPC, цели и награды. Рассмотрим параметры этого файла:9 j/ c" _& W* h# O* N, ~
7 L8 l; X. t2 ~/ }$ W( t4 d% _
newquestdata_begin / newquestdata_end: Эти параметры обозначают начало и конец блока данных квеста.
quest_id=10001: Уникальный идентификатор квеста (ID). В данном случае это квест с ID 10001.
quest_type=1: Тип квеста.# x1 s! f5 A6 s' I' } j, Q. O
1 обычно означает стандартный квест. 8 N+ W* x9 A9 @; y9 s
quest_name=[Новый путь]: Название квеста. Здесь указано "[Новый путь]" — это имя, отображаемое в игре.
quest_level={0;0}: Уровневые ограничения квеста. . x a8 x2 J: q) b& K
Первое значение указывает минимальный уровень, второе — максимальный уровень.
{0;0} означает, что нет ограничений по уровню.. v, z% Y) b4 n
pre_quest={}: Предварительный квест, который нужно выполнить перед началом этого квеста.2 g3 f) S/ H( l" K
В данном случае он пустой {}, что означает, что нет предварительных требований. . }% m8 ?2 \2 H# @* r
class={0;10;18;25;31;38;44;49;53;123;124}: Классы или расы, которые могут брать квест. , |) ^! p, {- `
Номера классов указывают на те классы, которым доступен этот квест. В данном примере классы, такие как 0 (человеки), 10 (рыцари) и другие, имеют доступ.. N d$ n/ j( O( g5 ]
quest_item=82948: ID квестового предмета, необходимого для выполнения цели или этапа квеста. 8 r" s+ {" n l1 J& H
В данном случае это предмет с ID 82948. r, D4 i: D# q3 y8 l$ C
start_item=0: Предмет, который выдается при начале квеста.* ~- u S5 L* l+ l0 N" s# Q! {7 @
Значение 0 означает, что предмет не выдается.# ~" `2 E& r1 G8 X0 W
start_npc=34505: ID NPC, у которого начинается квест.
start_npc_loc=1002: Локация NPC, у которого начинается квест. # F6 ^ R9 y: D% g+ Z" ]
Это ID локации, где находится стартовый NPC. 8 f1 K* K1 j" U+ v# y3 N
end_npc=34696: ID NPC, у которого завершается квест.
end_npc_loc=1003: Локация NPC, у которого завершается квест. 9 j# f1 ^7 K. v( d, y9 @1 Q( M
Это ID локации, где находится конечный NPC. 2 R7 P L0 }- v+ m T! C
quest_loc=1003: Основная локация выполнения квеста. 2 v3 {6 P/ T: _( o9 g$ ~# z
Это ID зоны, где нужно выполнять основные задачи. 6 q! t% l& k. }6 G; X
goal_string=[Дарти (Зона Тренировки)]: Описание цели квеста.& e2 V! l7 b$ B* Y# D$ |1 p
В данном случае цель связана с персонажем по имени "Дарти" в Зоне Тренировки.5 L% v5 N- W) W i
goal_num=1: Количество действий, необходимых для выполнения цели (например, убийств монстров или сбора предметов).+ j% W2 J, A# S1 i0 U
В данном случае нужно выполнить одно действие (1).9 }4 ]( l) t. Z5 u5 a0 R
reward_level=65535: Уровень, при котором можно получить награду. , X' h3 U! U- m) k& _
В данном случае это максимальное значение, указывающее, что награда доступна всегда. 8 Y/ `, g, M% z7 a+ v* m
reward_exp=0: Опыт (EXP), выдаваемый в качестве награды. " O$ A/ k h O
В данном случае опыт не выдается.1 p( H% p2 F5 v$ c) y
reward_sp=0: Количество SP (Skill Points), выдаваемых в качестве награды. " m% K9 D/ S8 I2 [' ?7 t9 x6 @
Здесь тоже 0, значит, SP не выдаются.$ V5 g0 [1 Z% D# t& P7 K1 M. L
reward_item={}: Наградные предметы. " L! I3 f( [+ B1 k
В данном случае наградные предметы отсутствуют.' `; a9 \) ]0 t0 V$ D( K* P
Этот файл определяет основной функционал и настройки для конкретного квеста в игре.- J& e4 l/ L. I4 I- w
7 _5 Z1 M: @. u* V3 a$ X2 p6 o3 Y " K/ k( q0 E5 w9 u6 ^* v U, c! t$ Y C4 m7 V! |$ r
, T9 x. B# D* W: [; Z9 w9 Y y* w0 j& \: B3 Q
% ~/ U8 `( y5 Z8 G+ X; t. | ! V0 ~; G: P' }9 N8 Q8 v6 y& O' s) \0 Y( i0 I* j8 x
& K; v8 v" T6 w% M1 @- z" T5 [ 0 D$ H) \5 z- b
Добро пожаловать artace.ru - творческий сектор (https://www.artace.ru/)