• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Full-Inventory Crafting System v1.5b

This bundle is marked as useful / simple. Simplicity is bliss, low effort and/or may contain minor bugs.
FICS (Full Inventory Crafting System) is a system that extends possibilities of WarCraft 3 6-slot inventory. This is like the thing, similar to what DotA uses but is more user friendly and also written on native Jass2.

What it can do:

1. Craft recipes:
- with up to 7 components (adds 1 additional component if compared with other recipe craft systems);
- with more than 1 same component per recipe.
2. Sum the charges of same items in one slot even if inventory is full
3. Track many item-related stuff like item cost and all like this.

by Sir Nikolas:The system was rewritten from zero. Recipe searching was drastically optimized.
JASS:
//TESH.scrollpos=-1
//TESH.alwaysfold=0
function FICS_Register takes integer id, integer rune, integer dis, integer gcost, integer lcost returns integer
    set udg_FICS_ItemCount = udg_FICS_ItemCount + 1
    set udg_FICS_Ids[udg_FICS_Length] = id
    set udg_FICS_Ids[udg_FICS_Length + 1] = rune
    set udg_FICS_Ids[udg_FICS_Length + 2] = dis
    set udg_FICS_Num[udg_FICS_Length] = udg_FICS_ItemCount
    set udg_FICS_Num[udg_FICS_Length + 1] = udg_FICS_ItemCount
    set udg_FICS_Num[udg_FICS_Length + 2] = udg_FICS_ItemCount
    set udg_FICS_Length = udg_FICS_Length + 3
    set udg_FICS_Items[udg_FICS_ItemCount * 5] = id
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 1] = rune
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 2] = dis
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 3] = gcost
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 4] = lcost
    return udg_FICS_ItemCount
endfunction

//Сортировка расческой
function FICS_Proceed takes nothing returns nothing
    local boolean end = true
    local integer jump = udg_FICS_Length
    local integer i
    local integer t
    loop
        exitwhen jump == 1 and end
        if jump > 1 then
            set jump = R2I(jump * .802)
        endif
        set end = true
        set i = 0
        loop
            exitwhen i + jump >= udg_FICS_Length
            if udg_FICS_Ids[i] > udg_FICS_Ids[i + jump] then
                set t = udg_FICS_Ids[i]
                set udg_FICS_Ids[i] = udg_FICS_Ids[i + jump]
                set udg_FICS_Ids[i + jump] = t
                set t = udg_FICS_Num[i]
                set udg_FICS_Num[i] = udg_FICS_Num[i + jump]
                set udg_FICS_Num[i + jump] = t
                set end = false
            endif
            set i = i + 1
        endloop
    endloop
endfunction

function FICS_Register7 takes integer result, integer i0, integer i1, integer i2, integer i3, integer i4, integer i5, integer i6 returns nothing
    local integer i = 0
    local integer j
    set udg_FICS_Temp[0] = i0
    set udg_FICS_Temp[1] = i1
    set udg_FICS_Temp[2] = i2
    set udg_FICS_Temp[3] = i3
    set udg_FICS_Temp[4] = i4
    set udg_FICS_Temp[5] = i5
    set udg_FICS_Temp[6] = i6
    set udg_FICS_RecipeCount = udg_FICS_RecipeCount + 1
    //Записываем в Recipes сортированные по невозрастанию индексы
    loop
        if udg_FICS_Temp[i] > 0 then
            if udg_FICS_LastList[udg_FICS_Temp[i]] == 0 or udg_FICS_Recipe[udg_FICS_LastList[udg_FICS_Temp[i]]] != udg_FICS_RecipeCount then
                set udg_FICS_ListCount = udg_FICS_ListCount + 1
                if udg_FICS_LastList[udg_FICS_Temp[i]] == 0 then
                    set udg_FICS_FirstList[udg_FICS_Temp[i]] = udg_FICS_ListCount
                else
                    set udg_FICS_Next[udg_FICS_LastList[udg_FICS_Temp[i]]] = udg_FICS_ListCount
                endif
                set udg_FICS_LastList[udg_FICS_Temp[i]] = udg_FICS_ListCount
                set udg_FICS_Recipe[udg_FICS_LastList[udg_FICS_Temp[i]]] = udg_FICS_RecipeCount
                set udg_FICS_Next[udg_FICS_LastList[udg_FICS_Temp[i]]] = 0
            endif
            set j = i
            loop
                exitwhen j == 0 or udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j - 1] >= udg_FICS_Temp[i]
                set udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j] = udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j - 1]
                set j = j - 1
            endloop
            set udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j] = udg_FICS_Temp[i]
        endif
        exitwhen i == 6
        set i = i + 1
    endloop
    set udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + 7] = result
endfunction

function FICS_Register6 takes integer result, integer i0, integer i1, integer i2, integer i3, integer i4, integer i5 returns nothing
    call FICS_Register7(result, i0, i1, i2, i3, i4, i5, 0)
endfunction

function FICS_Register5 takes integer result, integer i0, integer i1, integer i2, integer i3, integer i4 returns nothing
    call FICS_Register6(result, i0, i1, i2, i3, i4, 0)
endfunction

function FICS_Register4 takes integer result, integer i0, integer i1, integer i2, integer i3 returns nothing
    call FICS_Register5(result, i0, i1, i2, i3, 0)
endfunction

function FICS_Register3 takes integer result, integer i0, integer i1, integer i2 returns nothing
    call FICS_Register4(result, i0, i1, i2, 0)
endfunction

function FICS_Register2 takes integer result, integer i0, integer i1 returns nothing
    call FICS_Register3(result, i0, i1, 0)
endfunction

//Бесполезная штука, в общем-то, но такое тоже возможно
function FICS_Register1 takes integer result, integer i0 returns nothing
    call FICS_Register2(result, i0, 0)
endfunction
JASS:
//TESH.scrollpos=-1
//TESH.alwaysfold=0
constant function Trig_FICS_Effect takes nothing returns string
    return "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl"
endfunction

constant function Trig_FICS_Attach takes nothing returns string
    return "origin"
endfunction

function Trig_FICS_BinSearch takes integer id returns integer
    local integer first = 0
    local integer last = udg_FICS_Length
    local integer mid
    if id >= udg_FICS_Ids[0] and id <= udg_FICS_Ids[last - 1] then
        loop
            exitwhen first >= last
            set mid = (first + last) / 2
            if id <= udg_FICS_Ids[mid] then
                set last = mid
            else
                set first = mid + 1
            endif
        endloop
        if id == udg_FICS_Ids[last] then
            return udg_FICS_Num[last]
        endif
    endif
    return 0
endfunction

