Перейти к контенту

Dynamic Trade Listings


Карлан

Рекомендуемые сообщения

Ребят, может кто не понял, думаю еще раз стоит объяснить. Это не глобальный мод, это специализированный мод, поэтому прошу не задавать вопросов и не предлагать идей, которые не относятся к торговле в принципе (к ней конечно относится в принципе весь игровой процесс, но давайте тут все же только моментами, которые можно использовать без переделки чего-то кроме конфигов, обойдемся). Так же по поводу "вкуса и цвета" я согласен и никогда не буду кричать и спорить, что мои взгляды лучше ваших, считаете я сделал убого - переделайте под себя, я подробно описал как. Моя настройка дисконтов далеко не панацея. Да и сам этот мод не панацея. Всегда все можно переделать, ну или не трогать вообще.

Поделиться этим сообщением


Ссылка на сообщение

Решил написать подробную инструкцию по использованию, так как добавлено всего много, и те, кто скачал часто пишут в стиле «вы там ушли или че, мы тут в непонятках», версию до того, что было поставлено не дотянула, сейчас уже нет возможности. Поэтому функции все есть, протестированы и работают, но функционал немного староват, но плюс в том, что адаптируется легко под 6 патч, в целом под него и написан, поэтому довольно много эзотерики. Да ладно, это все лирика, перейдем к делу.

Большая популярность мода мне ясно дала понять, что дальнейшей разработкой, доработкой и развитием заниматься смысла нет никакого, мое последнее прощай.
Что это и зачем объяснено в шапке, если кому-то что-то неясно можете задавать вопросы, я отвечу.

Из движка мне было лень выкидывать все что я там делал, поэтому пользуйтесь на здоровье, но опишу только функции с торговлей.
Итак, ключевые лица:
karlan_trade_extensions.script – универсальный хак торговли
m_trade.script – сам модуль торовли
manager_trade.script – переработанный менеджер торговли

1. karlan_trade_extensions.script


Имеет вид:
 

// !!!don't del me!!!
// trade universal hack by Karlan
function can_item_trade(first_trader,second_trader,item)
return true
end

 

Удалять его низя, функция вызывается на каждый добавляемый итем в торговый лист с возможностью запрета, так же добавляются оба агента торговли. Если функция возвращает тру – итем добавляется, фолс – не добавляется. Как использовать – очевидно.


2. m_trade.script


Тут самое интересное, весит много, но пугаться не стоит. Принцип работы описывать долго и бесполезно, поэтому опишу только использование.
 

