Работа с магазинами

В этом уроке мы будем учится работать с файлом "shopping.dat" и рассмотрим основные опкоды для работы с ним.

Привет, друзья! Наконец-то нашел время написать новый урок. На очереди у нас обзор опкодов для работы с файлом "shopping.dat". Прежде чем приступить к написанию скриптов по этой теме, сначала разберёмся с форматом данного файла, так как опкоды во многом зависят от данных, которые находятся внутри.

Внутри файла есть две основные секции (в начале идёт название "section"): prices и shops. В первой секции идёт описание товаров (предметов), а во второй — описание магазинов, в которых и будут эти товары.

Секция "prices"

Секция "prices" дополнительно разделена на типы, используя тоже ключевое слово "section". Эти типы группируют товары по определённому признаку. По умолчанию используются 6 типов: "CarMods", "Clothes", "Haircuts", "Tattoos", "Food" и "Weapons". Есть ещё 3 пустые секции, которые не используются в игре ("Furniture", "Gifts" и "Property").

Формат каждого типа отличается по своей структуре. Давайте разбираться с тем, что есть. Каждый тип гарантировано имеет 7 параметров:

ПараметрКоличествоОписание

name

1

Идентификатор предмета

nametag

1

GXT-имя предмета

stats to change

4

На какие характеристики игрока будет влиять покупка (используется не всегда)

price

1

Цена товара

Идентификатор предмета — это уникальное имя. Его мы запомним, так как чуть ниже он будет упомянут. Отдельное внимание нужно обратить на характеристики. Они описаны четырьмя параметрами, но влиять можно только на два стата.

Характеристики описаны в следующей последовательности:

ИМЯ_СТАТА_1 ЗНАЧЕНИЕ_СТАТА_1 ИМЯ_СТАТА_2 ЗНАЧЕНИЕ_СТАТА_2

Вот таблица статов, которые можно использовать:

ХарактеристикаОписание

fat

Влияет на вес Карла

health

Влияет на здоровье Карла

calories

Влияет на вес и здоровье Карла

stamina

Влияет на выносливость Карла

respect

Влияет на уважение Карла

sexy

Влияет на привлекательность Карла

Значение стата указывается числом. Если покупка не влияет на характеристику, то используется 0. Если влияет, то положительное число будет увеличивать характеристику, а отрицательное — уменьшать (значения от -128 до 127). Если стат вообще не нужно использовать, то достаточно поставить символ - (вместо имени и значения). Пример:

ИМЯ_СТАТА_1 ЗНАЧЕНИЕ_СТАТА_1 - -
respect 0 sexy 0
respect 0 - -

× Примечание: Многие секции содержат статы для изменения, но в реальности только некторые из них действительно их изменяют. Остальные чисто декоративные и никак не реагируют при покупке.

Это основные параметры. Некоторые секции имеют в своём формате дополнительные параметры (extra; встречаются в секицях "тату", "причёски" и "одежда"). Они представлены в виде целых чисел или строк (в скрипте строки конвертируются в число алгоритмом CRC).

Секция "shops"

С товарами разобрались. Перейдём к магазинам. Структура этой секции проще. Она содержит в себе другие секции, которые описывают магазины. Общая структура такова:

section NAME
 type TYPE
 item ID
end

Имя секции (NAME) — уникальный идентификатор. Это имя используется в одном из опкодов, поэтому запомним его. Далее "type" — это слово указывает, какие товары будут использованы из секции "prices". Имя типа совпадает с именем секции, которые я описывал ранее. Далее идут предметы (по одному на строку). После слова "item" пишется уникальный идентификатор предмета.

Практика

С теорией мы кое-как разобрались. Давайте теперь посмотрим на опкоды, которые используются для работы с файлом "shopping.dat". Сначала идёт загрузка цен и магазинов:

075E: load_shopping_data_PRICES_subsection "ammun1" 
075D: load_shopping_data_SHOPS_subsection "Weapons"

Обратите внимание, что названия опкодов неправильные (на момент написания статьи)! Опкод 075E загружает информацию о магазинах, а 075D — о ценах. Я не увидел разницы в порядке их загрузки. Рекомендую использовать именно представленный мной порядок, именно так их использовали разработчики.

Здесь: "ammun1" - имя (идентификатор) магазина "Weapons" - тип (группа) цен

Как только работа с магазинами завершена, нам нужно выгрузить из памяти эту информацию, используя опкод:

087C: release_shopping_data