function Trig_FICS_Drop_Timer takes nothing returns nothing
    local item it
    loop
        set udg_FICS_DropCount = udg_FICS_DropCount - 1
        //Если предмет существует
        if GetItemTypeId(udg_FICS_Dropped[udg_FICS_DropCount]) != 0 then
            set it = CreateItem(udg_FICS_Items[udg_FICS_DropNum[udg_FICS_DropCount] * 5 + 1], GetWidgetX(udg_FICS_Dropped[udg_FICS_DropCount]), GetWidgetY(udg_FICS_Dropped[udg_FICS_DropCount]))
            if GetItemType(udg_FICS_Dropped[udg_FICS_DropCount]) == ITEM_TYPE_CHARGED then
                call SetItemCharges(it, GetItemCharges(udg_FICS_Dropped[udg_FICS_DropCount]))
            endif
            call SetItemPlayer(it, GetItemPlayer(udg_FICS_Dropped[udg_FICS_DropCount]), false)
            call RemoveItem(udg_FICS_Dropped[udg_FICS_DropCount])
        endif
        exitwhen udg_FICS_DropCount == 0
    endloop
    set it = null
endfunction

function Trig_FICS_DropItem takes item it, integer num returns nothing
    set udg_FICS_Dropped[udg_FICS_DropCount] = it
    set udg_FICS_DropNum[udg_FICS_DropCount] = num
    if udg_FICS_DropCount == 0 then
        call TimerStart(udg_FICS_Timer, .0, false, function Trig_FICS_Drop_Timer)
    endif
    set udg_FICS_DropCount = udg_FICS_DropCount + 1
endfunction

function Trig_FICS_Pick_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local item it = GetManipulatedItem()
    local item it2
    local player p = GetOwningPlayer(u)
    local boolean empty = false
    local boolean bought
    local integer itid = GetItemTypeId(it)
    local integer num = Trig_FICS_BinSearch(itid)
    local integer ls = udg_FICS_FirstList[num]
    local integer i = 0
    local integer j
    local integer k
    local integer l
    local integer m = 6
    if num != 0 and udg_FICS_Flag then
        //Заполняем массив отсортированными по невозрастанию индексами предметов в системе
        set udg_FICS_Temp[0] = num
        set udg_FICS_Temp[7] = -1
        loop
            set it2 = UnitItemInSlot(u, i)
            set k = GetItemTypeId(it2)
            set l = Trig_FICS_BinSearch(k)
            set j = i + 1
            if k == 0 or l == 0 or k != udg_FICS_Items[l * 5] then
                set m = m - 1
                set l = 0
            else
                loop
                    exitwhen j == 0 or udg_FICS_Temp[j - 1] >= l
                    set udg_FICS_Temp[j] = udg_FICS_Temp[j - 1]
                    set udg_FICS_Temp[j + 7] = udg_FICS_Temp[j + 6]
                    set j = j - 1
                endloop
            endif
            set udg_FICS_Temp[j] = l
            set udg_FICS_Temp[j + 7] = i
            exitwhen i == 5
            set i = i + 1
        endloop
        loop
            exitwhen ls == 0
            //Если Recipes является подпоследовательностью Temp, создать предмет
            set j = 0
            set k = 0
            loop
                exitwhen udg_FICS_Temp[j] < udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + k]
                if udg_FICS_Temp[j] == udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + k] then
                    set udg_FICS_Temp[k + 14] = udg_FICS_Temp[j + 7]
                    set k = k + 1
                    if k == 7 or udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + k] == 0 then
                        //Создать предмет по рецепту
                        set k = k + 14
                        loop
                            set k = k - 1
                            exitwhen k < 14
                            if udg_FICS_Temp[k] != -1 then
                                call RemoveItem(UnitItemInSlot(u, udg_FICS_Temp[k]))
                            endif
                        endloop
                        call UnitAddItemById(u, udg_FICS_Items[udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + 7] * 5 + 1])
                        call DestroyEffect(AddSpecialEffectTarget(Trig_FICS_Effect(), u, Trig_FICS_Attach()))
                        set u = null
                        set it = null
                        set it2 = null
                        set p = null
                        return
                    endif
                endif
                exitwhen j == m
                set j = j + 1
            endloop
            set ls = udg_FICS_Next[ls]
        endloop
        set udg_FICS_Flag = false
        set p = GetItemPlayer(it)
        set bought = p == Player(15)
        if bought then
            set itid = udg_FICS_Items[num * 5]
            set p = GetOwningPlayer(u)
        elseif p == GetOwningPlayer(u) then
            set itid = udg_FICS_Items[num * 5]
        else
            set itid = udg_FICS_Items[num * 5 + 2]
        endif
        set i = 0
        if GetItemType(it) == ITEM_TYPE_CHARGED then
            set j = GetItemCharges(it)
            loop
                set it2 = UnitItemInSlot(u, i)
                if GetItemTypeId(it2) == itid then
                    call SetItemCharges(it2, GetItemCharges(it2) + j)
                    exitwhen true
                elseif it2 == null then
                    set empty = true
                endif
                set i = i + 1
                exitwhen i > 5
            endloop
            if i > 5 then
                if bought and not empty then
                    set p = GetOwningPlayer(u)
                    call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + udg_FICS_Items[num * 5 + 3])
                    call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + udg_FICS_Items[num * 5 + 4])
                elseif empty then
					set it = UnitAddItemById(u, itid)
					call SetItemCharges(it, j)
					call SetItemPlayer(it, p, false)
				else
					call Trig_FICS_DropItem(it, num)
                endif
            endif
        else
            loop
                exitwhen UnitItemInSlot(u, i) == null
                set i = i + 1
                exitwhen i > 5
            endloop
            if i <= 5 then
                call SetItemPlayer(UnitAddItemById(u, itid), p, false)
            elseif bought then
                set p = GetOwningPlayer(u)
                call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + udg_FICS_Items[num * 5 + 3])
                call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + udg_FICS_Items[num * 5 + 4])
            else
                call Trig_FICS_DropItem(it, num)
            endif
        endif
        set udg_FICS_Flag = true
        set it2 = null
    endif
    set u = null
    set it = null
    set p = null
endfunction

function Trig_FICS_Drop_Actions takes nothing returns nothing
    local item it = GetManipulatedItem()
    local integer itid = GetItemTypeId(it)
    local integer num = Trig_FICS_BinSearch(itid)
    if num != 0 and (itid == udg_FICS_Items[num * 5] or itid == udg_FICS_Items[num * 5 + 2]) then
        call Trig_FICS_DropItem(it, num)
    endif
    set it = null
endfunction