--// для теста заполним первую таблицу всеми воможными ключами
--// торговать могут все чем только можно, но с заданной вероятностью
--// если переводить таблицу на скриптовый рандом то нужно учитывать единицу у первого ключа, если рандом будет максимальным, то итема добавится (max random + 1)
{
--// имя секции [required]
name = "bandage",
--// таблицы формирования списков и цен для торговцев и группировок [optional]:[base = tutor]
-- 1 сколько товара минимум
-- 2 сколько товара максимум
-- 3 макстмальная цена покупки у актора
-- 4 минимальная цена покупки у актора
-- 5 максимальная цена продажи актору
-- 6 минимальная цена продажи актору
-- 7 минимальное значения счетчика увеличения товара
-- 8 максимальное значение счетчика увеличения товара
-- 9 вероятность появления типа товара в продаже
["3"] = {20,(math.random(40,60)/100), 0.1,0.05, 4,2, 2,3, 80},
["3_esc_kill_bandits_quest_done"] = {30,(math.random(40,60)/100), 0.2,0.1, 3.7,1.5, 3,4, 90},
["500"] = {50,(math.random(40,60)/100), 0.16,0.04,4,2, 2,3, 80},
["500_yan_labx16_switcher_primary_off"] = {60,(math.random(35,55)/100), 0.2,0.08, 4,2, 3,4, 90},
["500_bar_darklab_document_done"] = {70,(math.random(30,50)/100), 0.4,0.15, 4,2, 4,5, 100},
["506"] = {40,(math.random(40,60)/100), nil,nil, 3,1.5, 1,3, 90},
["506_bar_svoboda_rg6_done"] = {50,(math.random(35,55)/100), nil,nil, 2,1, 2,3, 100},
["734"] = {30,(math.random(40,60)/100), nil,nil, 3,1.5, 1,3, 80},
["734_mil_leader_quest2_complete"] = {40,(math.random(40,60)/100), nil,nil, 2.8,1.2, 2,3, 90},
["734_mil_lukash_dolg_task_complete"] = {50,(math.random(35,55)/100), nil,nil, 2,1, 3,4, 100},
["902"] = {60,(math.random(35,55)/100), nil,nil, 2,1, 4,5, 100},
["902_yan_kill_brain_done"] = {70,(math.random(35,55)/100), nil,nil, 2,1, 5,6, 100},
--// вот так например можно менять цены и ассортимент у группировки после получения какого-то инфопоршня [optional]:[base = tutor]
["stalker_esc_kill_bandits_quest_done"] = {4,0.4,0.18,0.07,4,2,1,1, 100},
["stalker"] = {3,0.4,0.18,0.07,4,2,1,1, 100},
["ecolog"] = {30,0.4,0.18,0.07,4,2,1,1, 100},
["dolg"] = {30,0.4,0.18,0.07,4,2,1,1, 100},
["freedom"] = {30,0.4,0.18,0.07,4,2,1,1, 100},
--// эту таблицу будут юзать все, в случае отсутствия спецзаданной [optional]:[base = tutor]
all = {30,0.4,0.18,0.07,4,2,1,1, 100},
--// ТОДО: выяснить очереедность выдачи инфопоршней, пока как в оригинальном конфиге (на авось), но все вроде как надо работает [optional]:[base = tutor]
info = {"esc_kill_bandits_quest_done", "yan_labx16_switcher_primary_off", "bar_darklab_document_done", "yan_kill_brain_done", "bar_svoboda_rg6_done", "mil_leader_quest2_complete", "mil_lukash_dolg_task_complete"},
--// у этих приоритет выше [required]
traders = {3, 500, 506, 734, 902},
buyer = {3, 500},
--// чем у этих [required]
sell_stalkers = {"stalker", "ecolog", "dolg", "freedom"}, --// товары которые они продают
sell_stalkers_friend = {"stalker", "ecolog", "dolg", "freedom", "frien"},
buy_stalkers = {"stalker", "ecolog", "dolg", "freedom"}, --// товары которые покупают
buy_stalkers_friend = {"stalker", "ecolog", "dolg", "freedom", "frien"},
--// предикат по количеству для торговли со сталкерами [optional]:[base = 1]
max_cnt = 3,
--// предикат по рангу(фейковому) итема для торговли со сталкерам [optional]:[base = 1]
item_rank = 1,
--// предикат по левелу (как вариант совместить с ранговыми таблицами, но тогда полтоно нереально увеличится, а выхлоп небольшой, пока пусть так будет) [optional]:[base = tutor]
levels = {
--| торгуемость | актор продает (коэфф.)| актор покупает (коэфф.)| --
["l01_escape"] = {trade = true, 1, 1},
["l02_garbage"] = {trade = true, 1, 1},
["l03_agroprom"] = {trade = true, 1, 1},
["l03u_agr_underground"] = {trade = true, 1, 1},
["l04_darkvalley"] = {trade = true, 1, 1},
["l04u_LabX18"] = {trade = true, 1, 1},
["l05_bar"] = {trade = true, 1, 1},
["l06_rostok"] = {trade = true, 1, 1},
["l07_military"] = {trade = true, 1, 1},
["l08_yantar"] = {trade = true, 1, 1},
["l08u_brainlab"] = {trade = true, 1, 1},
["l09_deadcity"] = {trade = true, 1, 1},
["l10_radar"] = {trade = true, 1, 1},
["l10u_bunker"] = {trade = true, 1, 1},
["l11_pripyat"] = {trade = true, 1, 1},
["l12_stancia"] = {trade = true, 1, 1},
["l12u_sarcofag"] = {trade = true, 1, 1},
["l12u_control_monolith"] = {trade = true, 1, 1},
["l12_stancia_2"] = {trade = true, 1, 1},
},
},

 

