Лучше делать кастомную на основе невидимости волшебницы через дамми каст, там и бафф сразу вешается или постоянную невидимость, стремительность имеет свои баги.
Просто создаем real timeEnd типа и сохраняем в ХТ на какой-нибудь хэндл и выгружаем, меняем значение выгружая из ХТ где то и сохраняем новое значение, также с имитацией остановкой можно сохранить через boolean или обзавестись глобалками и менять их значения. Понятно что будет висеть тикающий таймер, но наверное что бы нагрузить игру это довольно много надо таких таймеров-пустышек сделать.
Centyrion, Про систему не скажу, а вот что бы было читабельно помещай повторяющиеся действия в циклы.
function F_Init_Players takes nothing returns nothing
local integer i = 0
call FogMaskEnable(false)
call FogEnable(false)
loop
exitwhen i >= 9
set MapControl[i] = ConvertMapControl(0)//MAP_CONTROL_USER
set i = i + 1
endloop
set i = 0
set MapControl[11] = ConvertMapControl(1)//MAP_CONTROL_COMPUTER
set Loop[1] = 0
loop
exitwhen Loop[1] > GetPlayers()
set Players[Loop[1]] = Player(Loop[1])
//from 1 to 12 == from 0 to 11
if Players[Loop[1]] != Players[11] and Players[Loop[1]] != Players[10] then
//исключение для 12 и 11 игрока
call SetPlayerState(Players[Loop[1]], PLAYER_STATE_RESOURCE_GOLD, 50)
endif
set Loop[1] = Loop[1] + 1
endloop
if GetPlayerSlotState(Players[10]) == ConvertPlayerSlotState(0) then//PLAYER_SLOT_STATE_EMPTY
if GetPlayerController(Players[10]) == ConvertMapControl(5) then//MAP_CONTROL_NONE
set MapControl[10] = ConvertMapControl(1)//MAP_CONTROL_COMPUTER
call SetPlayerController(Players[10], MapControl[10])
call SetPlayerName(Players[10],"Союзник")
call SetPlayerRacePreference(Players[10],RACE_PREF_NIGHTELF)
call SetPlayerTeam(Players[10],0)
set Loop[2] = 0
loop
exitwhen Loop[2] > GetPlayers() - 2
//чтоб игроки не нападали друг на друга
call F_Player_Alliance(Loop[2], true, i, 0, true)
set Loop[2] = Loop[2] + 1
set i = i + 1
endloop
set i = 0
endif//MAP_CONTROL_NONE
endif
if GetPlayerState(Players[10], ConvertPlayerState(11)) == 1 then//PLAYER_STATE_OBSERVER
if GetPlayerController(Players[10]) == ConvertMapControl(0) then
set MapControl[10] = ConvertMapControl(0)//MAP_CONTROL_USER
set Observer = Players[10]
set Players[13] = Player(13)//наш союзник!
call SetPlayerController(Players[10], MapControl[10])
call SetPlayerName(Players[10],"Зритель")
call SetPlayerName(Players[13],"Союзник")
call SetPlayerState(Players[10],ConvertPlayerState(7),0)//PLAYER_STATE_GIVES_BOUNTY
call SetPlayerColor(Players[13],ConvertPlayerColor(10))
call F_Player_Alliance(11, false, 10, 0, true)
//Враг не сможет атаковать Зрителя но игроков Да
//а Зритель будет смотреть на него как на врага как и игроки
call F_Player_Alliance(13, false, 11, 0, false)
//союзник будет смотреть на 12 игрока как на Врага
//13 игрок Союзник и он не умеет нападать на Зрителя или на Игроков
call F_Player_Alliance(10, false, 13, 0, true)
//для Зрителя 13 игрок Союзник
set Loop[3] = 0
loop
exitwhen Loop[3] > GetPlayers()-2
call F_Player_Alliance(Loop[3], true, i, 0, true)//и на себе подобных
set Loop[3] = Loop[3] + 1
set i = i + 1
endloop
set i = 0
endif//MAP_CONTROL_USER
endif//PLAYER_STATE_OBSERVER
if IsMapFlagSet(MAP_RANDOM_RACES) then
loop
exitwhen i >= 9
call SetPlayerRacePreference(Players[i],ConvertRacePref(1))
set i = i + 1
endloop
call SetPlayerRacePreference(Players[11],ConvertRacePref(8))
endif
if IsMapFlagSet(MAP_RANDOM_HERO) then
call SetMapFlag(MAP_RANDOM_HERO, false)
endif
endfunction
Как вариант можно добавлять для этих юнитов отдельную классификацию при касте и настроить все ауры что бы они не действовали на эту классификацию.
Вот допустим код твоего скила.
function Trig_Spell_Actions takes nothing returns nothing
call UnitAddAbility( GetSpellTargetUnit(), 'ACm2')
call UnitAddType(GetSpellTargetUnit(), UNIT_TYPE_MECHANICAL)
endfunction
function Trig_Spell_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction
//===========================================================================
function InitTrig_Spell takes nothing returns nothing
local trigger t = CreateTrigger()
local integer index
set index = 0
loop
call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition( t, Condition( function Trig_Spell_Conditions ) )
call TriggerAddAction( t, function Trig_Spell_Actions )
set t = null
endfunction
Юниту выдается иммунка архимонда и добавляем ему классификацию механического, а в настройках аур указываем действует на органических.
В периодическом таймере проверять условия пока они не будут равны и таймер остановится или просто по окончанию таймера проверять условия?(В этом случае таймер остановится независимо равны будут условия или нет)
1 вариант
globals
boolean A_CONDITION = true
boolean B_CONDITION = false
endglobals
function Timer_Time takes nothing returns nothing
if A_CONDITION and B_CONDITION then //Будет прокручивать таймер пока условия не будут равны
call PauseTimer(GetExpiredTimer())
//Твои действия
call DestroyTimer(GetExpiredTimer())
endif
endfunction
function Timer_Actions takes nothing returns nothing
call TimerStart( CreateTimer(), 0.01, true, function Timer_Time)
endfunction
//===========================================================================
function InitTrig_Timer takes nothing returns nothing
set gg_trg_Timer = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Timer, 0.00 )
call TriggerAddAction( gg_trg_Timer, function Timer_Actions )
endfunction
2 вариант
function Timer_Time takes nothing returns nothing
local boolean a = true
local boolean b = true
if a and b then //Условия
//Твои действия
endif
call PauseTimer(GetExpiredTimer())
call DestroyTimer(GetExpiredTimer())
endfunction
function Timer_Actions takes nothing returns nothing
local real time = 5.00
call TimerStart( CreateTimer(), time, false, function Timer_Time)
endfunction
//===========================================================================
function InitTrig_Timer takes nothing returns nothing
set gg_trg_Timer = CreateTrigger( )
call TriggerRegisterTimerEventSingle( gg_trg_Timer, 0.00 )
call TriggerAddAction( gg_trg_Timer, function Timer_Actions )
endfunction
Можно чекать через точку или еще лучше через координаты. Как можно проверить глубину? что такое глубина? это 1. Что там нельзя ходить пешим 2.Там плавают лодки. И что такое мелководье? Там где могут ходить и пешие и плавать лодки. Из этого мы уже можем путем двух проверок сделать.
function IsWaterCheck takes real x, real y, boolean shallow, boolean deep returns boolean
local boolean Log
if shallow and not deep then
set Log = not IsTerrainPathable( x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable( x, y, PATHING_TYPE_WALKABILITY)
elseif deep and not shallow then
set Log = not IsTerrainPathable( x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable( x, y, PATHING_TYPE_WALKABILITY)
elseif deep and shallow then
set Log = not IsTerrainPathable( x, y, PATHING_TYPE_FLOATABILITY)
endif
return Log
endfunction
Если в игре присутствует вода в виде декора. Тут уже добавляем чек на декор к этой функции.
Если из-за автокаста способности сбиваются другие приказы
1 Попробуй отключить автокаст
2 Сделай способность без автокаста, возьми волну лечения у ловца духов(темный охотник).
3 Сделай триггерное лечение.
4 Написать ИИ поведение приказов
function UnitHaveItem takes unit UnitItem, integer ItemTypeID returns boolean
local integer i = 0
local boolean ItemLog = false
loop
exitwhen i >= bj_MAX_INVENTORY
if GetItemTypeId(UnitItemInSlot(UnitItem, i)) == ItemTypeID then
set ItemLog = true
endif
set i = i + 1
endloop
return ItemLog
endfunction
function A takes nothing returns nothing
local unit caster = GetTriggerUnit()
if UnitHaveItem( caster, 'I000') and UnitHaveItem( caster, 'I001') and UnitHaveItem( caster, 'I002') and UnitHaveItem( caster, 'I003') then
//Твои действия
endif
set caster = null
endfunction
можно конечно извращаться и делать так например
function UnitHaveItem takes unit UnitItem, integer ItemTypeID returns boolean
local integer i = 0
local boolean ItemLog = false
loop
exitwhen i >= bj_MAX_INVENTORY
if GetItemTypeId(UnitItemInSlot(UnitItem, i)) == ItemTypeID then
set ItemLog = true
endif
set i = i + 1
endloop
return ItemLog
endfunction
function CheckItems takes unit caster, integer ItemA, integer ItemB, integer ItemC, integer ItemD, integer ItemE returns boolean
return UnitHaveItem( caster, ItemA) and UnitHaveItem( caster, ItemB) and UnitHaveItem( caster, ItemC) and UnitHaveItem( caster, ItemD) and UnitHaveItem( caster, ItemE)
endfunction
function B takes nothing returns nothing
local unit Unit = GetTriggerUnit()
if CheckItems(Unit, 'I000', 'I001', 'I002', 'I003', 'I004') then
//True
else
//False
endif
set Unit = null
endfunction
Заказчик: Гогонаш Способность: Аура вампиризма для дальников Выполнено: Да
Описание
Сделал через готовую систему отлова урона. Скопируй все нестандартные абилки и баф, в триггере системе отлова урона укажи равкоды 2х абилок, в триггере вампиризма укажи равкод бафа от ауры.
Super cool, Jass это встроенный язык программирования варкрафта, т.е код что на GUI - пользовательский интерфейс, только в виде кода. GUI ограничен, на нем могут вылезти утечки. Из-за чего могут быть лаги в картах.
подробнее про Jass Тут
Ну и конечно нужен JNGP, если на 1.26 патче или рефорджет. Скачать можно тут
Создаем триггер и конвертируем его в текст. Затем копируем и вставляем код.
Конвертируем в текст
udg_Tower - твоя башня, триггер рассчитан на 1 башню если нужно на несколько, используй другой код и заноси каждую башню в группу
Тогда нужно создать группу для башен, т.е GroupTowers.
Создаем GUI переменную
Код для 1 башни
scope LightningAutoCast
globals
private unit filterUnit //Юнит для перебора
private group GroupEnumG = CreateGroup() //Группа для перебора юнитов
//udg_Tower = Башня
endglobals
native UnitAlive takes unit id returns boolean //Нативка на жив ли юнит
function DistanceBetweenXY takes real x1, real y1, real x2, real y2 returns real //Дистанция между координатами
return SquareRoot((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
endfunction
function AOE_Lightning_Filter takes nothing returns boolean //Фильтр функция
local real x = GetUnitX(udg_Tower) //Координата Х башни
local real y = GetUnitY(udg_Tower) //Координата Y башни
local real x1
local real y1
set filterUnit = GetFilterUnit()
set x1 = GetUnitX(filterUnit) //Координата X фильтр юнита
set y1 = GetUnitY(filterUnit) //Координата Y фильтр юнита
return IsUnitEnemy(filterUnit, GetOwningPlayer(udg_Tower)) and filterUnit != udg_Tower and not IsUnitType(filterUnit, UNIT_TYPE_STRUCTURE) and DistanceBetweenXY( x, y, x1, y1) > 500
//Условия: Юнит враг Игроку Башни и Юнит не равен самой Башни и Юнит не является зданием и Дистанция между координатами юнита и башни > 500
endfunction
function AOE_Lightning_Actions takes nothing returns nothing
local real radius = 1000 // Радиус
local real x = GetUnitX(udg_Tower) //Координата Х башни
local real y = GetUnitY(udg_Tower) //Координата Y башни
local unit uf // Юнит для перебора в цикле
call GroupEnumUnitsInRange(GroupEnumG, x, y, radius, function AOE_Lightning_Filter) // Пикаем юнитов в радиусе от координат башни и перебираем в функции фильтре
loop
set uf = FirstOfGroup(GroupEnumG) // GroupPickRandomUnit(GroupEnumG) -- Если нужен случайный юнит в радиусе, удаляем FirstOfGroup(GroupEnumG) и ставим эту функцию
exitwhen uf == null
if UnitAlive(uf) then
call IssueTargetOrder(udg_Tower, "chainlightning", uf) //Кастуем молнию на юнита
endif
call GroupRemoveUnit( GroupEnumG, uf) //Удаляем юнита из группы
set uf = null //Обнуляем переменную
endloop
call GroupClear(GroupEnumG) //Очищаем группу
endfunction
function InitTrig_LightningAutoCast takes nothing returns nothing
call TimerStart( CreateTimer(), 0.03, true, function AOE_Lightning_Actions) //Создаем периодический таймер
endfunction
endscope
Код для несколько башень
scope LightningAutoCastGroup
globals
private unit filterUnit //Юнит для перебора
private group GroupEnumG = CreateGroup() //Группа для перебора юнитов
//udg_Tower = Башня
endglobals
native UnitAlive takes unit id returns boolean //Нативка на жив ли юнит
function DistanceBetweenXY takes real x1, real y1, real x2, real y2 returns real //Дистанция между координатами
return SquareRoot((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
endfunction
function AOE_Lightning_Filter takes nothing returns boolean //Фильтр функция
local real x = GetUnitX(GetEnumUnit()) //Координата Х башни
local real y = GetUnitY(GetEnumUnit()) //Координата Y башни
local real x1
local real y1
set filterUnit = GetFilterUnit()
set x1 = GetUnitX(filterUnit) //Координата X фильтр юнита
set y1 = GetUnitY(filterUnit) //Координата Y фильтр юнита
return IsUnitEnemy(filterUnit, GetOwningPlayer(GetEnumUnit())) and filterUnit != GetEnumUnit() and not IsUnitType(filterUnit, UNIT_TYPE_STRUCTURE) and DistanceBetweenXY( x, y, x1, y1) > 500
//Условия: Юнит враг Игроку Башни и Юнит не равен самой Башни и Юнит не является зданием и Дистанция между координатами юнита и башни > 500
endfunction
function AOE_Lightning_Actions takes nothing returns nothing
local real radius = 1000 // Радиус
local real x = GetUnitX(GetEnumUnit()) //Координата Х башни
local real y = GetUnitY(GetEnumUnit()) //Координата Y башни
local unit uf // Юнит для перебора в цикле
call GroupEnumUnitsInRange(GroupEnumG, x, y, radius, function AOE_Lightning_Filter) // Пикаем юнитов в радиусе от координат башни и перебираем в функции фильтре
loop
set uf = GroupPickRandomUnit(GroupEnumG) // GroupPickRandomUnit(GroupEnumG) -- Если нужен случайный юнит в радиусе, удаляем FirstOfGroup(GroupEnumG) и ставим эту функцию
exitwhen uf == null
if UnitAlive(uf) then
call IssueTargetOrder(GetEnumUnit(), "chainlightning", uf) //Кастуем молнию на юнита
endif
call GroupRemoveUnit( GroupEnumG, uf) //Удаляем юнита из группы
set uf = null //Обнуляем переменную
endloop
call GroupClear(GroupEnumG) //Очищаем группу
endfunction
function AOE_Lightning_Actions_GroupTower takes nothing returns nothing
call ForGroup( udg_GroupTowers, function AOE_Lightning_Actions)
endfunction
function InitTrig_LightningAutoCastGroup takes nothing returns nothing
call TimerStart( CreateTimer(), 0.03, true, function AOE_Lightning_Actions_GroupTower) //Создаем периодический таймер
endfunction
endscope
Super cool, тогда перебирай юнитов в радиусе 1000 и сравнивай дистанцию, поставь условие если расстояние между точками выбранного юнита и самой башни > 500, использовать цепную молнию.
но это лучше делать на Jass-е.
Вычислить 2 юнита при касте
GetTriggerUnit() это юнит каста
GetSpellTargetUnit() или в ГУИ как на скрине это юнит на которого кастует юнит
2 юнита нашли.
а дальше делаем с ними что угодно
Через что делаете модель? В Mdlvis-e в редакторе анимации нужно смотреть как привязаны меши к кости, возможно неправильно связаны меши(точки на модели).
» WarCraft 3 / Запрет выбора юнита
Условие: триггерный юнит = твой юнит
Действие: Отменить выбор или Переключить выбор на своего героя
» WarCraft 3 / Как запретить использование предметов?
Ред. SoulRazor
» WarCraft 3 / Как отследить удар из невидимости?
» WarCraft 3 / как изменить время внутри таймерного периодического триггера?
» WarCraft 3 / Зрители
Ред. SoulRazor
» WarCraft 3 / Невосприимчивость к аурам
Ред. SoulRazor
» WarCraft 3 / как на гуи/jass сделать проверку по таймеру
» WarCraft 3 / отслеживание захода в воду
» WarCraft 3 / как исправить возможность абуза
Ред. SoulRazor
» WarCraft 3 / ИИ и главное здание
1 Попробуй отключить автокаст
2 Сделай способность без автокаста, возьми волну лечения у ловца духов(темный охотник).
3 Сделай триггерное лечение.
4 Написать ИИ поведение приказов
Ред. SoulRazor
» WarCraft 3 / Оптимизация Выполнения Последовательности Кода
Ред. SoulRazor
» WarCraft 3 / Дополнительные эффекты для shockwave/carrion swarm
» WarCraft 3 / Способности и алгоритмы на заказ
Ред. SoulRazor
» WarCraft 3 / Способности и алгоритмы на заказ
» WarCraft 3 / Способности и алгоритмы на заказ
Ред. SoulRazor
» WarCraft 3 / Способности и алгоритмы на заказ
Заклинание готово!
Способность: Живительная волна
Выполнено: Да
» WarCraft 3 / Способности и алгоритмы на заказ
Способность: Аура вампиризма для дальников
Выполнено: Да
» WarCraft 3 / Пирокластическое уничтожение
Ред. SoulRazor
» WarCraft 3 / Радиус атаки
В коде есть комментарии для обучения Jass-у, как все устроено.
Ред. SoulRazor
» WarCraft 3 / Радиус атаки
подробнее про Jass Тут
Ну и конечно нужен JNGP, если на 1.26 патче или рефорджет. Скачать можно тут
Создаем триггер и конвертируем его в текст. Затем копируем и вставляем код.
Тогда нужно создать группу для башен, т.е GroupTowers.
» WarCraft 3 / Радиус атаки
но это лучше делать на Jass-е.
» WarCraft 3 / Радиус атаки
» WarCraft 3 / Как удалить анимацию у модели?
Ред. SoulRazor
» WarCraft 3 / Как дать приказ юниту на которого применили способность?
GetTriggerUnit() это юнит каста
GetSpellTargetUnit() или в ГУИ как на скрине это юнит на которого кастует юнит
2 юнита нашли.
а дальше делаем с ними что угодно
» WarCraft 3 / Редактор модлелей.