Алгоритмы, Наработки и Способности
Способ реализации:
Jass
Тип:
Наработка
Версия Warcraft:
1.26
В этой наработке представлена возможность использовать полноценный магазин. Изначально магазин пустой, но вы можете заложить вещичку в магазин, и она тут же появится на полке. Или наоборот, купив артефакт, он тут же пропадает с магазина.
Изначальная вдохновляющая идея была взята отсюда На тот момент я даже не думал, что такое возможно. Классная идея. Но она сделана была на гуи автором, и работает на один рынок. Поэтому, чтобы такая система работала сразу в нескольких магазинов, нужно переделывать полностью. Поэтому я переделал на хэш-таблицу.
Казалось бы проще сделать: добавил или удалил. Что тут такого сложного? Но возникали баги. При повторном добавлении итемы могли исчезать с рынка. Баг описан в этой теме. Пришлось по-другому доделывать - запоминать все айтемы в хэше, и при каждом изменении (добавлении/удалении) сначала все ячейки вычищаешь, а потом заново добавляешь.
Для работы требуется скачать папку триггеров "система рынка" + иметь те способности, которые указаны у рынка:
для работы нужно пункт 2.9
триггер инициализации
короче тут хранятся все настройки. Тут инициализируется хэш-таблица и кучу ключей к этой таблице (это очень важно). Ну и прочие триггеры.
при инициализации запускаем еще базу данных (описано что нужно туда хранить)
call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'bspd', 1) сапоги - сккороходы - здесь храним число снимаемых зарядов. Сделано специально. Если вы продаете два одинаковых итема, например, ботинки скорости - 2 шт, то они сложатся не в два отдельных слота, а в один но с +2 зарядом. При покупке нам надо снять определенное число, каждый раз будем снимать 1.
Но зачем тогда хранить эти значения? какой смысл? Дело в этом поле: Кол-во зарядов
Когда вы покупаете предмет, или создаете триггерно предмет, у вашего героя предмет получается с указанным кол-вом зарядов.
Вот например, Жезл молнии = 3 заряда, Жезл похищения маны = 2 заряда, Камень жизни = 1 зарядов.
Большинство итемов в варкрафте без зарядов - те же когти, маска смерти, сапоги или перчатки. Но эти беззарядовые итемы не могут быть равны 0, так как в РО записано, но в базе данных нужно записать 1. Иначе не вычитается при покупке. Если не вписать туда, то предмет с магазина удаляться даже не будет (пример боевые когти +15 или сфера льда).
call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'I007', 1) амулет леса (руна)
Есть еще один аспект - руны. Если кто знает, можно скрещивать несколько итемов в один с помощью рун.
  • В таких системах в магазинах обычно продаются руны, а не оригиналы.
  • При получении руна исчезает даже при заполненном инвентаре. Если совпадает рецепт, удаляем ненужные, создаем нужный. Иначе создаем и кладем обычный в инвентарь, при заполненном инвентаре дропаем.
  • Если выбрасывают обычный итем на землю, на земле подменяется на руну.
  • Очень удобно использовать не только при скрещивании, но при складываний зарядов однотипных. Особенно, когда у вас заполнен инвентарь. Например, амулет леса.
  • Если продаем обратно в рынок, то необходимо, заложить не оригинал, а ее копию - руну
call SaveInteger(udg_Hash, original, key, rune) - здесь записываем базу данных рун. Это нужно, чтобы доставать нужный тип руны по оригиналу. В качестве ключа key взял число 66
call SaveInteger(udg_Hash, 'I000', 66, 'I004')
function Trig_data_Actions takes nothing returns nothing
    call TriggerSleepAction( 2 )
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'I007', 1) //амулет леса (руна)
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'I001', 1) //Боевые когти (руна)
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'I002', 1) //Туфли логкости (руна)
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'I003', 1) //когти воина (руна)
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'I000', 1) //рецепт когти воина (руна)
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'pghe', 1) //целебное зелье
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'rde3', 1) //кольцо защиты (+4)
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'afac', 1) //флейта меткости
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'kpin', 1) //флейта прозрения
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'odef', 1) //сфера тьмы
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'evtl', 1) //талисман защиты
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'bspd', 1) //сапоги - сккороходы
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'bgst', 1) //пос богатыря
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'gcel', 1) //перчатки скорости
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'lhst', 1) //рог ветров
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'rst1', 1) //руковица огра
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'brac', 1) //рунные браслеты
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'prvt', 1) //талисман здоровья
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'clfm', 1) //огненный плащ
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'ciri', 1) //одеяние мага

    
    // Если является обычным предметов, связующий с руной. То можно заранее создать руну
    call SaveInteger(udg_Hash, 'I000', 66, 'I004') //рецепт когти воина
    call SaveInteger(udg_Hash, 'I001', 66, 'I005') //боевые когти
    call SaveInteger(udg_Hash, 'I002', 66, 'I006') //туфли ловкости
    call SaveInteger(udg_Hash, 'wild', 66, 'I007') //амулет леса
    
endfunction

//===========================================================================
function InitTrig_data takes nothing returns nothing
    set gg_trg_data = CreateTrigger(  )
    call TriggerAddAction( gg_trg_data, function Trig_data_Actions )
endfunction
триггер PawnItem (закладываем итем в магазин)
GetSellingUnit() =продающий торговец (типа всякие предметы закладывает в магазин и получает деньги)
GetSoldUnit() = проданный юнит (типа продать живое существо, типа осла, коровы)
GetBuyingUnit()=GetTriggerUnit() = покупающий торговец (это обычно магазин)
function ChargesItem takes integer charges returns integer
    local integer count_charges
    if ( charges > 0 ) then // обычные итемы не имеют зарядов (равен нулю).
        set count_charges = charges //Поэтому приравниваем к единице
    else
        set count_charges = 1 // остальные итемы, имеющие заряды. у них приравнивают к зарядам
    endif
    return count_charges
endfunction

