unit EnemyInGroup (unit u, float x, float y, float range) {
group enemies = CreateGroup()
unit u_e
GroupEnumUnitsInRange(enemies, x, y, range, Condition(function SimpleCond))
loop
u_e = FirstOfGroup(enemies)
exitwhen u_e == null
if IsUnitEnemy(u_e, GetOwningPlayer(u)) then
DestroyGroup(enemies)
enemies = null
return u_e // утечка переменной u_e, используй глобалку.
// exitwhen true // зачем это, когда есть return?
else
GroupRemoveUnit(enemies, u_e)
endif
endloop
DestroyGroup(enemies)
enemies = null
u_e = null
return null // нет враждебного юнита.
}
А вообще, что находится в функции SimpleCond? Тут можно всё упростить.
code
globals
player TransPlayer
unit LastEnemyUnit
endglobals
function filter takes nothing returns boolean
if IsUnitEnemy(GetFilterUnit(), TransPlayer) then
set LastEnemyUnit = GetFilterUnit()
endif
return false
endfunction
function EnemyInRange takes unit u, real x, real y, real range return boolean
set TransPlayer = GetOwningPlayer(u)
set LastEnemyUnit = null
call GroupEnumUnitsInRange(bj_lastCreatedGroup, x, y, range, Filter(function filter))
return LastEnemyUnit != null
endfunction
замечание от Raised: 1.4 (злоупотребление форматированием) используйте каты
А зачем инициализировать null, "" или 0? Все глобалки, что имеют присвоение в своём определении, выполняются в то время, как игрок кликнул на карту в списке карт. Потому лучше либо вообще ничего не прописывать, либо прописать нормальные значения, например:
Однако не для всех это работает. GetLocalPlayer(), CreateRegion(), CreateLeaderboard, CreateMultiboard() нельзя использовать в определении глобалок, они крашнут игру, как только игрок кликнет на карту. А, вот например, InitHashtable(), CreateTimer(), CreateTrigger() карту не крашат, потому можно сделать так:
я почти всем глобалкам ставлю при объявлении null или 0 или ""
ну это ты зря
Тогда остаётся только инициализацию мультибоарда передвинуть, а также проверить вызовы ExecuteFunc (что имя вызываемой функции точно есть в карте) на всякий случай.
Проще простого же. Пусть abil является действием в триггере, который ловит каст твоего спела.
function filter takes nothing returns nothing
local unit u = GetFilterUnit()
if /* нужные условия */ then
// нужные действия
endif
set u = null
endfunction
function abil takes nothing returns nothing
...
call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, Condition(function filter))
...
endfunction
компилирует war3map.j какой-то утилитой в составе JNGP
JassHelper эта утилита, её можно через PowerShell отдельно от JNGP запускать.
Так-то можно даже просто pjass.exe (тоже в составе JNGP) запустить (через PowerShell), ведь в war3map.j код уже в JASS.
БОльшая часть строк находится в war3map.wts, его и нужно переводить, там находятся все описания способностей, юнитов, предметов и так далее, иногда даже просто мусор, который редактор забыл убрать.
Дам совет, у способностей нужно переводить только описания, имена в самой игре всё равно не отображаются. А ещё на них может быть завязан код (как у меня в карте), так что лучше их вообще не трогать.
С юнитами и предметами возможна такая же ситуация, но вот тут сложнее, ведь их имена отображаются в игре.
Потому перед переводом, нужно проверить war3map.j на наличие функций GetObjectName, GetItemName, GetUnitName. Если они есть, то понять, для чего они используются, а потом уже переводить.
Часть строк может быть в war3map.j, многие и переводить не нужно (пути к эффектам, например), но вот выводимые на экран сообщения перевести стоит.
Кстати, а можно ли сделать карту с различными шириной и длиной?
Да, это можно сделать даже в меню создания новой карты.
Включи среднюю сетку, размер белого квадрата есть 128х128, и именно в них и измеряется размер карты, то есть, выражаясь точнее, когда увеличиваешь или уменьшаешь карту, нужно сделать количество белых квадратов по длине и ширине кратным 32.
Делать в if действие только в else плохой тон и просто неудобно для чтения кода. Тут всё равно идёт сравнение логических, потому данное исправление улучшит читаемость кода и никак не повлияет на производительность.
Событие: каждые 20 секунд.
Действия: поставить переменной B значение ноль.
Выбрать все предметы в области Х, равкод которых Z, и для каждого сделать Поставить переменной B значение B + 1.
Если B равно 0 создать предмет иначе ничего не делать.
У меня к каждому юниту крепится ссылка на объект структуры, в которой есть отдельные списки для разных типов баффов. Если же бафф имеет два разных эффекта, то ссылка на него хранится в двух списках. При удалении конфликтов не возникает, потому что при удалении бафф удаляет все ячейки, которые были к нему привязаны, а ячейки удаляются линейно.
Ячейка списка
struct MBSNode
readonly MinionBuff buf
readonly integer number
thistype prev = 0
thistype next = 0
method basicInit takes MinionBuff buf, integer number returns nothing
static if ErrorDetectionEnabled_MBSNode then
if this == 0 then
call ErrorOccurred("Error: MBSNode struct has run out of indexes. Current amount of indexes is 8190", "MBSNodeError")
endif
endif
set this.buf = buf
set this.number = number
endmethod
method removeFromList takes nothing returns nothing
if prev != 0 then
set prev.next = next
endif
if next != 0 then
set next.prev = prev
endif
endmethod
endstruct
struct MBSNodeReal extends MBSNode
real value = 0.
endstruct
struct MBSNodeInt extends MBSNode
integer value = 0
endstruct
struct MBSNodeIntNReal extends MBSNode
integer value = 0
real rvalue = 0.
endstruct
Структура, в которой содержится списки, называется MBS, в ней есть счётчик количества баффов, это нужно для определения, какой бафф был добавлен раньше.
Списки в основном задаются таким макросом.
Список
// Name - имя типа баффа
// ntyp - тип ячейки
// values - если есть значения у баффа
// bool - если значения типа boolean
// null - нуль для заданного типа значений.
//! textmacro MBSList takes Name, ntyp, values, type, bool, null
private MBSNode$ntyp$ head$Name$
readonly integer buffsAmount$Name$ = 0
method add$Name$Buff takes MinionBuff obj returns MBSNode$ntyp$
local MBSNode$ntyp$ node = MBSNode$ntyp$.create()
if buffsAmount$Name$ == 0 then
set head$Name$ = node
else
set node.next = head$Name$
set head$Name$.prev = node
set head$Name$ = node
endif
set BuffCounter = BuffCounter + 1
set buffsAmount$Name$ = buffsAmount$Name$ + 1
call node.basicInit(obj, BuffCounter)
//call DebugMsg("Current amount of $Name$ buffs is " + I2S(buffsAmount$Name$) + ".")
return node
endmethod
method remove$Name$Buff takes MBSNode$ntyp$ node returns nothing
set buffsAmount$Name$ = buffsAmount$Name$ - 1
if head$Name$ == node then
set head$Name$ = node.next
endif
static if $values$ then
static if $bool$ then
set booleanAmount$Name$ = booleanAmount$Name$ - node.value
set total$Name$Bonus = booleanAmount$Name$ > 0
else
set total$Name$Bonus = total$Name$Bonus - node.value
endif
endif
call node.removeFromList()
call node.destroy()
//call DebugMsg("Current amount of $Name$ buffs is " + I2S(buffsAmount$Name$) + ".")
endmethod
static if $values$ then
static if $bool$ then
private integer booleanAmount$Name$ = 0
readonly boolean total$Name$Bonus = false
else
readonly $type$ total$Name$Bonus = $null$
endif
method change$Name$Value takes MBSNode$ntyp$ node, $type$ value returns nothing
static if $bool$ then
local integer v = B2I(value)
set booleanAmount$Name$ = booleanAmount$Name$ - node.value + v
set total$Name$Bonus = booleanAmount$Name$ > 0
set node.value = v
else
set total$Name$Bonus = total$Name$Bonus - node.value + value
set node.value = value
endif
endmethod
endif
//! endtextmacro
В этой же системе определяется текущее кол-во брони, уязвимый ли он или нет, уровень замедления или ускорения, и пр.
При удалении объекта системы удаляются и все навешанные баффы.
Удаление
// Макрос ниже также используется для удаления баффов конкретного типа при каких-то обстоятельствах.
// pos - бафф положительный.
// Ячейки удаляются с удалением баффа.
//! textmacro DeleteBuffs takes Name, first, pos
static if $first$ then
local MBSNode node = head$Name$
local MBSNode temp
else
set node = head$Name$
endif
loop
exitwhen node == 0
set temp = node.next
$pos$if node.buf.buffdata.negative then
call node.buf.destroy()
$pos$endif
set node = temp
endloop
//! endtextmacro
...
method onDestroy takes nothing returns nothing
//! runtextmacro DeleteBuffs("EoT", "true", "//# ")
//! runtextmacro DeleteBuffs("Shield", "false", "//# ")
//! runtextmacro DeleteBuffs("MoveSpeed", "false", "//# ")
//! runtextmacro DeleteBuffs("Stun", "false", "//# ")
//! runtextmacro DeleteBuffs("Persistence", "false", "//# ")
//! runtextmacro DeleteBuffs("PhysArmor", "false", "//# ")
//! runtextmacro DeleteBuffs("MagcArmor", "false", "//# ")
//! runtextmacro DeleteBuffs("Armor", "false", "//# ")
//! runtextmacro DeleteBuffs("PhysImmune", "false", "//# ")
//! runtextmacro DeleteBuffs("MagcImmune", "false", "//# ")
//! runtextmacro DeleteBuffs("Protection", "false", "//# ")
//! runtextmacro DeleteBuffs("Invul", "false", "//# ")
call DebugMsg("MinionBuffStorage " + I2S(this) + " is deleted.")
endmethod
Сами баффы.
Каждый бафф - отдельная структура, которая наследуется от общей.
Бафф
struct MinionBuff
integer typ
Minion target
unit source
CustomPlayer owner
MinionBuffData buffdata
integer currticks = 0
boolean isRunning = false
MBSNode node1
MBSNode node2
MBSNode node3
//! runtextmacro CustomTimer("t", "Timer", "MinionBuff", "false")
method onDestroy takes nothing returns nothing
call DeleteTimer()
call RemoveSavedInteger(Hash, target.id, typ)
call UnitRemoveAbility(target.minion, buffdata.effectid)
set source = null
call DebugMsg("MinionBuff " + I2S(this) + " is deleted.")
endmethod
method basicInit takes Minion host, unit src, CustomPlayer p, integer T returns nothing
static if ErrorDetectionEnabled_MinionBuff then
if this == 0 then
call ErrorOccurred("Error: MinionBuff struct has run out of indexes. Current amount of indexes is 8190", "MinionBuffError")
endif
endif
set typ = T
set target = host
set source = src
set owner = p
set buffdata = p.minion_buffdata[T]
call InitTimer()
call SaveInteger(Hash, target.id, T, this)
//call DebugMsg("MinionBuff " + I2S(this) + " is created.")
endmethod
...
endstruct
Может быть всего 3 разных типа эффекта у баффа, пока максимум было 2.
Макрос InitBuff инициализирует любой бафф, но вопрос не об устройстве баффов, потому опустим его полное устройство. При вызове баффа (метод launch) делаются некоторые проверки, если всё хорошо, то создаётся объект и вызывается его метод onCreate, где сохраняются ссылки на его ячейки.
Ред. Raised
» WarCraft 3 / missing return
» WarCraft 3 / Вылет на полосе загрузки у некоторых игроков
Ред. PT153
» WarCraft 3 / Вылет на полосе загрузки у некоторых игроков
Ред. PT153
» WarCraft 3 / Вылет на полосе загрузки у некоторых игроков
Ред. PT153
» WarCraft 3 / Вылет на полосе загрузки у некоторых игроков
Какие глобалки у тебя сразу имеют значение? например constant integer A = 1
Ред. PT153
» WarCraft 3 / Способность которая действует по все карте
» WarCraft 3 / Движение, jass
» WarCraft 3 / Помогите разобраться в карте, в крафтах!
» WarCraft 3 / Движение, jass
» WarCraft 3 / Как сделать возраждение?
Ред. PT153
» WarCraft 3 / Помогите разобраться в карте, в крафтах!
Так-то можно даже просто pjass.exe (тоже в составе JNGP) запустить (через PowerShell), ведь в war3map.j код уже в JASS.
Дам совет, у способностей нужно переводить только описания, имена в самой игре всё равно не отображаются. А ещё на них может быть завязан код (как у меня в карте), так что лучше их вообще не трогать.
С юнитами и предметами возможна такая же ситуация, но вот тут сложнее, ведь их имена отображаются в игре.
Потому перед переводом, нужно проверить war3map.j на наличие функций GetObjectName, GetItemName, GetUnitName. Если они есть, то понять, для чего они используются, а потом уже переводить.
Часть строк может быть в war3map.j, многие и переводить не нужно (пути к эффектам, например), но вот выводимые на экран сообщения перевести стоит.
» WarCraft 3 / Как сделать возраждение?
Да, без локальной можно.
Ред. PT153
» WarCraft 3 / Варианты границ карты
Включи среднюю сетку, размер белого квадрата есть 128х128, и именно в них и измеряется размер карты, то есть, выражаясь точнее, когда увеличиваешь или уменьшаешь карту, нужно сделать количество белых квадратов по длине и ширине кратным 32.
Ред. PT153
» WarCraft 3 / Варианты границ карты
Ред. PT153
» WarCraft 3 / Как сделать возраждение?
» WarCraft 3 / Динамический триггер ?!
» WarCraft 3 / Аттач группы триггеров
» WarCraft 3 / Как сделать триггер по типу..
» WarCraft 3 / Как сделать триггер по типу..
Ред. PT153
» WarCraft 3 / Как сделать триггер по типу..
» WarCraft 3 / Как сделать триггер по типу..
» WarCraft 3 / Построение фигур
Atesla:
Ред. PT153
» WarCraft 3 / Как сделать триггер по типу..
Действия: поставить переменной B значение ноль.
Выбрать все предметы в области Х, равкод которых Z, и для каждого сделать Поставить переменной B значение B + 1.
Если B равно 0 создать предмет иначе ничего не делать.
Ред. PT153
» WarCraft 3 / Построение фигур
Ред. PT153
» WarCraft 3 / Аттач группы триггеров
Списки в основном задаются таким макросом.
При удалении объекта системы удаляются и все навешанные баффы.
Каждый бафф - отдельная структура, которая наследуется от общей.