//===========================================================================
function InitTrig_FICS takes nothing returns nothing
    local trigger pick = CreateTrigger()
    local trigger drop = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(pick, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
        call TriggerRegisterPlayerUnitEvent(drop, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null)
        exitwhen i == 15
        set i = i + 1
    endloop
    call TriggerAddAction(pick, function Trig_FICS_Pick_Actions)
    call TriggerAddAction(drop, function Trig_FICS_Drop_Actions)
    set pick = null
    set drop = null
endfunction
JASS:
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//===========================================================================
function InitTrig_InitDataBase takes nothing returns nothing
    call FICS_Register('I000', 'I001', 'I002', 0, 0)//1, Claws of Justice
    call FICS_Register('I003', 'I004', 'I005', 0, 0)//2, Ogre Gauntlets
    call FICS_Register('I006', 'I007', 'I008', 0, 0)//3, Gloves of Haste
    call FICS_Register('I009', 'I00A', 'I00B', 0, 0)//4, Mana Potion
    call FICS_Register('I00C', 'I00D', 'I00E', 0, 0)//5, Ice Shard

    call FICS_Proceed()

    call FICS_Register7(5, 1, 1, 1, 1, 1, 1, 1)
    call FICS_Register2(3, 2, 1)
endfunction
JASS:
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library FICS {
    #include "cj_types_priv.j"

    #define {
        private EFFECT = "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl"
        private ATTACH = "origin"
    }

    private constant timer T = CreateTimer();
    private item Dropped[ ];
    private int DropNum[ ], Temp[21];
    private int DropCount = 0;
    private int Ids[ ], Num[ ], Length = 0;
    private int Items[500][5], Recipes[256][8];
    private int ItemCount = 0, RecipeCount = 0;
    private int FirstList[ ], LastList[ ];
    private int Recipe[ ], Next[ ], ListCount = 0;
    private bool Flag = true;

    public int Register(int id, int rune, int dis, int gcost, int lcost) {
        ItemCount++;
        Ids[Length] = id;
        Ids[Length + 1] = rune;
        Ids[Length + 2] = dis;
        Num[Length] = ItemCount;
        Num[Length + 1] = ItemCount;
        Num[Length + 2] = ItemCount;
        Length += 3;
        Items[ItemCount][0] = id;
        Items[ItemCount][1] = rune;
        Items[ItemCount][2] = dis;
        Items[ItemCount][3] = gcost;
        Items[ItemCount][4] = lcost;
        return ItemCount;
    }

    //Сортировка расческой
    public void Proceed() {
        int jump = Length;
        bool end = true;
        whilenot jump == 1 && end {
            if jump > 1 { jump = R2I(jump * .802); }
            end = true;
            for (int i = 0; i + jump < Length; i++) {
                if Ids[i] > Ids[i + jump] {
                    int t = Ids[i];
                    Ids[i] = Ids[i + jump];
                    Ids[i + jump] = t;
                    t = Num[i];
                    Num[i] = Num[i + jump];
                    Num[i + jump] = t;
                    end = false;
                }
            }
        }
    }

    private int BinSearch(int id) {
        int first = 0, last = Length;
        if id >= Ids[0] && id <= Ids[last - 1] {
            whilenot first >= last {
                int mid = (first + last) / 2;
                if id <= Ids[mid] {
                    last = mid;
                } else {
                    first = mid + 1;
                }
            }
            if id == Ids[last] { return Num[last]; }
        }
        return 0;
    }

    public void Register7(int result, int i0, int i1, int i2, int i3, int i4, int i5, int i6) {
        #for j(0, 6)
            Temp[j] = i##j;
        #endfor
        RecipeCount++;
        //Записываем в Recipes сортированные по невозрастанию индексы
        for (int i = 0) {
            if Temp[i] > 0 {
                if Temp[i]:LastList == 0 || Temp[i]:LastList:Recipe != RecipeCount {
                    ListCount++;
                    if Temp[i]:LastList == 0 {
                        Temp[i]:FirstList = ListCount;
                    } else {
                        Temp[i]:LastList:Next = ListCount;
                    }
                    Temp[i]:LastList = ListCount;
                    Temp[i]:LastList:Recipe = RecipeCount;
                    Temp[i]:LastList:Next = 0;
                }
                int j = i;
                whilenot j == 0 || Recipes[RecipeCount][j - 1] >= Temp[i] {
                    Recipes[RecipeCount][j] = Recipes[RecipeCount][j - 1];
                    j--;
                }
                Recipes[RecipeCount][j] = Temp[i];
            }
            exitwhen i == 6;
            i++;
        }
        Recipes[RecipeCount][7] = result;
    }

    public void Register6(int result, int i0, int i1, int i2, int i3, int i4, int i5) {
        Register7(result, i0, i1, i2, i3, i4, i5, 0);
    }

    public void Register5(int result, int i0, int i1, int i2, int i3, int i4) {
        Register6(result, i0, i1, i2, i3, i4, 0);
    }

    public void Register4(int result, int i0, int i1, int i2, int i3) {
        Register5(result, i0, i1, i2, i3, 0);
    }

    public void Register3(int result, int i0, int i1, int i2) {
        Register4(result, i0, i1, i2, 0);
    }

    public void Register2(int result, int i0, int i1) {
        Register3(result, i0, i1, 0);
    }

    //Бесполезная штука, в общем-то, но такое тоже возможно
    public void Register1(int result, int i0) {
        Register2(result, i0, 0);
    }

    private void DropItem(item it, int num) {
        DropCount:Dropped = it;
        DropCount:DropNum = num;
        if ++DropCount == 1 {
            TimerStart(T, .0, false, \
                lambda void() {
                    item it;
                    do {
                        DropCount--;
                        if GetItemTypeId(DropCount:Dropped) != 0 {
                            it = CreateItem(Items[DropCount:DropNum][1], /*
                            */ GetWidgetX(DropCount:Dropped), GetWidgetY(DropCount:Dropped));
                            if GetItemType(DropCount:Dropped) == ITEM_TYPE_CHARGED {
                                SetItemCharges(it, GetItemCharges(DropCount:Dropped));
                            }
                            SetItemPlayer(it, GetItemPlayer(DropCount:Dropped), false);
                            RemoveItem(DropCount:Dropped);
                        }
                    } whilenot DropCount == 0;
                }
            );
        }
    }

    private void PickActions() {
        unit u = GetTriggerUnit();
        item it = GetManipulatedItem(), it2;
        player p = GetOwningPlayer(u);
        int itid = GetItemTypeId(it), num = BinSearch(itid);
        int ls = num:FirstList;
        int m = 6;
        if num != 0 && Flag {
            //Заполняем массив отсортированными по невозрастанию индексами предметов в системе
            Temp[0] = num;
            Temp[7] = -1;
            for (int i = 0) {
                it2 = UnitItemInSlot(u, i);
                int k = GetItemTypeId(it2), l = BinSearch(k);
                int j = i + 1;
                if k == 0 || l == 0 || k != Items[l][0] {
                    m--;
                    l = 0;
                } else {
                    whilenot j == 0 || Temp[j - 1] >= l {
                        Temp[j] = Temp[j - 1];
                        Temp[j + 7] = Temp[j + 6];
                        j--;
                    }
                }
                Temp[j] = l;
                Temp[j + 7] = i;
                exitwhen i == 5;
                i++;
            }
            whilenot ls == 0 {
                //Если Recipes является подпоследовательностью Temp, создать предмет
                int j = 0, k = 0;
                whilenot Temp[j] < Recipes[ls:Recipe][k] {
                    if Temp[j] == Recipes[ls:Recipe][k] {
                        Temp[k + 14] = Temp[j + 7];
                        k++;
                        if k == 7 || Recipes[ls:Recipe][k] == 0 {
                            k += 14;
                            whilenot --k < 14 {
                                if Temp[k] != -1 { RemoveItem(UnitItemInSlot(u, Temp[k])); }
                            }
                            UnitAddItemById(u, Items[Recipes[ls:Recipe][7]][1]);
                            DestroyEffect(AddSpecialEffectTarget(EFFECT, u, ATTACH));
                            return;
                        }
                    }
                    exitwhen j == m;
                    j++;
                }
                ls = ls:Next;
            }
            Flag = false;
            p = GetItemPlayer(it);
            bool bought = p == Player(15);
            if bought || p == GetOwningPlayer(u) {
                itid = Items[num][0];
                if bought { p = GetOwningPlayer(u); }
            } else {
                itid = Items[num][2];
            }
            int i = 0;
            bool empty = false;
            if GetItemType(it) == ITEM_TYPE_CHARGED {
                int j = GetItemCharges(it);
                do {
                    it2 = UnitItemInSlot(u, i);
                    if GetItemTypeId(it2) == itid {
                        SetItemCharges(it2, GetItemCharges(it2) + j);
                        break;
                    } elseif it2 == null {
                        empty = true;
                    }
                } whilenot ++i > 5;
                if i > 5 {
                    if bought && !empty {
                        p = GetOwningPlayer(u);
                        SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, /*
                        */ GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + Items[num][3]);
                        SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, /*
                        */ GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + Items[num][4]);
                    } elseif empty {
                        it = UnitAddItemById(u, itid);
                        SetItemCharges(it, j);
                        SetItemPlayer(it, p, false);
                    } else {
                        DropItem(it, num);
                    }
                }
            } else {
                do {
                    exitwhen UnitItemInSlot(u, i) == null;
                } whilenot ++i > 5;
                if i <= 5 {
                    SetItemPlayer(UnitAddItemById(u, itid), p, false);
                } elseif bought {
                    p = GetOwningPlayer(u);
                    SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, /*
                    */ GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + Items[num][3]);
                    SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, /*
                    */ GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + Items[num][4]);
                } else {
                    DropItem(it, num);
                }
            }
            Flag = true;
        }
    }

    private void DropActions() {
        item it = GetManipulatedItem();
        int itid = GetItemTypeId(it), num = BinSearch(itid);
        if num != 0 && (itid == Items[num][0] || itid == Items[num][2]) {
            DropItem(it, num);
        }
    }

    callback onInit() {
        trigger pick = CreateTrigger(), drop = CreateTrigger();
        for (int i = 0) {
            TriggerRegisterPlayerUnitEvent(pick, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null);
            TriggerRegisterPlayerUnitEvent(drop, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null);
            exitwhen i == 15;
            i++;
        }
        TriggerAddAction(pick, function PickActions);
        TriggerAddAction(drop, function DropActions);
    }
}