Иногда может быть полезно знать, данные какого магазина сейчас загружены в память. Для этого используем опкод:

07B0: get_active_shop_name_to s$CURRENT_SHOP_ID

Изначально я думал, что этот опкод получает имя интерьера, но оказалось совсем другое :)

Здесь: s$CURRENT_SHOP_ID - переменная, в которую будет записан ID (имя) загруженного магазина. Возвращает пустую строку, если ничего не загружено.

Давайте посмотрим, что можно сделать после загрузки! Первым на очереди станет опкод:

075F: store_shopping_data_entries_number_to $MAX_ITEMS_COUNT

Он получает количество товаров, которые есть в магазине. В нашем случае туда будет записано число 16 (это по умолчанию). Запомним переменную $MAX_ITEMS_COUNT и идём дальше:

0760: store_shopping_data_index 0 textureCRC_to $ITEM

Этот опкод позволяет сохранить идентификатор предмета за указанным индексом. Не обращайте внимания на описание; "textureCRC_to" не соответствует действительности (надеюсь, что это скоро исправят).

Здесь: 0 - индекс $ITEM - сохраняется идентификатор предмета

Индекс — это номер в списке товаров в текущем магазине. Диапазон варьируется в зависимости от количества товаров. Максимальный индекс мы можем получить, отняв единицу от количества товаров (опкод 075F). Таким образом мы можем перебрать весь список товаров, используя этот код:

0A8F: $MAX_INDEX = $MAX_ITEMS_COUNT - 1 // int
for $CURRENT_INDEX = 0 TO $MAX_INDEX 
 0760: store_shopping_data_index $CURRENT_INDEX textureCRC_to $ITEM 
 // ...
end

× Примечание: в этом уроке я использую цикл для рисования меню, но это делать не обязательно.

Дальше идут опкоды, которые позволяют извлечь информацию о предмете:

0761: get_shopping_item_with_textureCRC $ITEM price_to $PPRICE
078C: get_shopping_item_with_textureCRC $ITEM nametag_to s$GXT

Опкод 0761 получает цену предмета, а 075F — GXT-ключ с названием товара. Давайте напишем небольшой скрипт, который будет выводить информацию о товаре:

// ...
075E: load_shopping_data_PRICES_subsection "ammun1" 
075D: load_shopping_data_SHOPS_subsection "Weapons"
075F: store_shopping_data_entries_number_to $MAX_ITEMS_COUNT
0A8F: $MAX_INDEX = $MAX_ITEMS_COUNT - 1 // int
03F0: enable_text_draw 1
while true
wait 0
if
00E1: player 0 pressed_key 15 // k~~VEHICLE_ENTER_EXIT
then
jump @end
end
0@ = 20.0
for $CURRENT_INDEX = 0 TO $MAX_INDEX
0760: store_shopping_data_index $CURRENT_INDEX textureCRC_to $ITEM
0761: get_shopping_item_with_textureCRC $ITEM price_to $PPRICE
078C: get_shopping_item_with_textureCRC $ITEM nametag_to s$GXT
038E: draw_box_position 320.0 224.0 size 640.0 448.0 RGBA 0 0 0 16
0343: set_text_draw_linewidth 640.0
033E: set_draw_text_position 20.0 0@ GXT s$GXT
0343: set_text_draw_linewidth 640.0
045A: draw_text_1number 320.0 0@ GXT 'DOLLAR' number $PPRICE
0@ += 16.0
end
end
:end
087C: release_shopping_data
// ...

Результат:

Неплохо! Давайте двигаться дальше. А тут нас ждут опкоды, связанные с модификаторами цен:

08C8: set_shopping_item_with_textureCRC $ITEM price_to 16000
08C9: reset_shopping_item $ITEM price

Опкод 08C8 устанавливает новую цену на выбранный товар, независимо от настроек в файле. Его можно использовать вне цикла; как только новая цена задана, она используется постоянно. Опкод 08C9, должно быть, сбрасывает цену по умолчанию, однако у меня никакой реакции не происходило (он встречается только в скрипте гардероба). Следует отметить, что новая цена не сохраняется навсегда. Как только мы используем опкод "087C", товары вновь будут иметь старые цены.

Далее рассмотрим опкод, который получает данные об экстра параметре:

0783: get_shopping_item_with_textureCRC $ITEM flag 0 store_to $EXTRA1

Мы можем получить данные об экстра параметре в любой секции, даже если она не содержит экстр. Если параметра нет, то в переменную $EXTRA1 будет записано число 0.