Описывать досконально все довольно долго, я лучше буду пояснять конкретные непонятные моменты.


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

Теперь описание движковых функций и коллбеков.

 


У меня не осталось никаких хвостов по материалам, что сообразить и вспомнить смогу то и напишу, последний раз этим в апреле занимался.
Добавлены ключи дисконтов такие же как в ЗП. Добавлен порог убитости итема ниже которого НПС не купит предмет у ГГ. Еще хотел конфиг доапдейтить, но забил, так что больше ничего нет. В общем ключи также называются чтобы народ не путать.

Коллбеки:
 

on_start_dialog
to_our_trade
to_others_trade
to_our_bag
to_others_bag

 

Думаю, что какой означает – ясно из названия. В первый падают агенты, в остальные четыре юзердата итема.
Методы:
 

set_tradable_item_id(u16, bool, bool) - торгуемость по айди
get_tradable_item_id(u16, string)
set_tradable_item_section(string, bool, bool) - торгуемость по секции
get_tradable_item_section(string, string)
buy_item_condition_factor(float) – аналог ЗП 
set_section_condition_factor(section, float, float) - установка по какой кондиции купит/продаст
get_section_condition_factor(string, string)

 

Все методы для inventoryowner. Почему нет метода для изменения цены итема ингейм? А черт его знает, мне это было не нужно, не помню даже было это в планах или нет. Так или иначе это все довольно просто делается, можно написать хак напрямую, можно сделать элегантный метод, кому как удобнее. Если острая необходимость возникнет - добавлю, дело нескольких минут.
 
Чтобы небыло косяков необходимо менять флаги группировки итемов через flags16() и метод set_inventory_item_flags, функции крайне замудренные, спрашивал многих как с ними работать, в результате так никто и не помог, разобрался сам. В общем сделал две вменяемых обертки set_groupable, set_ungroupable, как они работают я не буду объяснять это муторно и все равно мало кто въедет. 
 
Добавлены статики:

	<string id="st_not_interested_item_other">
		<text>Торговец не заинтересован в этом предмете.</text>
	</string>
	<string id="st_not_interested_section_other">
		<text>Торговец не интересуется подобными предметами.</text>
	</string>
	<string id="st_not_interested_broken_item_other">
		<text>Предмет в слишком плохом состоянии для продажи.</text>
	</string>

Так же karlan_trade_ext_static статик который можно к примеру динамически менять, этот статик выскакивает если итем не может продаться по скрипту karlan_trade_extensions.script. С ним можно на любых условиях сделать любую причину отказа покупки товара, это на тот случай если тех что я добавил для вас будет недостаточно :).
 


 
Пока все, все что хотел – освятил. Если что-то непонятно пишите.

  • Спасибо 3
  • Не согласен 1

Поделиться этим сообщением


Ссылка на сообщение

Немного дополнил функции, теперь можно устанавливать цену конкретного предмета у конкретного торговца.

 

Каким путем:

В функции get_buy_discount и get_sell_discount теперь первым аргументом вместо айди идет юзердата собеседника (для работы с конкретным агентом), далее идет результирующая цена (та по которой он купит/продаст, для собственного анализа цены), и последним идет непосредственно юзердата итема для которого высчитывается цена.

 

То есть, говоря на луа:

get_buy_discount(userdata, int, userdata)
get_sell_discount (userdata, int, userdata)

Эти функции, как вы знаете, возвращают параметр типа float (WTF?!), далее (в движке) он умножается на результирующую, округляется до целого, и возвращает значение от единицы до миллиона (т.е. еще раз округляется). Это следует учитывать, повторюсь, наценка не суммируется, а умножается.

 

Самое главное, например:

Пример тупой, но какой сразу в голову пришел. У нас с вами есть какая-то аптечка, она нам по особенному дорога и мы ее хотим впарить в два раза дороже цены сбыта любому торговцу. Соответственно нам надо в тело get_buy_discount вставить какой-то такой код:

function get_buy_discount(npc, cost, obj)
// some code
return (obj and obj.is_my_medkit) and 2 or 1
//some code
return 1 // необязательное универсальное условие, для подстраховки
end

Можно сделать и суммирование, и суммирование/умножение по условию, но пока не вижу веских причин это делать.

 

 

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

 

А далее я засаживаюсь пиликать торговлю и превращать это все в "симулятор трейдера"™.

  • Не согласен 1

Поделиться этим сообщением


Ссылка на сообщение

Всем привет! :)

 

Version 1.3 RC

 

Новости и "что было сделано":

- Исправлена 'неправильно' работающая логика движковых функций (возвращала единицу вместо ноля, в результате чего надо было обязательно проводить настройку всех итемов в игре как минимум для одного торговца)

- Переписаны функции формирования цены для еще более тонкой настройки

- Начата работа по созданию подобия денежной системы

- Введено понятие (локального) дефицита товара, но еще не внедрено, делается так как задумывалось GSC, также еще один вид дефицита (глобальный), который "придумал" я, на стадии продумывания идеи

- Вернулось повышение цен на аптечки если ГГ в плохом состоянии и у него мало медикаментов (не у всех торговцев, некоторые по прежнему благосклонны)

- Начата разработка системы учета катаклизмов

- Начата (в который раз) переработка всех торговцев, мне теперь хочется больше ударить по геймплею, чтобы каждая локация "торговала" чем-либо для ГГ выгоднее, чем другая

- Обдумывается уместность конкуренции

 


 

Технического плана мануал:

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

get_buy_cost(userdata, userdata, u32, u32)
get_sell_cost(userdata, userdata, u32, u32)

Дабы никого не запутать, и не запутаться самому, get_buy_cost вызывается когда мы кликаем по итему из списка товаров ГГ, а get_sell_cost вызывается когда кликаем по итему из списка нашего второго экономического агента. 

Теперь о параметрах, первым передается экономический агент, вторым предмет, третьим цена-нетто, четвертым цена-брутто (в самом файле оформлены как '(npc, obj, net_price, gross_price)'). Функционал дисконтов никуда не потерялся, он по прежнему прямо также работает. И, самое главное, теперь эта функция занимает роль последней инстанции в формировании цены на предмет, таким образом Вы полностью, опираясь на входные данные, можете смотреть по каким ценам торгуются в данный момент эти предметы, и если вас что-то не устраивает то менять цену либо на конкретный предмет, либо на секцию, либо на какую-то группу которую Вы сами пожелаете сформировать. Те функции которые написаны в туторе, сделаны для управления списками торговли, а вот эти функции сделаны больше для управления ценами товаров из уже готового списка. Все делается ингейм, все очень удобно. Также напомню, для управления списком есть скрипт karlan_trade_extensions, там возможно управлять текущим списком, и, если потребуется, выводить динамический статик с текстом причины отказа в покупке предметов.

 


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

Поделиться этим сообщением


Ссылка на сообщение

Рот Фронт!

Version 1.4 RC


Изменения:

Добавлен полный дамп ценовых коэффициентов в виде луа-массива, называется karlan_costs (выступает глобальной переменной), и имеет следующие поля:

1. gross_price - цена-брутто
2. condition_factor - фактор влияния состояние предмета на его цену
3. relation_factor - фактор учета личных отношений экономических агентов
4. action_factor - значение отражает комбинированный фактор из произведения между фактором личных отношений и фактором из конфигурационного файла (первое, либо второе число берется в зависимости от количества благосклонности, константы которого устанавливаются в game_relations, и, если не ошибаюсь, имеют ограничения 2^16)
5. deficit_factor - фактор дефицита товара (общно - если существует, то значение количества и вероятности из конфига делится на значение количества и вероятности текущее)
6. net_price - цена-нетто, которая является произведением всех вышеуказанных факторов