Keywords:
full, inventory, crafting, fics, duos, bowser499, recipes, items, dota, 7, sir, nikolas, sirnikolas
Contents

Full Inventory Craft System v1.5b (Map)

Reviews
11:30, 3ndth Sep 2015 This resource has been set to Need Fix by BPower. Reason: I could produce a few bugs in the demo map. 1. When buying an item from the shop I recieve that item two times. 2. When picking up a mana potion while having full...

Moderator

M

Moderator

11:30, 3ndth Sep 2015

This resource has been set to Need Fix by BPower.

Reason:
I could produce a few bugs in the demo map.
1. When buying an item from the shop I recieve that item two times.
2. When picking up a mana potion while having full inventory, the potion simply vanishes. ( I guess because you made it a powerup )
3. Buying a mana potion gives a hero 10 charges instead of 5.

Seems like this system still requires some work.
The old review from Bribe is not about the current version, hence outdated.

Update 26 April 2012
Bribe: The originality of an IRS is controversial and I don't see any utility provided to say it brings anything new to the table. This is yet another way to do it, I suppose it's the beauty of open source. I will give it 2.5/5 (Approved).

15th Feb 2012
Bribe: I'm not sure why you need to create 3 different objects here, just to make the recipe work. It seems to add a lot of work to the user, would be nice to explain why a "disabled" and "rune" version of the item are necessary.

You have to use call "SaveItemTypeToDB(0,0,0,0)" to prevent a bug? Well I can get that, but what you should also make sure is to seperate the demo code from the system itself (currently you mixed demo code into your system).

You only need one hashtable for this. For example you can use "-parentKey" and "-childKey" and combinations of the two can make it easy for you to combine what would otherwise be 4 hashtables into 1.
 
You're actually one of the few people that write their code the way I like :)

Few things:
- This is extremely slow due to the lists and searches everywhere :/ (It would be better to have a linked list per item)
-
JASS:
function InitTrig_InitDataBase takes nothing returns nothing
    set gg_trg_InitDataBase = CreateTrigger()
    call TriggerRegisterTimerEvent(gg_trg_InitDataBase,0.,false)
    call TriggerAddAction(gg_trg_InitDataBase,function Trig_InitDataBase_Actions)
endfunction
Should be
JASS:
function InitTrig_InitDataBase takes nothing returns nothing
    call TimerStart(CreateTimer(), 0, false, function Trig_InitDataBase_Actions)
endfunction

- All of the below functions:
JASS:
function NormToRune takes integer niid returns integer
    local integer i = 0 
    local integer tdb = GetISDBItemsTotal()
    
    loop
        exitwhen i > tdb
        if niid == GetNormalType(i) then
            return GetRuneType(i)
        endif
        set i = i + 1
    endloop
    return -1
endfunction

function RuneToNorm takes integer riid returns integer
    local integer i = 0 
    local integer tdb = GetISDBItemsTotal()
    loop
        exitwhen i > tdb
        if riid == GetRuneType(i) then
            return GetNormalType(i)
        endif
        set i = i + 1
    endloop
    return -1
endfunction

function RuneToDis takes integer riid returns integer
    local integer i = 0 
    local integer tdb = GetISDBItemsTotal()
    loop
        exitwhen i > tdb
        if riid == GetRuneType(i) then
            return GetDisabledType(i)
        endif
        set i = i + 1
    endloop
    return -1