Здесь: 0 - номер экстра параметра $EXTRA1 - переменная, в которую будет записано значение этого параметра

Максимальное количество экстр: 2 (значения 0 и 1 соответственно). Для типа "Weapons" нет таких параметров но, к моему удивлению, опкод достал данные об экстрах (при 0). Изначально я подумал, что это количество патронов, так как оно присутствует в секции, но результат был совсем другим: были числа, но они не соответствовали моим догадкам (ниже будет пример)!

Следующий опкод осуществляет покупку предмета:

0790: charge_money_for_shopping_item_with_textureCRC $ITEM

Под "покупкой" имеется ввиду изьятие у игрока денег согласно цене; изменяет характеристики игрока, если секция позволяет это сделать; изменяет статистику игрока, обновляя данные о покупках. В случае с оружием игроку дают дополнительно оружие и патроны к нему.

× ВАЖНО: Необходимо убедиться, что модель купленого оружия загружена! Если этого не сделать, то при выстреле будет происходить вылет! Лучше загрузить все модели до загрузки магазинов и цен.

И последний опкод, который входит в "основную обойму":

0942: item_with_textureCRC $ITEM is_clothing

Эта проверка возвращает "true" в том случае, если предмет был когда-либо куплен опкодом 0790. Информация о покупке хранится всегда; в сейв-файле (или main.scm, точно не скажу).

Давайте рассмотрим пример с выбором предмета и его покупкой:

// ...
// загружаем модели оружия
075E: load_shopping_data_PRICES_subsection "ammun1"
075D: load_shopping_data_SHOPS_subsection "Weapons"
075F: store_shopping_data_entries_number_to $MAX_ITEMS_COUNT
0A8F: $MAX_INDEX = $MAX_ITEMS_COUNT - 1 // int
03F0: enable_text_draw 1
32@ = 0
while true
wait 0
if
00E1: player 0 pressed_key 15 // k~~VEHICLE_ENTER_EXIT
then
jump @end
end
if and
32@ > 150
0AB0: key_pressed 38 // up
then
5@ -= 1
32@ = 0
if
8029: not 5@ >= 0
then
008B: 5@ = $MAX_INDEX // (int)
end
end
if and
32@ > 150
0AB0: key_pressed 40 // down
then
5@ += 1
32@ = 0
if
001F: 5@ > $MAX_INDEX // (int)
then
5@ = 0
end
end
0@ = 20.0
for $CURRENT_INDEX = 0 TO $MAX_INDEX
0760: store_shopping_data_index $CURRENT_INDEX textureCRC_to $ITEM
0761: get_shopping_item_with_textureCRC $ITEM price_to $PPRICE
078C: get_shopping_item_with_textureCRC $ITEM nametag_to s$GXT
0783: get_shopping_item_with_textureCRC $ITEM flag 0 store_to $EXTRA1
0783: get_shopping_item_with_textureCRC $ITEM flag 1 store_to $EXTRA2
038E: draw_box_position 320.0 224.0 size 640.0 448.0 RGBA 0 0 0 16
if
0942: item_with_textureCRC $ITEM is_clothing
then
0343: set_text_draw_linewidth 640.0
045A: draw_text_1number 5.0 0@ GXT 'DOLLAR' number 1
end
if
07D6: 5@ == $CURRENT_INDEX // @ == $ (int)
then
0340: set_text_draw_RGBA 0 255 0 255
if
00E1: player 0 pressed_key 16 // k~~PED_SPRINT
then
0790: charge_money_for_shopping_item_with_textureCRC $ITEM
08C9: reset_shopping_item $ITEM price
end
end
0343: set_text_draw_linewidth 640.0
033E: set_draw_text_position 20.0 0@ GXT s$GXT
0343: set_text_draw_linewidth 640.0
045A: draw_text_1number 320.0 0@ GXT 'DOLLAR' number $PPRICE
0343: set_text_draw_linewidth 640.0
045A: draw_text_1number 460.0 0@ GXT 'DOLLAR' number $EXTRA1
0343: set_text_draw_linewidth 640.0
045A: draw_text_1number 500.0 0@ GXT 'DOLLAR' number $EXTRA2
0@ += 16.0
end
end
:end
087C: release_shopping_data
// выгружаем модели оружия
// ...

Результат:

Похожим способом делается покупка для остальных магазинов. Это вся базовая информация, которая у меня есть.

Last updated