//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);
}
}