endfunction

function DisToRune takes integer diid returns integer
    local integer i = 0 
    local integer tdb = GetISDBItemsTotal()
    loop
        exitwhen i > tdb
        if diid == GetDisabledType(i) then
            return GetRuneType(i)
        endif
        set i = i + 1
    endloop
    return -1
endfunction

function GetItemIndex takes integer iid returns integer
    local integer i = 0 
    local integer tdb = GetISDBItemsTotal()
    loop
        exitwhen i > tdb
        if iid == GetRuneType(i) or iid == GetNormalType(i) or iid == GetDisabledType(i) then
            return i
        endif
        set i = i + 1
    endloop
    return -1
endfunction

function IsItemRune takes integer iType returns boolean
    local integer i = 0
    local integer tdb = GetISDBItemsTotal()
    loop
        exitwhen i > tdb
        if iType == GetRuneType(i) then
            return true
        endif
        set i = i + 1
    endloop
    return false
endfunction
Are horrible.

Instead of using them, you could use your hashtable to store the boolean true for any rune, store the "Dis" or the "Norm", etc...


I like the features.
This totally beats my Recipe Engine :p
 
@Magtheridon96,
I wrote NormToRune, RuneToNorm, DisToRune, DisToRune and GetItemIndex functions almost a year ago o_o
I'll rewrite these, thanks for finding this SLOW issues. You're correct.
Also, I haven't destroyed the trigger with init. Haha.
1.2 soon to be released.

I think that in the future I can improve this system and get it working with only one hashtable.
 
Level 8
Joined
Dec 9, 2005
Messages
523
When you say "like DotA" do you mean the units can get more items even when their slots are full? Because if that's the case then please get rid of their annoying function where the item DROPS when you're full. It should tell us "Inventory is full" when the bought item can't be combined with the current items or stacked.

I lost so many items at shops because of the shitty drop when full system in DotA *rage*
 
Level 3
Joined
May 5, 2011
Messages
19
I set +Claw/Gauntlet/Mana Poition to 50 gold
and "greedisgood 1000"

I buy 6 Orge Gauntlets (300 golds), so i buy more 1 mana potion. (50 golds) = (1000 - 350 = 650 golds left)
The system removed the Mana Poition, but my golds are 650, it isnt 700 (cuz i cant buy anymore, the inventory is full)

Can u make it will return golds when inventory is full?
 
Level 3
Joined
Jan 31, 2012
Messages
42
Updated to v1.5

The system was rewritten from zero. Recipe searching was drastically optimized.
JASS:
globals
    constant timer udg_FICS_Timer = CreateTimer()
    item array udg_FICS_Dropped
    integer array udg_FICS_DropNum
    integer array udg_FICS_Temp    //[21]
    integer array udg_FICS_Items   //[ ][5]
    integer array udg_FICS_Recipes //[ ][8]
    integer array udg_FICS_Ids
    integer array udg_FICS_Num
    integer array udg_FICS_FirstList
    integer array udg_FICS_LastList
    integer array udg_FICS_Recipe
    integer array udg_FICS_Next
    integer udg_FICS_DropCount = 0
    integer udg_FICS_ItemCount = 0
    integer udg_FICS_RecipeCount = 0
    integer udg_FICS_Length = 0
    integer udg_FICS_ListCount = 0
    boolean udg_FICS_Flag = true
endglobals

//===========================================================================
function FICS_Register takes integer id, integer rune, integer dis, integer gcost, integer lcost returns integer
    set udg_FICS_ItemCount = udg_FICS_ItemCount + 1
    set udg_FICS_Ids[udg_FICS_Length] = id
    set udg_FICS_Ids[udg_FICS_Length + 1] = rune
    set udg_FICS_Ids[udg_FICS_Length + 2] = dis
    set udg_FICS_Num[udg_FICS_Length] = udg_FICS_ItemCount
    set udg_FICS_Num[udg_FICS_Length + 1] = udg_FICS_ItemCount
    set udg_FICS_Num[udg_FICS_Length + 2] = udg_FICS_ItemCount
    set udg_FICS_Length = udg_FICS_Length + 3
    set udg_FICS_Items[udg_FICS_ItemCount * 5] = id
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 1] = rune
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 2] = dis
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 3] = gcost
    set udg_FICS_Items[udg_FICS_ItemCount * 5 + 4] = lcost
    return udg_FICS_ItemCount
endfunction

//Сортировка расческой
function FICS_Proceed takes nothing returns nothing
    local boolean end = true
    local integer jump = udg_FICS_Length
    local integer i
    local integer t
    loop
        exitwhen jump == 1 and end
        if jump > 1 then
            set jump = R2I(jump * .802)
        endif
        set end = true
        set i = 0
        loop
            exitwhen i + jump >= udg_FICS_Length
            if udg_FICS_Ids[i] > udg_FICS_Ids[i + jump] then
                set t = udg_FICS_Ids[i]
                set udg_FICS_Ids[i] = udg_FICS_Ids[i + jump]
                set udg_FICS_Ids[i + jump] = t
                set t = udg_FICS_Num[i]
                set udg_FICS_Num[i] = udg_FICS_Num[i + jump]
                set udg_FICS_Num[i + jump] = t
                set end = false
            endif
            set i = i + 1
        endloop
    endloop
endfunction

function FICS_Register7 takes integer result, integer i0, integer i1, integer i2, integer i3, integer i4, integer i5, integer i6 returns nothing
    local integer i = 0
    local integer j
    set udg_FICS_Temp[0] = i0
    set udg_FICS_Temp[1] = i1
    set udg_FICS_Temp[2] = i2
    set udg_FICS_Temp[3] = i3
    set udg_FICS_Temp[4] = i4
    set udg_FICS_Temp[5] = i5
    set udg_FICS_Temp[6] = i6
    set udg_FICS_RecipeCount = udg_FICS_RecipeCount + 1
    //Записываем в Recipes сортированные по невозрастанию индексы
    loop
        if udg_FICS_Temp[i] > 0 then
            if udg_FICS_LastList[udg_FICS_Temp[i]] == 0 or udg_FICS_Recipe[udg_FICS_LastList[udg_FICS_Temp[i]]] != udg_FICS_RecipeCount then
                set udg_FICS_ListCount = udg_FICS_ListCount + 1
                if udg_FICS_LastList[udg_FICS_Temp[i]] == 0 then
                    set udg_FICS_FirstList[udg_FICS_Temp[i]] = udg_FICS_ListCount
                else
                    set udg_FICS_Next[udg_FICS_LastList[udg_FICS_Temp[i]]] = udg_FICS_ListCount
                endif
                set udg_FICS_LastList[udg_FICS_Temp[i]] = udg_FICS_ListCount
                set udg_FICS_Recipe[udg_FICS_LastList[udg_FICS_Temp[i]]] = udg_FICS_RecipeCount
                set udg_FICS_Next[udg_FICS_LastList[udg_FICS_Temp[i]]] = 0
            endif
            set j = i
            loop
                exitwhen j == 0 or udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j - 1] >= udg_FICS_Temp[i]
                set udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j] = udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j - 1]
                set j = j - 1
            endloop
            set udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + j] = udg_FICS_Temp[i]
        endif
        exitwhen i == 6
        set i = i + 1
    endloop
    set udg_FICS_Recipes[udg_FICS_RecipeCount * 8 + 7] = result