function TypeofItems takes integer Id returns integer
    local integer i = LoadInteger(udg_Hash, Id, 66)
    if i == 0 then
        set i = Id
    endif
    return i
endfunction

function Trig_PawnItem_Conditions takes nothing returns boolean
return not LoadBoolean(udg_Hash, GetHandleId(GetBuyingUnit()), udg_sell_item) //проверяем может ли магазин продавать
endfunction

function Trig_PawnItem_Actions takes nothing returns nothing
    local unit market = GetBuyingUnit() //магазин
    local integer id_market = GetHandleId(GetBuyingUnit()) //ид-хэндл магазина
     
    local integer id_item = TypeofItems(GetItemTypeId(GetSoldItem())) //тип итема
    local integer charges = ChargesItem(GetItemCharges(GetSoldItem())) //кол-во зарядов
    
    local integer key1 = ( id_item + udg_CountOfSlots ) //подсчитывает ключ для логическую busy_slot
    local boolean busy_slot = LoadBoolean(udg_Hash, id_market, key1) // занимает ли данный тип предмета магазин
    local integer count = LoadInteger(udg_Hash, id_market, udg_CountOfSlots) //кол-во занятых слотов
    //local boolean sell_item = LoadBoolean(udg_Hash, id_market, udg_sell_item) //можно ли продавать в магазин
    
    local integer stock
    local integer max_stock
    local integer i = 0
    local integer a = 0
    local integer MaxIT
    local boolean can_set = false //логическая определяет устанавить ли изменения с данным типом предмета (в конце будет проверка)
    call BJDebugMsg( "|cFFFFA500===========|r" )
    call BJDebugMsg( "|cFFCDA54Bзакладываемый предмет в рынок |cFFFFDC00" + GetItemName(GetSoldItem()) + "|r" ) 
    
    if (count >= 0 and count <= 11) then // ЕСЛИ у магазина есть свободные ячейки, то ...
         

        
        
        // проверяем, данный тип у предмета есть в магазине или нет.
        if ( busy_slot ) then // Если есть, то выгружаем из хэша и складываем все
            // загружаем стэки из хэша (стэк - кол-во штук итемов в магазине)
            set stock = LoadInteger(udg_Hash, id_market, id_item)
            call BJDebugMsg( "|cFF12FC40" + I2S(stock) + " - кол-во стэков из хэша" + "|r" )
            // складываем заряды и стэки в переменную max_stock
            set max_stock = ( charges + stock )
            call BJDebugMsg( "|cFFFFA500" + I2S(charges) + " кол-во зарядов Sold Item|r " + "+ " + "|cFF12FC40" + I2S(stock) + " кол-во стэков у предмета в магазине (из хэша)|r " + "= " + I2S(max_stock) )
            
            
            // сохраняем стэк в хэш
            call SaveInteger( udg_Hash, id_market, id_item, max_stock)
            set MaxIT = max_stock
            set can_set = true
            
        elseif ( (not busy_slot) and (count < 11) ) then //Иначе, если нет в магазине, то создаем новый (ничего не выгружая).
        
                // кол-во занятых ячеек в магазине стало больше на одну
                set count = ( count + 1 )
                // сохраняем кол-во занятых ячеек
                call SaveInteger( udg_Hash, id_market, udg_CountOfSlots, count )
                call BJDebugMsg("|cFF00FFFF" + "Кол-во занятых слотов стало больше, теперь их всего " + I2S(count) + "|r")
                //сохраняем какой-тип сохраняем
                call SaveInteger( udg_Hash, id_market, udg_TypeOfItem + count, id_item )
            
                // сохранить кол-во стэков предмета в магазине
                call SaveInteger( udg_Hash, id_market, id_item, charges )
                set MaxIT = charges
                set can_set = true
                call BJDebugMsg( "|cFFFFA500" + I2S(charges) + " кол-во зарядов Sold Item|r ")
                
                call SaveBoolean( udg_Hash, id_market, key1, true ) // сохраняем то, что юнит обладает данным типом
                call SaveInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item, count ) //сохраняем по типу номер слота
                
                
        endif
        
        if (can_set) then
            
            // удаляем все итемы из магазина
            loop
                exitwhen i > 12
                call RemoveItemFromStock( market, LoadInteger( udg_Hash, id_market, udg_TypeOfItem + i ))
                set i = i+1
            endloop
            
            set i = 0
            // добавляем все итемы обратно
            loop
                exitwhen i > 11
                set id_item = LoadInteger( udg_Hash, id_market, udg_TypeOfItem + i )
                if id_item > 0 then //проверяем, что ячейка магазина не пустует
                    set a = a + 1
                    set stock = LoadInteger(udg_Hash, id_market, id_item)
                    call SaveInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item, a ) //сохраняем по типу номер слота
                    call AddItemToStock( market, id_item, stock, stock )
                endif
                set i=i+1
            endloop

        endif
        
        // идет еще следующая проверка. Проверяет, стало ли занятых ячеек равно 11. Если да. то нужно ограничить
        if ( count == 11 ) then
            // если все ячейки заполнены. то удаляем способность продажа предметов, и никто больше не сможет продавать
                    
            // запоминаем, что способность удалена
            call SaveBoolean( udg_Hash, id_market, udg_sell_item, true )
            //call TriggerSleepAction(1.00) //очень нужна задержка, а то способность вместе с итемами пропадает
            call UnitRemoveAbility( market, 'Apit')
            call BJDebugMsg( "способность удалена, теперь нельзя продавать предметы" )
        endif
        
    endif
    set market = null
endfunction

//===========================================================================
function InitTrig_PawnItem takes nothing returns nothing
    set gg_trg_PawnItem = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_PawnItem, EVENT_PLAYER_UNIT_PAWN_ITEM )
    call TriggerAddCondition( gg_trg_PawnItem, Condition( function Trig_PawnItem_Conditions ) )
    call TriggerAddAction( gg_trg_PawnItem, function Trig_PawnItem_Actions )