Аргументами функций дисконтов теперь являются только две юзердаты (юзердату итема возможно получить из коллбека), они в контексте обновления массива цен являются константами. На финише (после ручной обработки) осталась нормализация значения и округление в диапазоне от 1 до 1000000.

 


 

Полный дамп может выглядеть вот так:

for coeff, value in pairs(karlan_costs) do
printf('%s = [%s]', coeff, value)
end

Следует заметить, что использование актуально только в функциях формирования цены, в остальных случаях - nil.

 


 

Также демонстрационно введена бартерная торговля водкой с военными через движковое торговое окно. Принцип в том, что все цены являются жестко округленными (до сотен рублей) константами, и влияют на них только какие-то сильные факторы (запой) которые могут перевесить чашу весов в чью-либо сторону. Статики цен не скрываются, но при желании можно скрыть (получится как в AMKII), тогда получится что-то вроде полноценного обмена без цифр.

 

К примеру АС "Вал" стоит 7000р, военный берет водку за 200р, нехитрыми вычислениями получаем, что автомат стоит 35 бутылок. Плюс системы в том, что вы можете за один заход купить у военного все что вам необходимо без мучительного (на мой взгляд) ползания по дебрям диалогов, сначала десять фраз чтобы получить патроны, потом десять фраз за тушенкой.. ну кому как, меня всегда раздражало :).

Поделиться этим сообщением


Ссылка на сообщение

Для тех, кто ждал, надеялся и верил.

 

Работа полностью завершена. Разработка в несколько урезанном варианте была опубликована в рамках Prosectors Project.

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

Что делать с темой - на усмотрение самизнаетекого.

 

Всем спасибо за поддержку.

  • Спасибо 1

Поделиться этим сообщением


Ссылка на сообщение

Да, но она очень старая (2013 года). У меня сохранилась, по моему, только версия 0.8, сейчас же уже делается 1.6, отличия колоссальные и методы подхода к реализации прямо противоположные, все никак не дойдут руки описать пятнадцатую версию, в ней скрипт выращивался кусками в связи с уходом от оригинала на конкретную платформу. Если интересно, я могу выложить 0.8 (она проще для восприятия, чем та же 1.1 с ее колоссальными данными), но там методы подхода к реализации довольно плохие для пользователя разработки, я бы даже сказал очень плохие, придется затратить достаточно времени на настройку всей торговли. Причем, что весь оригинальный (4-6 патчи, например) потенциал торговли я не раскрыл вплоть до 1.6 версии (сначала недостаток опыта, затем времени), вот так вот :). То есть вот куски, которые появились буквально недавно вполне себе замечательно будут работать и на обычном сталкере безо всяких исходников, если кто-то их портирует на оригинальную игру из скрипта на дату релиза, то возможно где-то кому-то и работы меньше будет. Но куда проще будет перейти на PP.

 

Стоит обратить внимание на мой тутор: http://www.amk-team.ru/forum/topic/13042-dynamic-trade-listings/?p=949806

Вот какой-то минимум ключей нужно будет делать для каждого итема, это ужасно, и такова история вплоть до 1.5, где я начисто вырезал этот скрипт, т.е. функционал оскуднел, но он был чрезвычайно избыточен (та же полокационная настройка, да кому и когда она будет нужна?), в принципе вырезан только скрипт формирования листа, но возможность его активировать в текущей версии присутствует и не составляет никакого труда его вернуть, просто в итоге я сделал вывод, что проще оформлять в конфигах в том стиле, в котором есть, а под какие-то уже конкретные расширения возможно да, формировать скриптом, но это опять же не составляет труда, так как в новых версиях есть возможность изменения не всего листа, а лишь его определенной части в любой момент времени.

 

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

  • Спасибо 1
  • Нравится 1

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

    Ни один зарегистрированный пользователь не просматривает эту страницу.

AMK-Team.ru

×
×
  • Создать...