endfunction

function FICS_Register6 takes integer result, integer i0, integer i1, integer i2, integer i3, integer i4, integer i5 returns nothing
    call FICS_Register7(result, i0, i1, i2, i3, i4, i5, 0)
endfunction

function FICS_Register5 takes integer result, integer i0, integer i1, integer i2, integer i3, integer i4 returns nothing
    call FICS_Register6(result, i0, i1, i2, i3, i4, 0)
endfunction

function FICS_Register4 takes integer result, integer i0, integer i1, integer i2, integer i3 returns nothing
    call FICS_Register5(result, i0, i1, i2, i3, 0)
endfunction

function FICS_Register3 takes integer result, integer i0, integer i1, integer i2 returns nothing
    call FICS_Register4(result, i0, i1, i2, 0)
endfunction

function FICS_Register2 takes integer result, integer i0, integer i1 returns nothing
    call FICS_Register3(result, i0, i1, 0)
endfunction

//Бесполезная штука, в общем-то, но такое тоже возможно
function FICS_Register1 takes integer result, integer i0 returns nothing
    call FICS_Register2(result, i0, 0)
endfunction
JASS:
constant function Trig_FICS_Effect takes nothing returns string
    return "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl"
endfunction

constant function Trig_FICS_Attach takes nothing returns string
    return "origin"
endfunction

function Trig_FICS_BinSearch takes integer id returns integer
    local integer first = 0
    local integer last = udg_FICS_Length
    local integer mid
    if id >= udg_FICS_Ids[0] and id <= udg_FICS_Ids[last - 1] then
        loop
            exitwhen first >= last
            set mid = (first + last) / 2
            if id <= udg_FICS_Ids[mid] then
                set last = mid
            else
                set first = mid + 1
            endif
        endloop
        if id == udg_FICS_Ids[last] then
            return udg_FICS_Num[last]
        endif
    endif
    return 0
endfunction

function Trig_FICS_Drop_Timer takes nothing returns nothing
    local item it
    loop
        set udg_FICS_DropCount = udg_FICS_DropCount - 1
        //Если предмет существует
        if GetItemTypeId(udg_FICS_Dropped[udg_FICS_DropCount]) != 0 then
            set it = CreateItem(udg_FICS_Items[udg_FICS_DropNum[udg_FICS_DropCount] * 5 + 1], GetWidgetX(udg_FICS_Dropped[udg_FICS_DropCount]), GetWidgetY(udg_FICS_Dropped[udg_FICS_DropCount]))
            if GetItemType(udg_FICS_Dropped[udg_FICS_DropCount]) == ITEM_TYPE_CHARGED then
                call SetItemCharges(it, GetItemCharges(udg_FICS_Dropped[udg_FICS_DropCount]))
            endif
            call SetItemPlayer(it, GetItemPlayer(udg_FICS_Dropped[udg_FICS_DropCount]), false)
            call RemoveItem(udg_FICS_Dropped[udg_FICS_DropCount])
        endif
        exitwhen udg_FICS_DropCount == 0
    endloop
    set it = null
endfunction

function Trig_FICS_DropItem takes item it, integer num returns nothing
    set udg_FICS_Dropped[udg_FICS_DropCount] = it
    set udg_FICS_DropNum[udg_FICS_DropCount] = num
    if udg_FICS_DropCount == 0 then
        call TimerStart(udg_FICS_Timer, .0, false, function Trig_FICS_Drop_Timer)
    endif
    set udg_FICS_DropCount = udg_FICS_DropCount + 1
endfunction

function Trig_FICS_Pick_Actions takes nothing returns nothing
    local unit u = GetTriggerUnit()
    local item it = GetManipulatedItem()
    local item it2
    local player p = GetOwningPlayer(u)
    local boolean empty = false
    local boolean bought
    local integer itid = GetItemTypeId(it)
    local integer num = Trig_FICS_BinSearch(itid)
    local integer ls = udg_FICS_FirstList[num]
    local integer i = 0
    local integer j
    local integer k
    local integer l
    local integer m = 6
    if num != 0 and udg_FICS_Flag then
        //Заполняем массив отсортированными по невозрастанию индексами предметов в системе
        set udg_FICS_Temp[0] = num
        set udg_FICS_Temp[7] = -1
        loop
            set it2 = UnitItemInSlot(u, i)
            set k = GetItemTypeId(it2)
            set l = Trig_FICS_BinSearch(k)
            set j = i + 1
            if k == 0 or l == 0 or k != udg_FICS_Items[l * 5] then
                set m = m - 1
                set l = 0
            else
                loop
                    exitwhen j == 0 or udg_FICS_Temp[j - 1] >= l
                    set udg_FICS_Temp[j] = udg_FICS_Temp[j - 1]
                    set udg_FICS_Temp[j + 7] = udg_FICS_Temp[j + 6]
                    set j = j - 1
                endloop
            endif
            set udg_FICS_Temp[j] = l
            set udg_FICS_Temp[j + 7] = i
            exitwhen i == 5
            set i = i + 1
        endloop
        loop
            exitwhen ls == 0
            //Если Recipes является подпоследовательностью Temp, создать предмет
            set j = 0
            set k = 0
            loop
                exitwhen udg_FICS_Temp[j] < udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + k]
                if udg_FICS_Temp[j] == udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + k] then
                    set udg_FICS_Temp[k + 14] = udg_FICS_Temp[j + 7]
                    set k = k + 1
                    if k == 7 or udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + k] == 0 then
                        //Создать предмет по рецепту
                        set k = k + 14
                        loop
                            set k = k - 1
                            exitwhen k < 14
                            if udg_FICS_Temp[k] != -1 then
                                call RemoveItem(UnitItemInSlot(u, udg_FICS_Temp[k]))
                            endif
                        endloop
                        call UnitAddItemById(u, udg_FICS_Items[udg_FICS_Recipes[udg_FICS_Recipe[ls] * 8 + 7] * 5 + 1])
                        call DestroyEffect(AddSpecialEffectTarget(Trig_FICS_Effect(), u, Trig_FICS_Attach()))
                        set u = null
                        set it = null
                        set it2 = null
                        set p = null
                        return
                    endif
                endif
                exitwhen j == m
                set j = j + 1
            endloop
            set ls = udg_FICS_Next[ls]
        endloop
        set udg_FICS_Flag = false
        set p = GetItemPlayer(it)
        set bought = p == Player(15)
        if bought then
            set itid = udg_FICS_Items[num * 5]
            set p = GetOwningPlayer(u)
        elseif p == GetOwningPlayer(u) then
            set itid = udg_FICS_Items[num * 5]
        else
            set itid = udg_FICS_Items[num * 5 + 2]
        endif
        set i = 0
        if GetItemType(it) == ITEM_TYPE_CHARGED then
            set j = GetItemCharges(it)
            loop
                set it2 = UnitItemInSlot(u, i)
                if GetItemTypeId(it2) == itid then
                    call SetItemCharges(it2, GetItemCharges(it2) + j)
                    exitwhen true
                elseif it2 == null then
                    set empty = true
                endif
                set i = i + 1
                exitwhen i > 5
            endloop
            if i > 5 then
                if bought and not empty then
                    set p = GetOwningPlayer(u)
                    call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + udg_FICS_Items[num * 5 + 3])
                    call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + udg_FICS_Items[num * 5 + 4])
                elseif empty then
					set it = UnitAddItemById(u, itid)
					call SetItemCharges(it, j)
					call SetItemPlayer(it, p, false)
				else
					call Trig_FICS_DropItem(it, num)
                endif
            endif
        else
            loop
                exitwhen UnitItemInSlot(u, i) == null
                set i = i + 1
                exitwhen i > 5
            endloop
            if i <= 5 then
                call SetItemPlayer(UnitAddItemById(u, itid), p, false)
            elseif bought then
                set p = GetOwningPlayer(u)
                call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + udg_FICS_Items[num * 5 + 3])
                call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + udg_FICS_Items[num * 5 + 4])
            else
                call Trig_FICS_DropItem(it, num)
            endif
        endif
        set udg_FICS_Flag = true
        set it2 = null
    endif
    set u = null
    set it = null
    set p = null