endfunction
триггер SellItem (Покупка итема)
GetSellingUnit()=GetTriggerUnit() =продающий торговец (в данном случае магазин продает нам)
GetSoldUnit() = проданный юнит (типа продать живое существо, типа осла, коровы)
GetBuyingUnit() = покупающий торговец (это наш герой отдает денюшку, а сам получает артефает или лошадь)
function Trig_SellItem_Actions takes nothing returns nothing
    local unit market = GetSellingUnit()
    local integer id_market = GetHandleId(market) // номер хэндла магазина
    
    local integer id_item = GetItemTypeId(GetSoldItem()) //тип итема
    local integer charges = LoadInteger(udg_Hash, udg_ChargesTypeOfItem, id_item) //стандартное кол-во зарядов в одном артефакте
    local integer stock = LoadInteger(udg_Hash, id_market, id_item) //общее кол-во зарядов этого типа
    local integer count_items = LoadInteger(udg_Hash, id_market, udg_CountOfSlots) //кол-во занятых слотов в магазине
    local integer key1 = (id_item + udg_CountOfSlots) //ключ данного типа
    local boolean busy_slot = LoadBoolean(udg_Hash, id_market, key1) // занимает ли данный тип предмета магазин
    local boolean sell_item = LoadBoolean(udg_Hash, id_market, udg_sell_item) //можно ли продавать в магазин
    
    local integer min_stock
    
    local integer min_count_items
    local integer i = 1
    local integer a = 0
    local integer key2
    local integer count_stock
    local boolean add_change = false
    call BJDebugMsg( "|cFFFFFF00===========|r" )
    call BJDebugMsg( "|cFFFF0000Купленный предмет в магазине |cFFFFDC00" + GetItemName(GetSoldItem()) + "|r" ) 
    call BJDebugMsg( "|cFF12FC40Stocks = " + I2S(stock) + " - кол-во стэков из хэша" )
    call BJDebugMsg( "|cFFFFA500Charges = " + I2S(charges) + " - кол-во отнимаемых зарядов у итема (загружается из базы данных типа итема)" + "|r" )
    
    set min_stock = stock - charges // вычитаем, тут еще проверку надо что если зарядов больше стэков
    call BJDebugMsg( "Кол-во зарядов = |cFF12FC40Stocks|r - |cFFFFA500Charges|r = "  + I2S(stock) + " - " + I2S(charges) + " = " + I2S(min_stock))
    
    
    
    
    if ( busy_slot and count_items > 0 and count_items <= 11 ) then
        // сохраняем кол-во стэков
        call SaveInteger( udg_Hash, id_market, id_item, min_stock )
    
        if (min_stock==0) then //если кол-во стэков стало равно ноль (если зарядов совсем нет), то удаляем итем
            
            set min_count_items = count_items - 1 //перерасчет кол-во итемов
            set add_change = true //ВНИЗУ ИДЕТ ПОЛНОЕ вычищение ИТЕМА из магазина
            
            call BJDebugMsg( "|cFF00FFFFКол-во занятых ячеек в магазине поубавилось: было = " + I2S(count_items) + ", но стало = " + I2S(min_count_items)+" |r" )
            // сохраняем кол-во занимаемых ячеек
            call SaveInteger( udg_Hash, id_market, udg_CountOfSlots, min_count_items )
            
            set key2 = (udg_TypeOfItem+LoadInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item ))
            
            call SaveInteger( udg_Hash, id_market, key2, 0 ) //сохраняем что такого типа нет
            //call BJDebugMsg( "есть ли тип: " + I2S(LoadInteger( udg_Hash, id_market, key2)) )
            call SaveBoolean( udg_Hash, id_market, key1, false ) // запоминаем в хэш что данного типа предмета больше нет
            call RemoveItemFromStock( market, id_item)
            
            // проверяем ячейки магазина
            if ( count_items == 11 and min_count_items == 10 ) then // если ячейка освободилась, то добавляем способность
            
                call BJDebugMsg( "Свободных слотов в магазине было 11, стало 10. Ячейка освободилась" )
                if ( sell_item ) then
                    call UnitAddAbility( market,'Apit' )
                    
                    call BJDebugMsg( "НЕЛЬЗЯ БЫЛО ПРОДАВАТЬ - теперь МОЖНО" )
                    // запоминаем, что способность больше не удалена
                    call SaveBoolean( udg_Hash, id_market, udg_sell_item, false )
                    
                endif
            endif
        elseif (min_stock > 0) then //если произошли изменения с кол-вом стэков (стало или больше или меньше), то изменяем число

            // сохраняем кол-во занимаемых ячеек
            call BJDebugMsg( "итог " + I2S(min_stock) )
            set add_change = true
            
            
            //call AddItemToStock( market, id_item, min_stock, min_stock )
        endif
    endif
    

    
    if add_change then

        set i = 0 
        // удаляем все итемы из магазина
        loop
            exitwhen i > 12
            call RemoveItemFromStock( market, LoadInteger( udg_Hash, id_market, udg_TypeOfItem + i ))
            set i = i+1
        endloop
    
        set i = 0
    
        loop
            exitwhen i>count_items
            set id_item = LoadInteger( udg_Hash, id_market, (udg_TypeOfItem+i) )
            if id_item > 0 then
                set a = a + 1
                set stock = LoadInteger(udg_Hash, id_market, id_item)
                call SaveInteger( udg_Hash, id_market, (udg_TypeOfItem+a), id_item )
                call SaveInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item, a ) //сохраняем по типу номер слота
                call AddItemToStock( market, id_item, stock, stock )
            endif

            set i = i+1
        endloop
    endif
    
    set market = null

endfunction

//===========================================================================
function InitTrig_SellItem takes nothing returns nothing
    set gg_trg_SellItem = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_SellItem, EVENT_PLAYER_UNIT_SELL_ITEM )
    call TriggerAddAction( gg_trg_SellItem, function Trig_SellItem_Actions )
