// globals
// integer array udg_cocoonSpawnUnitTypeId
// integer array udg_cocoonSpawnsQuantity
// integer array udg_cocoonUnitTypeId
// integer cocoonsQuantity = 0
// player array udg_cocoonOwner
// real array udg_cocoonHatchDelay
// real array udg_cocoonOriginX
// real array udg_cocoonOriginY
// real array udg_cocoonTargetY
// real array udg_cocoonTragetX
// real array udg_cocoonVectorX
// real array udg_cocoonVectorY
// unit array udg_cocoon
// unit array udg_cocoonMissile
// timer udg_cocoonsTimer
// endglobals
function CocoonTimerCallback takes nothing returns nothing
local integer i = 0
local integer j = 0
local player owner = null
local real distanceCovered = 0.0
local real distanceTotal = 0.0
local real distanceRemaining = 0.0
local timer t = GetExpiredTimer()
local real timeout = TimerGetTimeout(t)
local real x = 0.0
local real x0 = 0.0
local real x1 = 0.0
local real y = 0.0
local real y0 = 0.0
local real y1 = 0.0
local unit missile = null
local unit spawn = null
local unit u = null
local real z = 0.0
if udg_cocoonsQuantity <= 0 then
set t = null
call DestroyTimer(t)
endif
loop
exitwhen i >= udg_cocoonsQuantity
if IsUnitDeadBJ(udg_cocoon[i]) and null == udg_cocoonMissile[i] then
set udg_cocoonsQuantity = udg_cocoonsQuantity - 1
set udg_cocoonSpawnUnitTypeId[i] = udg_cocoonSpawnUnitTypeId[udg_cocoonsQuantity]
set udg_cocoonSpawnsQuantity[i] = udg_cocoonSpawnsQuantity[i]
set udg_cocoonUnitTypeId[i] = udg_cocoonUnitTypeId[udg_cocoonsQuantity]
set udg_cocoonOwner[i] = udg_cocoonOwner[udg_cocoonsQuantity]
set udg_cocoonHatchDelay[i] = udg_cocoonHatchDelay[udg_cocoonsQuantity]
set udg_cocoonOriginX[i] = udg_cocoonOriginX[udg_cocoonsQuantity]
set udg_cocoonOriginY[i] = udg_cocoonOriginY[udg_cocoonsQuantity]
set udg_cocoonTargetX[i] = udg_cocoonTargetX[udg_cocoonsQuantity]
set udg_cocoonTargetY[i] = udg_cocoonTargetY[udg_cocoonsQuantity]
set udg_cocoonVectorX[i] = udg_cocoonVectorX[udg_cocoonsQuantity]
set udg_cocoonVectorY[i] = udg_cocoonVectorY[udg_cocoonsQuantity]
set udg_cocoon[i] = udg_cocoon[udg_cocoonsQuantity]
set udg_cocoonMissile[i] = udg_cocoonMissile[udg_cocoonsQuantity]
set udg_cocoonSpawnUnitTypeId[udg_cocoonsQuantity] = 0
set udg_cocoonSpawnsQuantity[udg_cocoonsQuantity] = 0
set udg_cocoonUnitTypeId[udg_cocoonsQuantity] = 0
set udg_cocoonOwner[udg_cocoonsQuantity] = null
set udg_cocoonHatchDelay[udg_cocoonsQuantity] = 0.0
set udg_cocoonOriginX[udg_cocoonsQuantity] = 0.0
set udg_cocoonOriginY[udg_cocoonsQuantity] = 0.0
set udg_cocoonTargetX[udg_cocoonsQuantity] = 0.0
set udg_cocoonTargetY[udg_cocoonsQuantity] = 0.0
set udg_cocoonVectorX[udg_cocoonsQuantity] = 0.0
set udg_cocoonVectorY[udg_cocoonsQuantity] = 0.0
set udg_cocoon[udg_cocoonsQuantity] = null
set udg_cocoonMissile[udg_cocoonsQuantity] = null
endif
set u = udg_cocoon[i]
set missile = udg_cocoonMissile[i]
if missile != null then
set x0 = udg_cocoonOriginX[i]
set y0 = udg_cocoonOriginY[i]
set x1 = udg_cocoonTargetX[i]
set y1 = udg_cocoonTargetY[i]
call SetUnitPosition(missile, GetUnitX(missile) + udg_cocoonVectorX[i]*timeout, GetUnitY(missile) + udg_cocoonVectorY[i]*timeout)
set x = GetUnitX(missile)
set y = GetUnitY(missile)
set distanceTotal = SquareRoot((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0))
set distanceRemaining = SquareRoot((x1 - x)*(x1 - x) + (y1 - y)*(y1 - y))
set distanceCovered = SquareRoot((x - x0)*(x - x0) + (y - y0)*(y - y0))
set z = 4*128.0/distanceTotal*distanceRemaining*(distanceCovered/distanceTotal)
call SetUnitFlyHeight(missile, z, 0.0)
if distanceRemaining <= 64.0 then
call RemoveUnit(missile)
set udg_cocoon[i] = CreateUnit(udg_cocoonOwner[i], udg_cocoonUnitTypeId[i], x1, y1, 225.0)
set u = udg_cocoon[i]
call SetUnitUseFood(u, false)
call UnitAddType(u, UNIT_TYPE_SUMMONED)
call SetUnitExploded(u, true)
call PauseUnit(u, true)
endif
endif
if u != null then
set udg_cocoonHatchDelay[i] = udg_cocoonHatchDelay[i] - timeout
endif
if udg_cocoonHatchDelay[i] <= 0.0 and IsUnitAliveBJ(u) then
set x1 = udg_cocoonTargetX[i]
set y1 = udg_cocoonTargetY[i]
call KillUnit(u)
set j = 0
loop
exitwhen j >= udg_cocoonSpawnsQuantity[i]
set spawn = CreateUnit(udg_cocoonOwner[i], udg_cocoonSpawnUnitTypeId[i], x1, y1, 225.0)
call SetUnitUseFood(spawn, false)
call UnitAddType(spawn, UNIT_TYPE_SUMMONED)
call SetUnitExploded(spawn, true)
set j = j + 1
endloop
endif
set i = i + 1
endloop
set owner = null
set t = null
set missile = null
set spawn = null
set u = null
endfunction
function CreateSpellEffectCocoon takes unit c, integer cocoon, integer cq, integer spiderling, integer sq, real delay, real x1, real y1, real r returns nothing
local integer cocoonsQuantity = IMinBJ(IMaxBJ(cq, 1), IMinBJ(128, JASS_MAX_ARRAY_SIZE - udg_cocoonsQuantity - 1))
local integer i = 0
local integer j = 0
local integer spiderlingsQuantity = IMinBJ(IMaxBJ(sq, 1), 64)
local player p = GetOwningPlayer(c)
local real hatchDelay = RMaxBJ(1.0, delay)
local real radius = RMaxBJ(r, 32.0)
local real x0 = GetUnitX(c)
local real y0 = GetUnitY(c)
local unit u = null
loop
exitwhen j >= cocoonsQuantity
set u = CreateUnit(p, cocoon, x0, y0, bj_UNIT_FACING)
call SetUnitUseFood(u, false)
call UnitAddAbility(u, 'Aloc')
call UnitAddAbility(u, 'Amrf')
call SetUnitInvulnerable(u, true)
call SetUnitX(u, x0)
call SetUnitY(u, y0)
call PauseUnit(u, true)
set i = udg_cocoonsQuantity
set udg_cocoonSpawnUnitTypeId[i] = spiderling
set udg_cocoonSpawnsQuantity[i] = spiderlingsQuantity
set udg_cocoonUnitTypeId[i] = cocoon
set udg_cocoonOwner[i] = p
set udg_cocoonHatchDelay[i] = hatchDelay
set udg_cocoonOriginX[i] = x0
set udg_cocoonOriginY[i] = y0
set udg_cocoonTargetX[i] = x1 + radius*Cos(I2R(i)*(360.0/I2R(cocoonsQuantity)*bj_DEGTORAD))
set udg_cocoonTargetY[i] = y1 + radius*Sin(I2R(i)*(360.0/I2R(cocoonsQuantity)*bj_DEGTORAD))
set udg_cocoonVectorX[i] = (udg_cocoonTargetX[i] - x0)/radius*1100.0
set udg_cocoonVectorY[i] = (udg_cocoonTargetY[i] - y0)/radius*1100.0
set udg_cocoon[i] = null
set udg_cocoonMissile[i] = u
set udg_cocoonsQuantity = udg_cocoonsQuantity + 1
set j = j + 1
endloop
if null == udg_cocoonsTimer or 0 == TimerGetTimeout(udg_cocoonsTimer) then
set udg_cocoonsTimer = CreateTimer()
call TimerStart(udg_cocoonsTimer, 0.05, true, function CocoonTimerCallback)
endif
set p = null
set u = null
endfunction
function CreateSpellEffectCocoonDefault takes unit caster returns nothing
call CreateSpellEffectCocoon(caster, udg_COCOON_UNITTYPEID, udg_COCOON_QUANTITY, udg_COCOON_SPAWN_UNITTYPEID, udg_COCOON_SPAWN_QUANTITY, udg_COCOON_DELAY, GetUnitX(caster), GetUnitY(caster), udg_COCOON_OFFSET)
endfunction
Настраивается с помощью аргументов к функции, а не глобалок. В карте которую прикрепляю есть пример. Это позволяет иметь разные конфигурации заклинания в одной карте. Например, разные цвета коконов или разные по силе паучки, в зависимости от паучихи.
Как импортировать. Включите копирование глобальных переменных в редакторе. Скопируйте триггер. Удостоверьтесь что все глобальные переменные последовали. Скопируйте скрипт JASS в скрипт карты (корень дерева триггеров). Настройка производится либо передачей аргументов "вручную", либо изменением глобальных переменных, которые начинаются с "COCOON_...". Все что начинаются с малых литер должны оставаться неприкасаемыми.
COCOON_DELAY - задержка перед появлением паучков, секунд.
COCOON_OFFSET - растояние от паучихи до кокона.
COCOON_QUANTITY - количество коконов за применение способности.
COCOON_SPAWN_QUANTITY - количество паучков.
COCOON_SPAWN_UNITTYPEID - тип юнита паучка.
COCOON_UNITTYPEID - тип юнита кокона.
Сыграл. В целом, нормально. Посмеялся над иконками из Казаков и Героев.
Мне кажется нужно больше особенностей. К примеру я считаю что нужно пойти дальше с улучшениями. Если один игрок улучшает войска, то это улучшение распространяется на оба лагеря.
Понравились переменные режимы стрельбы мортир.
FPS rate был низок.
Игра довольно простая. Я предлагаю убрать жёлтых сторожей с дорог вовсе. Или оставить, скажем, двух пехотинцев. Вместо этого, дать игрокам вызвать подкрепление, скажем один раз на этом этапе. Возможно дать предмет, боевой рожок с одним зарядом, как способ это представить.
Каков контекст у этого всего? Буквально вчера написал заклинание AoE на точке.
/* SpellContaminate.j 1.0 */
globals
constant integer CONTAMINATE = 'A601'
constant integer CONTAMINATE_SUMMON = 'nvdl'
constant real CONTAMINATE_AOE = 200.0
constant real CONTAMINATE_DURATION = 16.0
constant real CONTAMINATE_SUMMON_DURATION = 60.0
constant real CONTAMINATE_UPDATE_TIMER_TIMEOUT = 2.0
constant string CONTAMINATE_EFFECT = "Abilities\\Spells\\Undead\\UnholyAura\\UnholyAura.mdl"
integer SCQuantity = 0
effect array SCEffect
integer array SCLevel
location array SCLoc
player array SCOwner
timer array SCTimerExpiration
endglobals
function SCOnDeathFilter takes nothing returns boolean
local boolean isConvertable = false
local unit u = GetDyingUnit()
set isConvertable = not IsUnitType(u, UNIT_TYPE_UNDEAD) and not IsUnitType(u, UNIT_TYPE_MECHANICAL)
return isConvertable and (SCQuantity > 0)
endfunction
function SCOnDeathCallback takes nothing returns nothing
local integer i = 0
local unit f = null
local unit u = GetTriggerUnit()
local location loc = GetUnitLoc(u)
/* In case there are overlaping Contamination zones,
make sure only one summon is created.
Moreover, make sure only the oldest zone takes effect.*/
loop
exitwhen i >= SCQuantity or (f != null)
if DistanceBetweenPoints(loc, SCLoc[i]) <= (CONTAMINATE_AOE / 2 + CONTAMINATE_AOE / 2 * I2R(SCLevel[i])) then
set f = CreateUnitAtLoc(SCOwner[i], CONTAMINATE_SUMMON, loc, GetUnitFacing(u))
call SetUnitUseFood(f, false)
call UnitAddType(f, UNIT_TYPE_SUMMONED)
call UnitAddType(f, UNIT_TYPE_UNDEAD)
call UnitApplyTimedLife(f, 'BTLF', CONTAMINATE_SUMMON_DURATION)
call SetUnitExploded(f, true)
call DestroyEffect(AddSpecialEffectLoc(CONTAMINATE_EFFECT, loc))
endif
set i = i + 1
endloop
call RemoveLocation(loc)
set f = null
set loc = null
set u = null
endfunction
function SCOnCastFilter takes nothing returns boolean
return CONTAMINATE == GetSpellAbilityId()
endfunction
function SCTimerExpirationCallback takes nothing returns nothing
local integer i = 0
local timer t = GetExpiredTimer()
local integer j = 0
loop
exitwhen i >= SCQuantity
if t == SCTimerExpiration[i] then
call RemoveLocation(SCLoc[i])
call DestroyTimer(SCTimerExpiration[i])
call DestroyEffect(SCEffect[i])
/* Pull other instances down the stack,
to preserve the creation order,
that is relevant in resolving application conflicts. */
set j = i + 1
loop
exitwhen j >= SCQuantity
set SCEffect[j - 1] = SCEffect[j]
set SCLevel[j - 1] = SCLevel[j]
set SCLoc[j - 1] = SCLoc[j]
set SCOwner[j - 1] = SCOwner[j]
set j = j + 1
endloop
/* Accessing out of array size elements terminates the game,
instead of returning null,
hence the ugly patch that follows. */
set SCQuantity = SCQuantity - 1
set SCEffect[SCQuantity] = null
set SCLevel[SCQuantity] = 0
set SCLoc[SCQuantity] = null
set SCOwner[SCQuantity] = null
set t = null
/* Assume each timer in the array is unique. */
return
endif
set i = i + 1
endloop
endfunction
function SCOnCastCallback takes nothing returns nothing
local unit c = GetSpellAbilityUnit()
local integer i = SCQuantity
local location loc = null
if i >= JASS_MAX_ARRAY_SIZE then
return
endif
set loc = GetSpellTargetLoc()
set SCEffect[i] = AddSpecialEffectLoc(CONTAMINATE_EFFECT, loc)
set SCLoc[i] = loc
set SCOwner[i] = GetOwningPlayer(c)
set SCLevel[i] = GetUnitAbilityLevel(c, CONTAMINATE)
set SCTimerExpiration[i] = CreateTimer()
call TimerStart(SCTimerExpiration[i], CONTAMINATE_DURATION, false, function SCTimerExpirationCallback)
set SCQuantity = SCQuantity + 1
set c = null
set loc = null
endfunction
function initSpellContaminate takes nothing returns nothing
local trigger t = CreateTrigger()
local trigger t2 = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, Condition(function SCOnCastFilter))
call TriggerAddAction(t, function SCOnCastCallback)
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t2, Condition(function SCOnDeathFilter))
call TriggerAddAction(t2, function SCOnDeathCallback)
set t = null
set t2 = null
endfunction
/* end SpellContaminate.j */
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(t, Condition(function SCOnCastFilter))
call TriggerAddAction(t, function SCOnCastCallback)
...
set loc = GetSpellTargetLoc()
Хотя мне казалось что заклинания которые юнит поддерживает (channeling) тоже запускают "EVENT_PLAYER_UNIT_SPELL_CAST".
Значит они в атакующей группе. Я думал что может они остаются потому что количество юнитов в атакующей группе превышает 12, но перечитав скрипт не вижу такой проблемы.
+
О, они точно производятся ИИ? Или они создаются при инициализации карты?
+
Попробуйте ещё поменять количество начальных ресурсов, может быть. Я уже просто угадываю к этому моменту.
Но они есть среди атакующих и "стражников". Может они просто стоят там и ждут своей очереди или что-то в этом роде? Хотя мне все ещё кажется что это скорее ошибка обновления.
По главному вопросу, я сам так и не нашел решения. Вероятно это ошибка в коде по ту сторону API. У меня были куда более странные проблемы.
Могу разве что посоветовать разделить базу на несколько владельцев.
Да действительно. Ladik's не создаёт необходимых записей в war3campaign.imp.
Может кто помочь с написанием Batch скрипта, который бы заполнял war3campaign.imp основываясь на дереве папок и файлов?
+ Впрочем, чем утруждаться со скриптами проще добавить записи в WE "вручную".
PT153,
Я думал это распространяется только на архивы игры, а не карты и кампании.
Я имею ввиду, об CASC говорят как о другом формате. Однако я мог открыть *.w3n как обычно.
Кстати есть функция ForcePickRandomPlayer. Например
function forceUsersFilter takes nothing returns boolean
return PLAYER_SLOT_STATE_PLAYING == GetPlayerSlotState(GetFilterPlayer()) and MAP_CONTROL_USER == GetPlayerController(GetFilterPlayer())
endfunction
function getRandomPlayer takes nothing returns player
local force f = CreateForce()
call ForceEnumPlayers(f, Condition(forceUsersFilter))
return ForcePickRandomPlayer(f)
endfunction
Используется ли модель как декорация? Если да, установлены ли вариации декорации в РО? В таком случае уберите вариации. Как основу используйте декорацию без вариаций, как указательный знак или факел.
На создание Pit Lord, кампанию из двух карт, у меня ушел ровно месяц. Я занимался кампанией приблизительно 4 часа в день. Сообщаю чтобы участники могли соотнести себя.
Мне интересно посмотреть что получится. Поигрываю иногда в пользовательские кампании. Меня удручает что у девяти из десяти очень низкий уровень производства. Казалось бы, за пятнадцать лет можно было научиться, ан нет.
Это возможно. Нужно выставить нужные галки в одном из параметров "Канала" и удостовериться что установлен достаточно большой радиус действия.
Однако на сколько я помню невозможно затем в скрипте отследить всех юнитов которые попали в область. Придется самому считать от центра применения способности.
Да, на снимках почти ничего не видно. Они здесь лишь как повод чтобы задать вопрос.
Как сделать классический уровень приятным? Такой уровень будет содержать обычные воду и утёсы. Я сам могу додуматься добавить густой туман и парочку новых декораций. И да, я читал статью Шурика и пару книжек на эту тему. Что ещё? Какова программа минимум для классического уровня? BranaR,
Грубоватый интерфейс портит всё впечатление. Проходящие сквозь друг друга колонны на первом снимке и на некоторых других слегка не к месту мне кажется. Хотя это только мне так кажется, возможно.
Отредактирован Zahanc
» WarCraft 3 / Заклинания на заказ
COCOON_OFFSET - растояние от паучихи до кокона.
COCOON_QUANTITY - количество коконов за применение способности.
COCOON_SPAWN_QUANTITY - количество паучков.
COCOON_SPAWN_UNITTYPEID - тип юнита паучка.
COCOON_UNITTYPEID - тип юнита кокона.
Отредактирован Zahanc
» Освободители / Главная страница
» Осквернитель / Главная страница
» WarCraft 3 / Странное поведение AI script
» WarCraft 3 / Получение точки применения способности ?
И затем удаляется когда он больше не нужен.
» WarCraft 3 / Получение точки применения способности ?
» WarCraft 3 / Получение точки применения способности ?
Отредактирован Zahanc
» WarCraft 3 / Получение точки применения способности ?
Отредактирован Zahanc
» WarCraft 3 / Странное поведение AI script
+
О, они точно производятся ИИ? Или они создаются при инициализации карты?
+
Попробуйте ещё поменять количество начальных ресурсов, может быть. Я уже просто угадываю к этому моменту.
» WarCraft 3 / Странное поведение AI script
» WarCraft 3 / Странное поведение AI script
» WarCraft 3 / Проблема с изменением архива кампании с Ladik's MPQ Editor.
+ Впрочем, чем утруждаться со скриптами проще добавить записи в WE "вручную".
» WarCraft 3 / Проблема с изменением архива кампании с Ladik's MPQ Editor.
» WarCraft 3 / Проблема с изменением архива кампании с Ladik's MPQ Editor.
Я думал это распространяется только на архивы игры, а не карты и кампании.
Я имею ввиду, об CASC говорят как о другом формате. Однако я мог открыть *.w3n как обычно.
» WarCraft 3 / Ошибка при выборе рандомного игрока (Jass)
» WarCraft 3 / Ошибка при выборе рандомного игрока (Jass)
» WarCraft 3 / Ошибка при выборе рандомного игрока (Jass)
» WarCraft 3 / Подскажите как проще всего написать рандом >покупку< героя
И наверное это N*X - 1 а не N*X - N.
» WarCraft 3 / Дамми спелл по типу "Буран"
» WarCraft 3 / Модель - странная штука. Вроде работает, а вроде и нет...
Отредактирован Zahanc
» XGM Конкурсы / Warcraft 3 Custom Campaign Contest 2019
» WarCraft 3 / ИИ использование способностей
» WarCraft 3 / Дамми спелл по типу "Буран"
» Повелитель Бездны / Главная страница
» WarCraft 3 / Галерея скриншотов ландшафта
BranaR,