endfunction

function Trig_FICS_Drop_Actions takes nothing returns nothing
    local item it = GetManipulatedItem()
    local integer itid = GetItemTypeId(it)
    local integer num = Trig_FICS_BinSearch(itid)
    if num != 0 and (itid == udg_FICS_Items[num * 5] or itid == udg_FICS_Items[num * 5 + 2]) then
        call Trig_FICS_DropItem(it, num)
    endif
    set it = null
endfunction

//===========================================================================
function InitTrig_FICS takes nothing returns nothing
    local trigger pick = CreateTrigger()
    local trigger drop = CreateTrigger()
    local integer i = 0
    loop
        call TriggerRegisterPlayerUnitEvent(pick, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
        call TriggerRegisterPlayerUnitEvent(drop, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null)
        exitwhen i == 15
        set i = i + 1
    endloop
    call TriggerAddAction(pick, function Trig_FICS_Pick_Actions)
    call TriggerAddAction(drop, function Trig_FICS_Drop_Actions)
    set pick = null
    set drop = null
endfunction
JASS:
//===========================================================================
function InitTrig_InitDataBase takes nothing returns nothing
    call FICS_Register('I000', 'I001', 'I002', 0, 0)//1, Claws of Justice
    call FICS_Register('I003', 'I004', 'I005', 0, 0)//2, Ogre Gauntlets
    call FICS_Register('I006', 'I007', 'I008', 0, 0)//3, Gloves of Haste
    call FICS_Register('I009', 'I00A', 'I00B', 0, 0)//4, Mana Potion
    call FICS_Register('I00C', 'I00D', 'I00E', 0, 0)//5, Ice Shard

    call FICS_Proceed()

    call FICS_Register7(5, 1, 1, 1, 1, 1, 1, 1)
    call FICS_Register2(3, 2, 1)
endfunction
Also, the cJass version is available:
JASS:
library FICS {
    #include "cj_types_priv.j"

    #define {
        private EFFECT = "Abilities\\Spells\\Items\\AIem\\AIemTarget.mdl"
        private ATTACH = "origin"
    }

    private constant timer T = CreateTimer();
    private item Dropped[ ];
    private int DropNum[ ], Temp[21];
    private int DropCount = 0;
    private int Ids[ ], Num[ ], Length = 0;
    private int Items[500][5], Recipes[256][8];
    private int ItemCount = 0, RecipeCount = 0;
    private int FirstList[ ], LastList[ ];
    private int Recipe[ ], Next[ ], ListCount = 0;
    private bool Flag = true;

    public int Register(int id, int rune, int dis, int gcost, int lcost) {
        ItemCount++;
        Ids[Length] = id;
        Ids[Length + 1] = rune;
        Ids[Length + 2] = dis;
        Num[Length] = ItemCount;
        Num[Length + 1] = ItemCount;
        Num[Length + 2] = ItemCount;
        Length += 3;
        Items[ItemCount][0] = id;
        Items[ItemCount][1] = rune;
        Items[ItemCount][2] = dis;
        Items[ItemCount][3] = gcost;
        Items[ItemCount][4] = lcost;
        return ItemCount;
    }

    //Сортировка расческой
    public void Proceed() {
        int jump = Length;
        bool end = true;
        whilenot jump == 1 && end {
            if jump > 1 { jump = R2I(jump * .802); }
            end = true;
            for (int i = 0; i + jump < Length; i++) {
                if Ids[i] > Ids[i + jump] {
                    int t = Ids[i];
                    Ids[i] = Ids[i + jump];
                    Ids[i + jump] = t;
                    t = Num[i];
                    Num[i] = Num[i + jump];
                    Num[i + jump] = t;
                    end = false;
                }
            }
        }
    }

    private int BinSearch(int id) {
        int first = 0, last = Length;
        if id >= Ids[0] && id <= Ids[last - 1] {
            whilenot first >= last {
                int mid = (first + last) / 2;
                if id <= Ids[mid] {
                    last = mid;
                } else {
                    first = mid + 1;
                }
            }
            if id == Ids[last] { return Num[last]; }
        }
        return 0;
    }

    public void Register7(int result, int i0, int i1, int i2, int i3, int i4, int i5, int i6) {
        #for j(0, 6)
            Temp[j] = i##j;
        #endfor
        RecipeCount++;
        //Записываем в Recipes сортированные по невозрастанию индексы
        for (int i = 0) {
            if Temp[i] > 0 {
                if Temp[i]:LastList == 0 || Temp[i]:LastList:Recipe != RecipeCount {
                    ListCount++;
                    if Temp[i]:LastList == 0 {
                        Temp[i]:FirstList = ListCount;
                    } else {
                        Temp[i]:LastList:Next = ListCount;
                    }
                    Temp[i]:LastList = ListCount;
                    Temp[i]:LastList:Recipe = RecipeCount;
                    Temp[i]:LastList:Next = 0;
                }
                int j = i;
                whilenot j == 0 || Recipes[RecipeCount][j - 1] >= Temp[i] {
                    Recipes[RecipeCount][j] = Recipes[RecipeCount][j - 1];
                    j--;
                }
                Recipes[RecipeCount][j] = Temp[i];
            }
            exitwhen i == 6;
            i++;
        }
        Recipes[RecipeCount][7] = result;
    }

    public void Register6(int result, int i0, int i1, int i2, int i3, int i4, int i5) {
        Register7(result, i0, i1, i2, i3, i4, i5, 0);
    }

    public void Register5(int result, int i0, int i1, int i2, int i3, int i4) {
        Register6(result, i0, i1, i2, i3, i4, 0);
    }

    public void Register4(int result, int i0, int i1, int i2, int i3) {
        Register5(result, i0, i1, i2, i3, 0);
    }

    public void Register3(int result, int i0, int i1, int i2) {
        Register4(result, i0, i1, i2, 0);
    }

    public void Register2(int result, int i0, int i1) {
        Register3(result, i0, i1, 0);
    }

    //Бесполезная штука, в общем-то, но такое тоже возможно
    public void Register1(int result, int i0) {
        Register2(result, i0, 0);
    }

    private void DropItem(item it, int num) {
        DropCount:Dropped = it;
        DropCount:DropNum = num;
        if ++DropCount == 1 {
            TimerStart(T, .0, false, \
                lambda void() {
                    item it;
                    do {
                        DropCount--;
                        if GetItemTypeId(DropCount:Dropped) != 0 {
                            it = CreateItem(Items[DropCount:DropNum][1], /*
                            */ GetWidgetX(DropCount:Dropped), GetWidgetY(DropCount:Dropped));
                            if GetItemType(DropCount:Dropped) == ITEM_TYPE_CHARGED {
                                SetItemCharges(it, GetItemCharges(DropCount:Dropped));
                            }
                            SetItemPlayer(it, GetItemPlayer(DropCount:Dropped), false);
                            RemoveItem(DropCount:Dropped);
                        }
                    } whilenot DropCount == 0;
                }
            );
        }
    }

    private void PickActions() {
        unit u = GetTriggerUnit();
        item it = GetManipulatedItem(), it2;
        player p = GetOwningPlayer(u);
        int itid = GetItemTypeId(it), num = BinSearch(itid);
        int ls = num:FirstList;
        int m = 6;
        if num != 0 && Flag {
            //Заполняем массив отсортированными по невозрастанию индексами предметов в системе
            Temp[0] = num;
            Temp[7] = -1;
            for (int i = 0) {
                it2 = UnitItemInSlot(u, i);
                int k = GetItemTypeId(it2), l = BinSearch(k);
                int j = i + 1;
                if k == 0 || l == 0 || k != Items[l][0] {
                    m--;
                    l = 0;
                } else {
                    whilenot j == 0 || Temp[j - 1] >= l {
                        Temp[j] = Temp[j - 1];
                        Temp[j + 7] = Temp[j + 6];
                        j--;
                    }
                }
                Temp[j] = l;
                Temp[j + 7] = i;
                exitwhen i == 5;
                i++;
            }
            whilenot ls == 0 {
                //Если Recipes является подпоследовательностью Temp, создать предмет
                int j = 0, k = 0;
                whilenot Temp[j] < Recipes[ls:Recipe][k] {
                    if Temp[j] == Recipes[ls:Recipe][k] {
                        Temp[k + 14] = Temp[j + 7];
                        k++;
                        if k == 7 || Recipes[ls:Recipe][k] == 0 {
                            k += 14;
                            whilenot --k < 14 {
                                if Temp[k] != -1 { RemoveItem(UnitItemInSlot(u, Temp[k])); }
                            }
                            UnitAddItemById(u, Items[Recipes[ls:Recipe][7]][1]);
                            DestroyEffect(AddSpecialEffectTarget(EFFECT, u, ATTACH));
                            return;
                        }
                    }
                    exitwhen j == m;
                    j++;
                }
                ls = ls:Next;
            }
            Flag = false;
            p = GetItemPlayer(it);
            bool bought = p == Player(15);
            if bought || p == GetOwningPlayer(u) {
                itid = Items[num][0];
                if bought { p = GetOwningPlayer(u); }
            } else {
                itid = Items[num][2];
            }
            int i = 0;
            bool empty = false;
            if GetItemType(it) == ITEM_TYPE_CHARGED {
                int j = GetItemCharges(it);
                do {
                    it2 = UnitItemInSlot(u, i);
                    if GetItemTypeId(it2) == itid {
                        SetItemCharges(it2, GetItemCharges(it2) + j);
                        break;
                    } elseif it2 == null {
                        empty = true;
                    }
                } whilenot ++i > 5;
                if i > 5 {
                    if bought && !empty {
                        p = GetOwningPlayer(u);
                        SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, /*
                        */ GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + Items[num][3]);
                        SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, /*
                        */ GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + Items[num][4]);
                    } elseif empty {
                        it = UnitAddItemById(u, itid);
                        SetItemCharges(it, j);
                        SetItemPlayer(it, p, false);
                    } else {
                        DropItem(it, num);
                    }
                }
            } else {
                do {
                    exitwhen UnitItemInSlot(u, i) == null;
                } whilenot ++i > 5;
                if i <= 5 {
                    SetItemPlayer(UnitAddItemById(u, itid), p, false);
                } elseif bought {
                    p = GetOwningPlayer(u);
                    SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, /*
                    */ GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD) + Items[num][3]);
                    SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, /*
                    */ GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER) + Items[num][4]);
                } else {
                    DropItem(it, num);
                }
            }
            Flag = true;
        }
    }

    private void DropActions() {
        item it = GetManipulatedItem();
        int itid = GetItemTypeId(it), num = BinSearch(itid);
        if num != 0 && (itid == Items[num][0] || itid == Items[num][2]) {
            DropItem(it, num);
        }
    }

    callback onInit() {
        trigger pick = CreateTrigger(), drop = CreateTrigger();
        for (int i = 0) {
            TriggerRegisterPlayerUnitEvent(pick, Player(i), EVENT_PLAYER_UNIT_PICKUP_ITEM, null);
            TriggerRegisterPlayerUnitEvent(drop, Player(i), EVENT_PLAYER_UNIT_DROP_ITEM, null);
            exitwhen i == 15;
            i++;
        }
        TriggerAddAction(pick, function PickActions);
        TriggerAddAction(drop, function DropActions);
    }
}
 

Attachments

  • FICSv1.5.w3x
    23.5 KB · Views: 91
Last edited:
Top