endfunction
Необычные идеи:
  1. Когда забьете все слоты (максимум 11 штук, можно сделать 12), удаляете способность магазина "Лавка: продать итемы (Apit)". Тогда в магазин нельзя продать, но вы сможете у магазина что-нибудь купить. Когда слот какой-нибудь освободиться, вы сможете обратно добавить способность. Недостаток: когда у вас забит магазин, не получится в один слот одинаковые вещи складировать: типа рубашка + рубашка = 2 рубашки (потому что у магазина способность удалена, и он не может принять).
  2. Можно было и не запрещать продажу при забитом магазине. Надо было проверять, что за предмет продается, есть ли такой в магазине. Если есть, складываем, иначе, если нет, пробуем предотвратить продажу.
проблема
Пробовал выкидывать в момент продажи
выкидывает под ногами, но ссыпаются деньги от продажи. Короче продажа как-бы произошла, но итем как лежит под ногами. Не знаю, как отменить, чтобы деньги не ссыпались.
Пробовал ловить приказ, проблема еще та: надо понять какой приказ, как отследить предмет, и что в этот магазин продается. (Будет это реализовано, не знаю)
  1. Или можно вообще не запрещать. Использовать бесконечные ячейки с бесконечными листами. Можно было переворачивать листы.
  2. Использовать аукцион (можно продавать вещицу, и между игроками устраивать ставки).
  3. Можно попробовать изменять стоимость. Тогда на каждый оригинал нужно делать копию, как с руной. Или использовать MemoryHuck
  4. можно использовать дабл-клик. повторную покупку таймером отслеживайте (проверяете сколько секунд прошло с первой покупкой. Если таймер через 2 секунды проходит, то дабл-клик не работает). Короче что хочу сказать, можно двойным нажатием купить все зелья этого типа.
остаются проблемы с зарядами (не доработал, доработаю попозже)
  • если покупаешь 1 итем, скажем тот же жезл молнии. Вам в инвентарь героя прибавляю +3 заряда, а в самом магазине вычли -1. А должны вычесть -3.
  • Вот забыл с остатком поработать. вот например, у жезла = 3 заряда. За каждую покупку будет снимать 3. А если я продам в магазин 4 шт, а потом будут выкупать предметы обратно. при первой покупке получу 3 заряда, останется 1. При второй покупке должен получить +1, из-за поля Кол-во зарядов прибавит +3 (а надо +1). Надо тут отрегулировать с остатками .
  • Также вытекает и проблема с ценой. В магазине при заряде +3, и при заряде +1 стоимость одинаковая. Жезл молнии 3 заряда = 150 стоимость; 1 заряд = 150 стоимость (а должен быть 1 заряд 50 стоимость)
