27

» WarCraft 3 / Как на одну стандартную модель нацепить разные текстуры?

8gabriel8, да, вот я новичок в модделинге. Пока что не пробовал
хорош пункт 2, и пункт 6 (но надо понять как сделать самому в модделинг-редакторе, ничего не соображаю на какие кнопки там нажимать. Вроде во 2 пункте все расписано. Щас попробую)
27

» WarCraft 3 / Jass New Gen Pack - Rebuild 1.4

У меня слетел опять UMSWE (достало уже чего плагин слетает то? У меня 2-3 за год так). Хотел тайлы поставить, и еще клифы изменить (галочки на проходимость и строительство). И в результате, что то критануло из-за terrain.slk. Час настраивал, удалял. А нужно было эту сборку на помойку, и взять норм. И почему-то переустановка сборки не решает проблему.
короче поискал на сайте, и везде перессылки на эту страничку. А эта сборка не работает. =( Мне помогла старая сборка, которая хорошо что сохранилась (5d не сохранилась, но вот JNGP_R1.3_COMPAT осталась, хорошо что не удалил). другую сборку было не найти
27

» WarCraft 3 / Юнит и принадлежность

Я видел эту карту (что-то сделано норм, а что-то на гуи):
код
function Trig_jingong_chufadanweiActions takes nothing returns nothing
	set udg_unit04=GetTriggerUnit()
	if((RectContainsUnit(udg_rect22,udg_unit04)==true))then
		if((IsUnitInForce(udg_unit04,udg_forces04[1])==true))then
			set udg_locations01[0]=GetRectCenter(udg_rect07)
			call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
			call RemoveLocation(udg_locations01[0])
		else
			set udg_locations01[0]=GetRectCenter(udg_rect03)
			call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
			call RemoveLocation(udg_locations01[0])
		endif
	else
		if((RectContainsUnit(udg_rect23,udg_unit04)==true))then
			if((IsUnitInForce(udg_unit04,udg_forces04[1])==true))then
				set udg_locations01[0]=GetRectCenter(udg_rect08)
				call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
				call RemoveLocation(udg_locations01[0])
			else
				set udg_locations01[0]=GetRectCenter(udg_rect04)
				call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
				call RemoveLocation(udg_locations01[0])
			endif
		else
			if((RectContainsUnit(udg_rect24,udg_unit04)==true))then
				if((IsUnitInForce(udg_unit04,udg_forces04[1])==true))then
					set udg_locations01[0]=GetRectCenter(udg_rect09)
					call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
					call RemoveLocation(udg_locations01[0])
				else
					set udg_locations01[0]=GetRectCenter(udg_rect05)
					call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
					call RemoveLocation(udg_locations01[0])
				endif
			else
				if((RectContainsUnit(udg_rect25,udg_unit04)==true))then
					if((IsUnitInForce(udg_unit04,udg_forces04[1])==true))then
						set udg_locations01[0]=GetRectCenter(udg_rect10)
						call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
						call RemoveLocation(udg_locations01[0])
					else
						set udg_locations01[0]=GetRectCenter(udg_rect06)
						call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
						call RemoveLocation(udg_locations01[0])
					endif
				else
					if((IsUnitInForce(udg_unit04,udg_forces04[1])==true))then
						set udg_locations01[0]=GetRectCenter(udg_rect12)
						call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
						call RemoveLocation(udg_locations01[0])
					else
						set udg_locations01[0]=GetRectCenter(udg_rect13)
						call IssuePointOrderLoc(udg_unit04,"attack",udg_locations01[0])
						call RemoveLocation(udg_locations01[0])
					endif
				endif
			endif
		endif
	endif
endfunction

set udg_trigger432=CreateTrigger()
call TriggerAddAction(udg_trigger432,function Trig_jingong_chufadanweiActions)


function Trig_bunengbeikongzhiConditions takes nothing returns boolean
	return(((IsUnitSelected(GetTriggerUnit(),Player(0))==true)or(IsUnitSelected(GetTriggerUnit(),Player(1))==true)or(IsUnitSelected(GetTriggerUnit(),Player(2))==true)or(IsUnitSelected(GetTriggerUnit(),Player(3))==true)or(IsUnitSelected(GetTriggerUnit(),Player(4))==true)or(IsUnitSelected(GetTriggerUnit(),Player(5))==true)or(IsUnitSelected(GetTriggerUnit(),Player(6))==true)or(IsUnitSelected(GetTriggerUnit(),Player(7))==true))and(IsUnitType(GetTriggerUnit(),UNIT_TYPE_GIANT)==true)and((GetIssuedOrderIdBJ()==String2OrderIdBJ("stop"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("move"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("smart"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("patrol"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("AImove"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("attack"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("attackgrouned"))or(GetIssuedOrderIdBJ()==String2OrderIdBJ("attackonce"))))
endfunction

function Trig_bunengbeikongzhiActions takes nothing returns nothing
	call DisableTrigger(GetTriggeringTrigger())
	if((GetUnitAbilityLevelSwapped('A0AI',GetTriggerUnit())>=1))then
		call SelectUnitRemoveForPlayer(GetTriggerUnit(),GetTriggerPlayer())
		if((GetUnitAbilityLevelSwapped('A0AI',GetTriggerUnit())>=8))then
			if((IsUnitInForce(GetTriggerUnit(),udg_forces04[1])==true))then
				call SetUnitOwner(GetTriggerUnit(),Player(bj_PLAYER_NEUTRAL_VICTIM),false)
			else
				call SetUnitOwner(GetTriggerUnit(),Player(bj_PLAYER_NEUTRAL_EXTRA),false)
			endif
		else
		endif
	else
	endif
	if((GetUnitAbilityLevelSwapped('A0AI',GetTriggerUnit())==0))then
		call UnitAddAbilityBJ('A0AI',GetTriggerUnit())
	else
		call IncUnitAbilityLevelSwapped('A0AI',GetTriggerUnit())
	endif
	call TriggerExecute(udg_trigger432)
	call EnableTrigger(GetTriggeringTrigger())
endfunction

set udg_trigger420=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(udg_trigger420,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(udg_trigger420,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerRegisterAnyUnitEventBJ(udg_trigger420,EVENT_PLAYER_UNIT_ISSUED_ORDER)
call TriggerAddCondition(udg_trigger420,Condition(function Trig_bunengbeikongzhiConditions))
мы могли взять и выделить юнита, и потом дать какой-нибудь order. Но не выполняет его, и с него снимается выборка.
в этой карте ловится приказ, и его перебивают. там самая простая реализация. У любой тд-шки нам не нужно запоминать приказ, просто отдай снова приказ в точку, и он туда пойдет. (даже когда застрянет)
Тоже не знал. Предположил что в приказах. Взломал карту, решил поискать события на приказы. Но к удивлени, их оказалось не много, 4 события. нашел куски кода, собрал воедино код. были сомнения, поэтому для проверки я удалил в этом куске кода (см. код выше) - события приказов, теперь они не запускаются, и как вследствие, ими можно управлять
скидываю 2 карты, одну взломанную и измененную, и оригинал
если бы идея была бы сложнее, скажем, запоминать все приказы и цели, это было бы сложнее. а тут мы знаем, что юнит бежит к точке 1 (запоминаем 1). Тут все просто.
у юнита не отображаются на панеле команды - норм, видимо там классификация "страж" дана, не видел никакого импорта типа текстовика, координаты.
Загруженные файлы
27

» WarCraft 3 / Как назывется тип карты где играешь только героем?

Ну тут мало информации, что у вас за карта такая?
RPG - часто это жанр, в котором персонаж живет в своем мире. Где обычно присутствуют сюжет, квесты и прочее. Персонаж бегает по карте и пытается пройти игру, в этом то и смысл. Мб ошибаюсь. ссылка
Hero-Arena - герой, который участвует в дуэли с другими героями противников на арене.
Hero Defense - карта, в которой надо охранять героем от нападения орды крипов.
AOS (Aeon of Strife) - то же самая дота. от базы до базы.
Survival (в выживалке бывает один герой бегает и ему приходится выживать)
вопрос не о чем. пустяковый
27

» WarCraft 3 / Графика - Сдвиг окна

quq_CCCP, а что будет, если значение между углом поворота Юнита и его целью будет больше этого значения? он не выпустит снаряд или что?
27

» WarCraft 3 / Хак на память Warcraft3

DracoL1ch, короче понял
так понимаю, на пассивках это работать не будет. критует.
вот сделал систему когда прибавляет при убийстве blademaster-ом
Загруженные файлы
27

» WarCraft 3 / Хак на память Warcraft3

DracoL1ch, не понимаю. у меня что-то не работает =( вылетает ^_^
вот карта
Загруженные файлы
27

» WarCraft 3 / Преобразовать подстроку в реальное

Loran124,
используй логику - сравнение реальных чисел
if value <= 600 then //если значение равно или меньше 10 мин
//делать действия
endif
в 1 минуте = 60 секунд, тогда 10 мин = 600 сек
в таймер вводят только секунды
Загруженные файлы
27

» WarCraft 3 / Есть ли объяснение каждого параметра в редакторе объектов?

так понял что
cast animation - полная анимация включающая в себя каст поинт и бэксвинг.
cast point - время необходимое для каста спелла или атаки
cast backswing - любая анимация после применения скилла. Например, опускание рук Лины после задувки 1-м скиллом или опускание лука дровкой после автоатаки. Ее можно отменить (не завершить эту анимацию, перебив другой анимой), если юнит получает другой приказ
тфу попутал с анимацией точки обратного хода и анимацией точки повреждения с анимация: обратный ход броска и анимация: точка броска
27

» Кузня Волчачки / Отзыв: Серебряная душа [Аниме]

да аниме скучное, 20 серии посмотрел, и дропнул. =\ сейчас вроде вышел новый сезон аниме-сериала вроде, находил в интернете случайно в заголовках.
27

» WarCraft 3 / Есть ли объяснение каждого параметра в редакторе объектов?

Принятый ответ
  • про анимацию точки обратного хода и точки повреждения не знаю точно, сам не тестил эти два поля. См. выше ответ Факова и по ссылке, сравни, потести. Знаю, что можно поставить ноль, для быстрого воспроизведения каста даймика (например). Кто-то писал что Если у юнита поставить Art - Animation - Cast Backswing и Art - Animation - Cast Pint на 0, то он при касте не будет останавливаться чтобы воспроизвести аниму (те же Рёв и Провокация).
  • про автонаведение это есть у волшебниц и целителей хуманов. У эльфийских лучниц этого в параметре не стоит галочка. И летает прямо, снаряд промахивается, но урон все равно получает противник. Есть поставить галочку, то снаряд летает за противником.
  • Показать UI - вроде кнопка атаки пропадает при снятии галочки, если не ошибаюсь
  • траектория полета снаряда вот вот
  • урон (эффект от улучшения) - наскока будет у тебя улучшаться при завершении исследования. С каждым исследованием, у тебя будет улучшаться на заданное число.
  • урон кол-во граней и урон кол-во костей - можно найти в FAQ пункт 4.2
  • остальное
27

» WarCraft 3 / Лава

Принятый ответ
можно проверить через
native GetTerrainType takes real x, real y returns integer
или в моей карте делал через регион, в нее добавлял области. При чем области в разных местах могут быть. В моей карте идет обработка почвы (типа копание грядки в веселой ферме, квадратики), и потом циклом проверяешь. И GetTerrainType не всегда помогает понять, что этот участок уже обработан. Поэтому на помощь идут регионы, точнее мне достаточно одного региона, и одной вспомогательной области.
native IsPointInRegion takes region whichRegion, real x, real y returns boolean
native IsUnitInRegion takes region whichRegion, unit whichUnit returns boolean
например, выбираю участок областью Rect, задаю размеры, координаты и все такое. И потом этот участок добавляю в регион. могу несколько областей в регион добавить.
native RegionAddRect takes region whichRegion, rect r returns nothing
или чистить. точнее удалять этот участок из региона
native RegionClearRect takes region whichRegion, rect r returns nothing
раскрыть
В моей карте создание тайлов, терраина terrain сопровождается неприятным смещением. Как выяснил, он смещается центр таила на пересечении линии больших квадратиков, а в самих триггерах
Загруженные файлы
27

» Государь / Государь

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

» WarCraft 3 / 2-3. Локальные переменные

Globder, судя по скрину ты не понял для чего нужны локалки. Их удобство в том, что создаются (объявляются) каждый раз новые, и работают в определенной области - внутри функции. В отличии от глобалок их невозможно переписать где-то вне функции. Лучше использовать где есть задержки, как показано здесь. Короче в мультиплеере полезны.
примеры
вот тема 1 аргументы функции тоже являются локалками, и их обнулять не нужно

Приведу еще один пример с аргументами, не обязательно объявлять локалку, можно брать аргумент и что-то делать, правда аргумент перезапишется
раскрыть
function A takes integer i returns nothing
set i = 10 //видите, взял аргумент и присвоил новое значение
endfunction
тема 2 примеры работы локалок
вот тема 3 хотя локалки советуют использовать в динамических триггерах. Кстати, у меня бывала ситуация, писал наработку для новичков на гуи, но у меня она не работала. Тысячу раз перепроверил. Короче конвентировал в код, сократил добавил, локалки - у меня заработало. Тут неизвестно чего. Просто на jass наиболее читаемо, чем на гуи с ветвлениями и не работой чего-то там.
список локалок для новичков, есть jngp там можно посмотреть. или взять в гуи триггерную комманду конвентировать в код
27

» WarCraft 3 / триггер

эффекты горения можно убрать, удаляя нужную способность или бафф раздел пустышки
но все равно это не выход.
И кстати, есть же разница между строительством и ремонтом. У работника есть ремонтно-строительные способности, они вот отвечают за это. В первый раз идет строительство, а если здание покоцано ремонт. раздел строительство У этих способностей указано как быстро строится здание, сколько ресурсов уходит.
Ну можно даймиком попробовать поставить, и тут же удалить. если нужно узнать строителя, то узнается через событие "юнит отдал приказ на цель". Есть карты
вот тема
вот карта
выяснил, что строителя вполне реально вычислить по приказам. получается, что приказ на цель выводится только тогда, когда здание поставил.
ну или то что PyCCKuu_4eJlпредложил
27

» WarCraft 3 / Система рынка (продажа и покупка итемов)

13 версия

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

» WarCraft 3 / Система рынка (продажа и покупка итемов)

Немного переделал карту.
при инициализации пишем базу данных
Теперь не нужно всем писать, а только предметам с зарядами или с рунами. В остальных случаях вернет 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:'
Теперь получается
вот карта
27

» WarCraft 3 / Как ходить по дну?

можно паффинг отключить триггерно у наземного, и он ходит по дну
находил и скачивал похожие, но к сожалению не сохранилось, и не помню как. это надо протестить, но лень.
27

» WarCraft 3 / Отлов цели приказа

-> в массив предмет добавляется для того чтоб пока за этим предметом следуют на него не переключались другие юниты?
  • ну пометку boolean добавляют по handle item (когда перебираешь ближайшим итем, надо проверять и метки). когда на карте 10 артефактов, а все стадо идет за одним ^_^
  • еще можно ссылку в виде item по handle unit, если юнит сдохнет получит или другой приказ, метку с итема можно смело удалять.
  • периодически проверяем, что мобы не стоят
  • если триггером добавляется на карте итем, в группе циклом перебираем и ищем ближайших итемов. заново ищем. это если вдруг бежит раб, и внезапно перед носом появляется, а он бежит дальше
27

» WarCraft 3 / Отлов цели приказа

заметил, что не всегда ловит приказы IssuedOrder. Например, что вот отдал приказ продать в магазин, мне приказ IssuedOrder не выдаст.
А вот GetUnitCurrentOrder() выдает order_dropitem = 852001, когда юнит бежит к магазину, чтобы продать. Это как пример. Не надежный, надо еще проверять и координаты. Это что, таймером перебирать собрались группу?