`
ОЖИДАНИЕ РЕКЛАМЫ...
0
4
6 лет назад
0
Интересно...
2
27
6 лет назад
Отредактирован MpW
2
Немного переделал карту.
при инициализации пишем базу данных
Теперь не нужно всем писать, а только предметам с зарядами или с рунами. В остальных случаях вернет 0 (или 1).
код
// функция SaveR2I
// Сохраняем id копии по id оригинала (короче идишник оригинала - ключ. Из нее будем доставать нужный тип копии). 
// Если итем не имеет копии, то вернет 0. Значит вернет id оригинал.
// Определяет какой тип итема будет создан в ячейке магазина (руна или оригинал). Если копии нет, то будет создан оригинал. 

function SaveR2I takes integer original, integer rune returns nothing
    call SaveInteger(udg_Hash, original, 66, rune) //66 - в качестве ключа
endfunction

// функция SaveR2Icharges
// Сохраняет связь id оригинала с id-копиями. Делано для сокращения части кода.
// У итемов с зарядами могут быть несколько копии, связано это с ценами. 
// У зарядов есть своя цена, в инвентаре героя 1 заряд может стоить 50 золота, 2 заряда 100, 3 заряда 150.
// В магазине заряды никак не связаны с ценой, тут она всегда одна, постоянна. 1 заряд или 2 заряда = всегда будут стоить 50 золота 
// В варкрафте у предметов есть такое поле "Характеристика - количество зарядов". При покупке или создании в инвентаре героя создается это число зарядов.
// Но в магазине снимается 1 стэк (лучше правильно его так называть, а не заряд), а не указанное число. Он может перезаряжаться. 
// Было придумано так, что покупаешь указанное число зарядов. И с магазина это число снимается.
// Чтобы было понятно, у меня система такая как если покупаешь упаковку конфет или пояс гранат (стэки), внутри определенное число конфет или гранат (заряды).
//Если у заложенного итема count_charges > кол-во зарядов в РО, то ставить самый максимальный ценник. Иначе ставим требуемый.
// Для красоты добавляется несколько копии с разными ценами, и разным число указанных в "Редакторе Объектов" зарядов. При продаже наследуют charge.
// ВАЖНО: для правильной записи необходимо чтобы равкоды копии, заряды на одну единичку +1 отличались (и цены тоже)

function SaveR2Icharges takes integer original, integer rune, integer start_charges returns nothing
    local integer i = 0
    
    loop
        exitwhen i == start_charges
        call SaveInteger(udg_Hash, rune+i, 666, original) //Нужно связать ценники с одним типом. Это нужно для проверки, что занят ли он в магазине, также возвращает тип оригинала.
        call SaveInteger(udg_Hash, original, 100 + i+1, rune + i )
        //call BJDebugMsg( "i: " + I2S(i) )
        set i = i + 1
    endloop
    call SaveInteger(udg_Hash, udg_ChargesTypeOfItem, original, start_charges)
    
endfunction

function Trig_data_Actions takes nothing returns nothing
    call TriggerSleepAction( 2 )
    
    //SaveR2I(original, rune)
    call SaveR2I('I000', 'I004') //рецепт когти воина
    call SaveR2I('I001', 'I005') //боевые когти
    call SaveR2I('I002', 'I006') //туфли ловкости
    
    //SaveR2Icharges(original, rune, charge)
    call SaveR2Icharges('wild', 'I007', 1) //амулет леса х1 заряд
    call SaveR2Icharges('whwd', 'I008', 3) //духи-целители х3 заряда I008-I009-I00:
    call SaveR2Icharges('wlsd', 'I00;', 3) //жезл-молнии x3 заряда I00; - I00< - I00=
    
endfunction

//===========================================================================
function InitTrig_data takes nothing returns nothing
    set gg_trg_data = CreateTrigger(  )
    call TriggerAddAction( gg_trg_data, function Trig_data_Actions )
endfunction
триггер PawnItem

// функция LoadR2I
// Загружает из хэш-таблицы id руны с помощью ключа original, где записан id подлинного итема. 
// Определяет какой тип итема будет создан в ячейке магазина (руна или оригинал). Если копии нет, то будет создан оригинал. 

function LoadR2I takes integer original returns integer
    return LoadInteger(udg_Hash, original, 66) //66 - в качестве ключа
endfunction

function LoadTypeRune takes item it, integer charges returns integer
    //local integer id_market = GetHandleId(market)
    local integer id_item = GetItemTypeId(it) //продаем предмет-оригинал
    local integer k = LoadInteger(udg_Hash, udg_ChargesTypeOfItem, id_item) //кол-во зарядов в одном стэке, или кол-во ценников
    
    //local integer stock = LoadInteger(udg_Hash, id_market, id_item)
    
    local integer ID 
    
    if GetItemType(it) == ITEM_TYPE_CHARGED then 
        if charges >= k then
            set ID = LoadInteger(udg_Hash, id_item, 100 + k )
        elseif charges < k then
            set ID = LoadInteger(udg_Hash, id_item, 100 + charges )
        endif
    else
        set ID = LoadR2I(id_item)
        if ID == 0 then
            set ID = id_item
        endif
    endif
    return ID
endfunction

function ChargesItem takes integer charges returns integer
    local integer count_charges
    if ( charges > 0 ) then // остальные итемы, имеющие заряды. у них приравнивают к зарядам
        set count_charges = charges 
    else // обычные итемы не имеют зарядов (равен нулю).
        set count_charges = 1 //Поэтому приравниваем к единице
    endif
    return count_charges
endfunction


function Trig_PawnItem_Conditions takes nothing returns boolean
return not LoadBoolean(udg_Hash, GetHandleId(GetBuyingUnit()), udg_sell_item) //проверяем может ли магазин продавать
endfunction

function Trig_PawnItem_Actions takes nothing returns nothing
    local unit market = GetBuyingUnit() //магазин
    local integer id_market = GetHandleId(GetBuyingUnit()) //ид-хэндл магазина
     
    local integer id_item = GetItemTypeId(GetSoldItem()) //тип итема  = продаем итем-оригинал
    local integer id_rune //тип руны - это то, что закладываем в магазин. Если копии нет, вернет оригинал id_item
    
    local integer charges = ChargesItem(GetItemCharges(GetSoldItem())) //кол-во зарядов оригинала
    
    local integer key1 = ( id_item + udg_CountOfSlots ) //подсчитывает ключ для логической busy_slot
    local boolean busy_slot = LoadBoolean(udg_Hash, id_market, key1) // занимает ли данный тип предмета магазин
    local integer count = LoadInteger(udg_Hash, id_market, udg_CountOfSlots) //кол-во занятых слотов
    //local boolean sell_item = LoadBoolean(udg_Hash, id_market, udg_sell_item) //можно ли продавать в магазин
    
    local integer stock
    local integer max_stock
    local integer i = 0
    local integer a = 0
    local integer MaxIT
    local boolean can_set = false //логическая определяет устанавить ли изменения с данным типом предмета (в конце будет проверка)
    call BJDebugMsg( "|cFFFFA500===========|r" )
    call BJDebugMsg( "|cFFCDA54Bзакладываемый предмет в рынок |cFFFFDC00" + GetItemName(GetSoldItem()) + "|r" ) 
    
    if (count >= 0 and count <= 11) then // ЕСЛИ у магазина есть свободные ячейки, то ...
         
        // проверяем, данный тип у предмета есть в магазине или нет.
        if ( busy_slot ) then // Если есть, то выгружаем из хэша и складываем все
            // загружаем стэки из хэша (стэк - кол-во штук итемов в магазине)
            set stock = LoadInteger(udg_Hash, id_market, id_item)
            call BJDebugMsg( "|cFF12FC40" + I2S(stock) + " - кол-во стэков из хэша" + "|r" )
            // складываем заряды и стэки в переменную max_stock
            set max_stock = ( charges + stock )
            call BJDebugMsg( "|cFFFFA500" + I2S(charges) + " кол-во зарядов Sold Item|r " + "+ " + "|cFF12FC40" + I2S(stock) + " кол-во стэков у предмета в магазине (из хэша)|r " + "= " + I2S(max_stock) )
             
            //достаем номер ячейки (достаем по id оригинала, так как удобнее)
            set a = LoadInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item )
            //должны достать идишник будущей копии (у зарядных айтемов несколько копии, поэтому может достать одну из них. У обычных либо одна копия, либо вообще нет копии, вернет оригинал)
            set id_rune = LoadTypeRune(GetSoldItem(), max_stock)
 
            //обязательно должны удалить с рынка данный тип, иначе на него не сохранится ссылка, так как на этот номер, на эту ячейку перезапишут новый идишник
            call RemoveItemFromStock( market, LoadInteger( udg_Hash, id_market, udg_TypeOfItem + a ))

            //пересохраняем типы итема (сохраняем по номеру ячейки, потом перебирать будем)
            call SaveInteger( udg_Hash, id_market, (udg_TypeOfItem+a), id_rune )
            // сохраняем стэк в хэш (сохраняем по id оригинала - id_item)
            call SaveInteger( udg_Hash, id_market, id_item, max_stock)
            set MaxIT = max_stock
            set can_set = true
            
        elseif ( (not busy_slot) and (count < 11) ) then //Иначе, если нет в магазине, то создаем новый (ничего не выгружая).
        
                // кол-во занятых ячеек в магазине стало больше на одну
                set count = ( count + 1 )
                // сохраняем кол-во занятых ячеек
                call SaveInteger( udg_Hash, id_market, udg_CountOfSlots, count )
                call BJDebugMsg("|cFF00FFFF" + "Кол-во занятых слотов стало больше, теперь их всего " + I2S(count) + "|r")
                
                
                //должны достать идишник будущей копии (у зарядных айтемов несколько копии, поэтому может достать одну из них. У обычных либо одна копия, либо вообще нет копии, вернет оригинал)
                set id_rune = LoadTypeRune(GetSoldItem(), charges)
                //сохраняем какой-тип сохраняем (сохраняем по номеру ячейки, потом перебирать будем)
                call SaveInteger( udg_Hash, id_market, udg_TypeOfItem + count, id_rune )
                if id_item != id_rune and id_rune > 0 then
                    call BJDebugMsg( "тип руны: " + I2S(id_rune))
                elseif id_rune == 0 then
                    call BJDebugMsg( "У этого типа нет руны. Тип руны = 0")
                endif
                // сохранить кол-во стэков предмета в магазине
                call SaveInteger( udg_Hash, id_market, id_item, charges )
                set MaxIT = charges
                set can_set = true
                call BJDebugMsg( "|cFFFFA500" + I2S(charges) + " кол-во зарядов Sold Item|r ")
                
                call SaveBoolean( udg_Hash, id_market, key1, true ) // сохраняем то, что юнит обладает данным типом
                call SaveInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item, count ) //сохраняем по типу номер слота
                
                
        endif
        
        if (can_set) then
            set i = 0
            // удаляем все итемы из магазина
            loop
                exitwhen i > 12
                set id_rune = LoadInteger( udg_Hash, id_market, udg_TypeOfItem + i ) //загружаем ид руны и перебираем по номеру ячеек i
                call RemoveItemFromStock( market, id_rune)
                set i = i+1
            endloop
            
            set a = 0
            set i = 0
            // добавляем все итемы обратно
            loop
                exitwhen i > count
                set id_rune = LoadInteger( udg_Hash, id_market, udg_TypeOfItem + i ) //загружаем ид руны и перебираем по номеру ячеек i
                if id_rune > 0 then //проверяем, что ячейка магазина не пустует (взята переменная id_rune для работы в цикле пусть вас не путает и не смущает что здесь руна должна быть. здесь мб и оригинал)
                    set a = a + 1 //новый номер ячейки (короче новый порядок)
                    set id_item = SelectItem(id_rune) //достаем идишник оригинала (так как заряды сохранены по ид оригинала)
                    set stock = LoadInteger(udg_Hash, id_market, id_item) //загружаем заряды оригинала
                    call BJDebugMsg( "заряды stock: " + I2S(stock))
                    call SaveInteger( udg_Hash, id_market, (udg_TypeOfItem+a), id_rune ) //пересохраняем идишник на новый слот
                    call SaveInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item, a ) //сохраняем по типу номер слота
                    call AddItemToStock( market, id_rune, stock, stock ) //добавляем в магазин
                endif
                set i=i+1
            endloop

        endif
        
        // идет еще следующая проверка. Проверяет, стало ли занятых ячеек равно 11. Если да. то нужно ограничить
        if ( count == 11 ) then
            // если все ячейки заполнены. то удаляем способность продажа предметов, и никто больше не сможет продавать
                    
            // запоминаем, что способность удалена
            call SaveBoolean( udg_Hash, id_market, udg_sell_item, true )
            //call TriggerSleepAction(1.00) //очень нужна задержка, а то способность вместе с итемами пропадает
            call UnitRemoveAbility( market, 'Apit')
            call BJDebugMsg( "способность удалена, теперь нельзя продавать предметы" )
        endif
        
    endif
    set market = null
endfunction

//===========================================================================
function InitTrig_PawnItem takes nothing returns nothing
    set gg_trg_PawnItem = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_PawnItem, EVENT_PLAYER_UNIT_PAWN_ITEM )
    call TriggerAddCondition( gg_trg_PawnItem, Condition( function Trig_PawnItem_Conditions ) )
    call TriggerAddAction( gg_trg_PawnItem, function Trig_PawnItem_Actions )
endfunction
триггер SellItem

function SelectItem takes integer id_rune returns integer
local integer id = LoadInteger(udg_Hash, id_rune , 666)
if id == 0 then
    set id = LoadInteger(udg_Hash, id_rune , 66)
    if id == 0 then
        set id = id_rune
    endif
endif

return id
endfunction

function TypeOfItems2 takes item rune returns integer
    //local integer id_market = GetHandleId(market) //ид магазина
    local integer id_item = LoadInteger(udg_Hash, GetItemTypeId(rune), 666) //загружаем идишник оригинала от зарядовых
    
    
    if id_item == 0 then //Если ничего не записано, вернет 0. Значит, ничего в базе данных не записано. Типа это не зарядовые итемы. Ищем следующие 
        set id_item = LoadR2I(id_item) //загружаем идишник оригинала от обычной руны
        if id_item == 0 then //Если опять вернет ноль, значит это обычный итем
            set id_item = GetItemTypeId(rune)
        endif
    endif
    return id_item
endfunction

function ChargesTypeOfItem takes integer id_item returns integer
local integer k = LoadInteger(udg_Hash, udg_ChargesTypeOfItem, id_item)
if k <= 0 then
    set k = 1 //если ничего не записано, то вернет ноль. значит надо записать 1. Так как беззарядовых быть не может, иначе из магазина не снять будет стэк
endif

return k

endfunction

function Trig_SellItem_Actions takes nothing returns nothing
    local unit market = GetSellingUnit()
    local integer id_market = GetHandleId(market) // номер хэндла магазина
    
    local integer id_rune = GetItemTypeId(GetSoldItem()) //тип итема (или копии), ведь в магазинах могут быть изначально заложены копии. Если копии нет, то там будет оригинал.
    local integer id_item = TypeOfItems2(GetSoldItem())//нам нужен ид оригинал, так как на него записаны многие вещи
    
    local integer charges = ChargesTypeOfItem(id_item) //стандартное кол-во зарядов в одном артефакте
    local integer stock = LoadInteger(udg_Hash, id_market, id_item) //общее кол-во зарядов этого типа
    local integer count_items = LoadInteger(udg_Hash, id_market, udg_CountOfSlots) //кол-во занятых слотов в магазине
    local integer key1 = (id_item + udg_CountOfSlots) //ключ данного типа
    local boolean busy_slot = LoadBoolean(udg_Hash, id_market, key1) // занимает ли данный тип предмета магазин
    local boolean sell_item = LoadBoolean(udg_Hash, id_market, udg_sell_item) //можно ли продавать в магазин
    
    local integer min_stock
    
    local integer min_count_items
    local integer i = 1
    local integer a = 0
    
    local integer key2
    local integer count_stock
    local boolean add_change = false
    call BJDebugMsg( "|cFFFFFF00===========|r" )
    call BJDebugMsg( "|cFFFF0000Купленный предмет в магазине |cFFFFDC00" + GetItemName(GetSoldItem()) + "|r" ) 
    call BJDebugMsg( "|cFF12FC40Stocks = " + I2S(stock) + " - кол-во стэков из хэша" )
    call BJDebugMsg( "|cFFFFA500Charges = " + I2S(charges) + " - кол-во отнимаемых зарядов у итема (загружается из базы данных типа итема)" + "|r" )
    
    if stock>charges then
        set min_stock = stock - charges
    else//if LoadInteger(udg_Hash, udg_ChargesTypeOfItem, id_item) > 0 then
        set min_stock = stock - stock //ModuloInteger(stock, charges)
        //call SetItemCharges(GetSoldItem(), stock) //подправляем на нужное число зарядов. А то выдает указанное кол-во зарядов в РО. Если в магазине заряда становится на 1 меньше, то при создании выдает указанное кол-во в РО
    endif
    
    call BJDebugMsg( "Кол-во зарядов = |cFF12FC40Stocks|r - |cFFFFA500Charges|r = "  + I2S(stock) + " - " + I2S(charges) + " = " + I2S(min_stock))
    
    if ( busy_slot and count_items > 0 and count_items <= 11 ) then
        // сохраняем кол-во стэков
        call SaveInteger( udg_Hash, id_market, id_item, min_stock )
    
        if (min_stock==0) then //если кол-во стэков стало равно ноль (если зарядов совсем нет), то удаляем итем
            
            set min_count_items = count_items - 1 //перерасчет кол-во итемов
            set add_change = true //ВНИЗУ ИДЕТ ПОЛНОЕ вычищение ИТЕМА из магазина
            
            call BJDebugMsg( "|cFF00FFFFКол-во занятых ячеек в магазине поубавилось: было = " + I2S(count_items) + ", но стало = " + I2S(min_count_items)+" |r" )
            // сохраняем кол-во занимаемых ячеек
            call SaveInteger( udg_Hash, id_market, udg_CountOfSlots, min_count_items )
            

            //достаем номер ячейки
            set a = LoadInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item )
            
            set key2 = (udg_TypeOfItem+a)
            
            //в базу пишем, что такого типа нет
            call SaveInteger( udg_Hash, id_market, key2, 0 ) //хранится здесь тип, пересохраняем тип итема, сохраняем то, что такого типа нет = 0
            call SaveBoolean( udg_Hash, id_market, key1, false ) // запоминаем в хэш что данного типа предмета больше нет (типа не занят)
            
            // проверяем ячейки магазина
            if ( count_items == 11 and min_count_items == 10 ) then // если ячейка освободилась, то добавляем способность
            
                call BJDebugMsg( "Свободных слотов в магазине было 11, стало 10. Ячейка освободилась" )
                if ( sell_item ) then
                    call UnitAddAbility( market,'Apit' )
                    
                    call BJDebugMsg( "НЕЛЬЗЯ БЫЛО ПРОДАВАТЬ - теперь МОЖНО" )
                    // запоминаем, что способность больше не удалена
                    call SaveBoolean( udg_Hash, id_market, udg_sell_item, false )
                    
                endif
            endif
        elseif (min_stock > 0) then //если произошли изменения с кол-вом стэков (стало или больше или меньше), то изменяем число

            
            //достаем номер ячейки
            set a = LoadInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item )
            //обязательно должны удалить с рынка данный тип, иначе на него не сохранится ссылка, так как на этот номер, на эту ячейку перезапишут новый идишник
            call RemoveItemFromStock( market, LoadInteger( udg_Hash, id_market, udg_TypeOfItem + a ))
            
            //должны достать новый идишник будущей копии (если это зарядовый)
            set id_rune = LoadTypeRune(GetSoldItem(), min_stock) //+1
            //пересохраняем типы
            call SaveInteger( udg_Hash, id_market, (udg_TypeOfItem+a), id_rune )
        
            // сохраняем кол-во занимаемых ячеек
            call BJDebugMsg( "итог " + I2S(min_stock) )
            set add_change = true
            
            
            //call AddItemToStock( market, id_item, min_stock, min_stock )
        endif
    endif
    
    if add_change then

        set i = 0 
        // удаляем все итемы из магазина
        loop
            exitwhen i > 12
            call RemoveItemFromStock( market, LoadInteger( udg_Hash, id_market, udg_TypeOfItem + i ))
            set i = i+1
        endloop
    
        set i = 0
        set a = 0
        
        // добавляем все итемы обратно
        loop
            exitwhen i>count_items
            set id_rune = LoadInteger( udg_Hash, id_market, (udg_TypeOfItem+i) ) //загружаем ид руны и перебираем по номеру ячеек i
            if id_rune  > 0 then //проверяем, что ячейка магазина не пустует
                set a = a + 1 //новый номер ячейки (короче новый порядок)
                set id_item = SelectItem(id_rune) //достаем идишник оригинала (так как заряды сохранены по ид оригинала)
                set stock = LoadInteger(udg_Hash, id_market, id_item) //загружаем заряды оригинала
                call SaveInteger( udg_Hash, id_market, (udg_TypeOfItem+a),id_rune ) //пересохраняем идишник на новый слот

                call SaveInteger( udg_Hash, id_market, udg_NumberTypeItems + id_item, a ) //сохраняем новый номер слота по идишнику
                //if SaveInteger(udg_Hash, udg_ChargesTypeOfItem, 'whwd', 3)
                call AddItemToStock( market, id_rune, stock+1, stock ) //добавляем в магазин
            endif

            set i=i+1
        endloop
     
    endif
    
    set market = null

endfunction

//===========================================================================
function InitTrig_SellItem takes nothing returns nothing
    set gg_trg_SellItem = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_SellItem, EVENT_PLAYER_UNIT_SELL_ITEM )
    call TriggerAddAction( gg_trg_SellItem, function Trig_SellItem_Actions )
endfunction
требуется
Внимание: при работе с зарядами базу данных заполняете так:
call SaveR2Icharges('whwd', 'I008', 3) духи-целители х3 заряда I008-I009-I00:
SaveR2Icharges(original, rune, charges)
original - итем с зарядами, у него указано кол-во зарядов charges
rune - первая руна, у вас должен быть равкод забит заранее, например:
I008-первая руна I009- вторая руна I00: - третья руна
В остальном ничего сложного нет. Я уже третий раз расписываюсь. В карте написано все.
Казалось бы проще сделать: добавил или удалил. Что тут такого сложного? Но возникали баги.
Возможные баги:
  1. Часто имеет свойство пропадать. При повторном добавлении итемы могли исчезать с рынка. Баг описан и иллюстрирован картинками в этой теме. Пришлось по-другому доделывать - запоминать все айтемы в хэше, и при каждом изменении (добавлении/удалении) сначала все ячейки вычищаешь, а потом заново добавляешь.
  1. В некоторых предметах бывает не правильно складывают/убывают итемы. Например, возьмем, стандартный "Кинжал мага"
пример
Подбираю 3 кинжала
Продаю 2 кинжала, в магазине 2 заряда
Затем заново покупаю обратно 1 кинжал, должно быть остаться 1. Но нам показывает дебаг, что остался 1 заряд. Но в магазине ничего не остается, итем уходит в кулдаун. У меня даже код построен так, что должен очистить все (удалить все итемы), а потом заново вернуть (добавить итемы). А как видим, даже после такого кулдаун не спадает...

Или не стоит у итема не то значение после покупки.
Например, продал 9 зарядов духов-целителей. В магазине стало 9 зарядов.
Нажал, и в результате купил +3. Должно остаться +6, даже счетчик дебагом показывает +6. Но в магазине стало +5.
Вывод: Все это происходит из-за поля "Интервал пополнения".
Во избежания такой фигни рекомендую в продаваемых итемах ставить 0 в поле "интервал пополнения". С чем это связано, мне неизвестно.
Предположение: Короче как видим, кулдаун забирает единицу. Допустим, в магазине +5, покупаешь 2, в магазине должно остаться 3. Но кулдаун забирает 1, и остается 2. Но это предположение, не тестил пока
  1. Это база данных. Третий пункт - это не баг, а ошибка, с которой можете столкнуться вы. Мы заранее составляем базу данных. Дело в том, что в базе данных может быть отсутствует какой-нибудь идишник, и поэтому в игре в магазине не создается итем. Поэтому будьте внимательны.
Дело в том, что у меня так база данных построена, код написан. А то логически в начале написал правильно, потом целый день не мог понять в чем дело.
Покажу пример, который допустил я:
зарядный итем
I008-итем с 1 зарядом цена 200
I009-итем с 2 зарядом цена 400
I00A-итем с 3 зарядом цена 600
казалось бы все правильно, равкод числа на одну единицу меньше. Но как оказалось, где-то допустил ошибку. Берем любой онлайн-калькулятор ASCII , и переводим 10-чную систему, проверяя насколько отличается.
I008=1227894840
I009=1227894841
I00A=1227894849 Тут отличается на целых 8 знаков, короче сбивается база данных
Давайте проверим что же под номером 1227894842 скрывается
1227894842=I00: не удивляйтесь, двоеточие - это тоже символ, в 256-ричной системе по-другому номеруются символы. Просто варкрафт не хочет вписывать этот символ, но мы можем вписать.
Беру копирую итем I00A, и в jngp выскакивает окошко Create Object, и туда копируете 'I00:'
Теперь получается
вот карта
4
27
6 лет назад
Отредактирован MpW
4

13 версия

сделал в 12 версии ошибку, не заметил. Там с обычными рунами, и кое-что еще.
кстати, еще вот такое нашел благодаря Факову тема - хотя это мне никак не помогло, у меня другое
Загруженные файлы
1
32
6 лет назад
Отредактирован Fakov
1
пропадание предметов вот тут пофиксенное выложил
если шо вдруг
2
27
5 лет назад
Отредактирован MpW
2

14 версия

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

В дальнейших планах:
  • попробовать реализовать торговлю между игроками. Что хочу сделать назначать ресурсы за итемов. Без хака нереально изменять ценник
  • использовать дабл-клик. повторную покупку таймером отслеживайте (проверяете сколько секунд прошло с первой покупкой.
Загруженные файлы
Чтобы оставить комментарий, пожалуйста, войдите на сайт.