Немного не понял где можно в редакторе объектов прописать это. Не видел такого. нельзя кажись. Можно в гуи в редакторе триггеров посмотреть что за текстура (если они есть), но сейчас мы говорим про удар грома, знаю, что она есть в уберсплате
инструкция
нажимаете "создать уберсплат"
выбираете, смотрите что за текстура (там написано)
можно конвентировать триггеры в код и посмотреть что за текстура (нам нужно взять строку)
Получается "THND"
открываете MPQ master открываешь, в архиве находишь папку splats и оттуда извлекаешь таблицу
в таблице ищешь строчку с названием "THND", записано в ней путь текстуры. Это чтоб не искать текстуры.
Но как писал выше, ищи текстуру по пути replaceable textures/splats
вот там в гуи все ли указаны? неизвестно. Смотрел, что-то в таблице мало текстур (44 шт.). Остальные, что хранятся папке по пути replaceable textures/splats, это рассовые (типа A_OrcUberSplat.blp и B_OrcUberSplat.blp и так далее - не понял что значат, и даже не разбирался, больно надо
можешь попробовать свой сплат сделать. Берешь таблицу, прописываешь новый код, новый путь текстурке и др.
Ну это можно для заклинаний и прочее применить. Да можно и без эффекта. Это типа поверхностные картинки всяких кратеров, поверхностей и прочее. Их можно удалить.
для тех кто не знает, чтобы появились нужно прописать (в разделе триггеры - текстура земли). для замены: лежат по пути replaceable textures/splats
аналогично и с изображением Image (в разделе триггеры - изображение)
долго пробовал создавать, у меня что-то не отображалась ни фига без render always state и rendering state. Вообще-то большинство сплатов, и image могут без rendering state отобразиться. А еще вот с изображением image какие-то траблы. если импортировать в изображение какую-нибудь иконку, то бывает текстура изображения почему то размыта или черные квадраты. Создать легко, но часто не прорисовываются изображения норм, и приходится мучаться с переделками иконок. Поможет статья см. ниже
создать uberspat с настройками (boolean forcePaused, boolean noBirthTime). Что значат эти настройки не знаю.
native CreateUbersplat takes real x, real y, string name, integer red, integer green, integer blue, integer alpha, boolean forcePaused, boolean noBirthTime returns ubersplat
разблокирование для показа самого изображения (типа прорисовывается изображение). Без этой команды бывает не отображает уберсплат. Если поставить false, то изображение пропадает. Зачем тогда нужна команда ShowUbersplat?
native SetUbersplatRenderAlways takes ubersplat whichSplat, boolean flag returns nothing
разблокирование во избежание глюков (не знаю что это значит). Как-то связана с отображением, без этой команды в некоторых случаях, видимо, не работает уберсплат.
native SetUbersplatRender takes ubersplat whichSplat, boolean flag returns nothing
показать/спрятать
native ShowUbersplat takes ubersplat whichSplat, boolean flag returns nothing
local group = CreateGroup()
local unit e
//выбираете всех юнитов группу g, есть в комменте (http://xgm.guru/p/wc3/187447?postid=345848#comment10) описание всех выборок, начинающих на GroupEnum..
call GroupEnumUnitsInRange(g, x, y, 400., null)
//цикл
loop
set e = FirstOfGroup(g)
exitwhen e == null
//какое-то действие, что-то делаешь с юнитом e
call GroupRemoveUnit(g,e)
endloop
call DestroyGroup(g)
что-то похожее есть вот здесь или тут или тут кому надо найдет на сайте
Следует предположение, что как только дамми получает приказ применить способность на основе Предмет:Иллюзии, условие IsUnitIllusion просто не успевает какаим-то образом сделать проверку =/
Почему каким-то?
Proshel_Doty, ну возможно они еще не созданы при касте, поэтому лови через определенное время таймером (0.00 сек или 0.01 и так далее). Лучше проверять событием - юнит вызывает боевую единицу, засовывать в группу и так далее
да, есть такое (не 270, а 240). например, у друидов-медведей не меняет угол, а у друидов-воронов меняет. ворон поворачивается до превращения. Как-то только опуститься вниз, то перевоплощается в другую форму. Думал, связано это с абилкой, пробовал другие, одно и тоже. можно периодически таймером заставлять не изменять угол поворота, и он останется таким-же
с чем связано неизвестно и бесполезно думать об этом
вот скинул наработку. это примерно, на скорую руку. вейты и прочее. нужно точное время отсчитать от каста до окончательного поворота (я от балды поставил вейт 1 сек.), на гуи
ScopteRectuS, тоже такое делал. Помню, надо было найти площадку для стройки, задавал вопрос, и там перебирал каждую точку loop'ами. Но выяснил, что такую работу до конца не выполняет, обрыв. Приходилось там где есть лупы, отделять, и в другую функцию вставлять эти циклы. чтобы потом отдельный поток создавать через ExcecuteFunc.Только так он работал у меня
вот примеры. Ничего нового в них нет. Один пример - код из доты про рексара с топорами, и второй по параболе (там подумал еще и поднимать, и двигать в бок), единственное, что не написал возвращение. Просто лень было. Darknessay, радиус очень сложно вычислить. Это тебе не окружность или сфера, где идеально круглое. там что вроде овала, эллипса. мб есть какие-то способы, но чтобы сделать = надо знать математику хорошо (там геометрия, тригонометрия, матрица и др)
раскрыть
радиус можно выяснить по теореме пифагора. Помнишь прямоугольный треугольник. Там есть два катета, и гипотенуза (гипотенуза это и есть радиус). горизонтальный катет = d/2, вертикальный катет = h. И там ищи по теореме пифагора. Зная, значения двух катетов, можно еще и узнать и угол (если он нужен).
// OpenDota 6.41 deprotected by NETRAT and DioD
// inspired by everyone who posted on forum threads and feedback page
// based on OpenDota 6.32b, deprotected by DimonT, NETRAT and TheBloodiest
// http://dimon.xgm.ru/opendota/
// Visit our modmaking community at http://xgm.ru/
// Objects used:
// 'A0O1' = Wild Axes (Beastmaster : Rexxar)
// 'A04R' = Marker (Nether Ward 4,Lightning Bolter,Nether Ward 3,Nether Ward 2,Vengeance Death caster,...)
// 'e01T' = Boomerang
// 'Amrf' = Crow Form (Medivh)
// DEBUG Trigger Number : 34
function WildAxesSpell takes nothing returns boolean
return GetSpellAbilityId()=='A0O1'
endfunction
function WildAxesTreeCut takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
function WildAxesDamage takes unit pWho,real pxx,real pyy,group pVictims returns nothing
local group lGroup=CreateGroup()
local unit lTMP
local rect lMx=Rect(pxx-150,pyy-150,pxx+150,pyy+150)
call GroupEnumUnitsInRange(lGroup,pxx,pyy,150,null)
loop
set lTMP=FirstOfGroup(lGroup)
exitwhen lTMP==null
if(IsUnitInGroup(lTMP,pVictims)==false and IsUnitEnemy(lTMP,GetOwningPlayer(pWho))and IsUnitVisible(lTMP,GetOwningPlayer(pWho)))then
if(GetUnitAbilityLevel(lTMP,'A04R')!=1 and GetUnitState(lTMP,UNIT_STATE_LIFE)>0 and IsUnitType(lTMP,UNIT_TYPE_STRUCTURE)==false)then
call GroupAddUnit(pVictims,lTMP)
call UnitDamageTarget(pWho,lTMP,60+GetUnitAbilityLevel(pWho,'A0O1')*30,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_METAL_HEAVY_SLICE)
call AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl",lTMP,"overhead")
endif
endif
call GroupRemoveUnit(lGroup,lTMP)
endloop
call EnumDestructablesInRect(lMx,null,function WildAxesTreeCut)
call RemoveRect(lMx)
call DestroyGroup(lGroup)
endfunction
function WildAxesTimer takes nothing returns nothing
local string lTable=H2Tx(GetExpiredTimer())
local unit lAxe=GetUnit(lTable,"Axe")
local unit lCaster=GetUnit(lTable,"Hero")
local real lAx=GetReal(lTable,"Ax")
local real lAy=GetReal(lTable,"Ay")
local real lCx=GetReal(lTable,"Cx")
local real lCy=GetReal(lTable,"Cy")
local real lBx=GetReal(lTable,"Bx")
local real lBy=GetReal(lTable,"By")
local real laa=GetReal(lTable,"a")
local real lbb=1-laa
local boolean lIsPassed=GetBoolean(lTable,"FirstPass")
local group lCheckGroup=GetGroup(lTable,"AlreadyDamaged")
call SetUnitX(lAxe,SafeX(lAx*laa*laa+lBx*2*laa*lbb+lCx*lbb*lbb))
call SetUnitY(lAxe,SafeY(lAy*laa*laa+lBy*2*laa*lbb+lCy*lbb*lbb))
call WildAxesDamage(lCaster,GetUnitX(lAxe),GetUnitY(lAxe),lCheckGroup)
if(lIsPassed)then
call SetReal(lTable,"a",laa-.02)
else
call SetReal(lTable,"a",laa+.02)
call SetReal(lTable,"Ax",GetUnitX(lCaster))
call SetReal(lTable,"Ay",GetUnitY(lCaster))
endif
if(laa<0 and lIsPassed)then
call SetBoolean(lTable,"FirstPass",false)
call SetReal(lTable,"Bx",lAx+300*Cos(Atan2(lCy-lAy,lCx-lAx)+GetReal(lTable,"AngleOffset")))
call SetReal(lTable,"By",lAy+300*Sin(Atan2(lCy-lAy,lCx-lAx)+GetReal(lTable,"AngleOffset")))
endif
if(laa>1 and lIsPassed==false)then
call PauseTimer(GetExpiredTimer())
call DestroyGroup(lCheckGroup)
call FastFlush(lTable)
call RemoveUnit(lAxe)
call DestroyTimer(GetExpiredTimer())
endif
endfunction
function WildAxesSettings takes nothing returns nothing
local unit lCaster=GetTriggerUnit()
local real lCasterX=GetUnitX(lCaster)
local real lCasterY=GetUnitY(lCaster)
local real lTargetX=GetLocationX(GetSpellTargetLoc())
local real lTargetY=GetLocationY(GetSpellTargetLoc())
local unit lAxe1=CreateUnit(GetOwningPlayer(lCaster),'e01T',lCasterX,lCasterY,270.)
local unit lAxe2=CreateUnit(GetOwningPlayer(lCaster),'e01T',lCasterX,lCasterY,270.)
local string lTable1
local string lTable2
local timer lTimer1=CreateTimer()
local timer lTimer2=CreateTimer()
if GetSpellTargetUnit()!=null then
set lTargetX=GetUnitX(GetSpellTargetUnit())
set lTargetY=GetUnitY(GetSpellTargetUnit())
endif
call UnitAddAbility(lAxe1,'Amrf')
call UnitRemoveAbility(lAxe1,'Amrf')
call SetUnitFlyHeight(lAxe1,150,0)
call UnitAddAbility(lAxe2,'Amrf')
call UnitRemoveAbility(lAxe2,'Amrf')
call SetUnitFlyHeight(lAxe2,150,0)
set lTable1=H2Tx(lTimer1)
call SetHandle(lTable1,"Hero",lCaster)
call SetHandle(lTable1,"Axe",lAxe1)
call SetHandle(lTable1,"AlreadyDamaged",CreateGroup())
call SetReal(lTable1,"Ax",lCasterX)
call SetReal(lTable1,"Ay",lCasterY)
call SetReal(lTable1,"Cx",lTargetX)
call SetReal(lTable1,"Cy",lTargetY)
call SetReal(lTable1,"Bx",lCasterX+300*Cos(Atan2(lTargetY-lCasterY,lTargetX-lCasterX)+45))
call SetReal(lTable1,"By",lCasterY+300*Sin(Atan2(lTargetY-lCasterY,lTargetX-lCasterX)+45))
call SetReal(lTable1,"a",1)
call SetReal(lTable1,"AngleOffset",-45)
call SetBoolean(lTable1,"FirstPass",true)
set lTable2=H2Tx(lTimer2)
call SetHandle(lTable2,"Hero",lCaster)
call SetHandle(lTable2,"Axe",lAxe2)
call SetHandle(lTable2,"AlreadyDamaged",CreateGroup())
call SetReal(lTable2,"Ax",lCasterX)
call SetReal(lTable2,"Ay",lCasterY)
call SetReal(lTable2,"Cx",lTargetX)
call SetReal(lTable2,"Cy",lTargetY)
call SetReal(lTable2,"Bx",lCasterX+300*Cos(Atan2(lTargetY-lCasterY,lTargetX-lCasterX)-45))
call SetReal(lTable2,"By",lCasterY+300*Sin(Atan2(lTargetY-lCasterY,lTargetX-lCasterX)-45))
call SetReal(lTable2,"a",1)
call SetReal(lTable2,"AngleOffset",45)
call SetBoolean(lTable2,"FirstPass",true)
call TimerStart(lTimer1,.025,true,function WildAxesTimer)
call TimerStart(lTimer2,.025,true,function WildAxesTimer)
endfunction
function WildAxesInit takes nothing returns nothing
local trigger ltt=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(ltt,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(ltt,Condition(function WildAxesSpell))
call TriggerAddAction(ltt,function WildAxesSettings)
endfunction
function InitTrig_Wild_Axes takes nothing returns nothing
endfunction
код новой доты
function R92 takes nothing returns boolean
return GetSpellAbilityId()==1093685041
endfunction
function LWI takes nothing returns boolean
return true
endfunction
function T5I takes destructable d returns boolean
return GetDestructableTypeId(d)==1314157667 or GetDestructableTypeId(d)==1314157687 or GetDestructableTypeId(d)==1096053874 or GetDestructableTypeId(d)==1110454322 or GetDestructableTypeId(d)==1110454323 or GetDestructableTypeId(d)==1110454325
endfunction
function QDI takes nothing returns nothing
if T5I(GetEnumDestructable())and IsDestructableAliveBJ(GetEnumDestructable())then
set JJ=JJ+1
call KillDestructable(GetEnumDestructable())
endif
endfunction
function QEI takes real x,real y,real d returns integer
local rect r=Rect(x-d,y-d,x+d,y+d)
set JJ=0
call EnumDestructablesInRect(r,Condition(function LWI),function QDI)
call RemoveRect(r)
set r=null
return JJ
endfunction
function PAI takes real x1,real y1,real x2,real y2 returns real
return SquareRoot(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)))
endfunction
function RGI takes real y returns real
local real RDI=GetRectMinY(bj_mapInitialPlayableArea)+50
if(y<RDI)then
return RDI
endif
set RDI=GetRectMaxY(bj_mapInitialPlayableArea)-50
if(y>RDI)then
return RDI
endif
return y
endfunction
function RCI takes real x returns real
local real RDI=GetRectMinX(bj_mapInitialPlayableArea)+50
if(x<RDI)then
return RDI
endif
set RDI=GetRectMaxX(bj_mapInitialPlayableArea)-50
if(x>RDI)then
return RDI
endif
return x
endfunction
function MCI takes group g returns nothing
local integer i=GetHandleId(g)-UY
if i<0 or i>120 then
set OJ=true
else
call GroupClear(g)
set QY[i]=false
set IJ=i
endif
endfunction
function RA2 takes unit R7I,real x,real y,group WVO returns nothing
local group GK1=MDI()
local unit V11
call QEI(x,y,150)
call GroupEnumUnitsInRange(GK1,x,y,150,Condition(function LWI))
loop
set V11=FirstOfGroup(GK1)
exitwhen V11==null
if(IsUnitInGroup(V11,WVO)==false and IsUnitEnemy(V11,GetOwningPlayer(R7I)))then
if(GetUnitAbilityLevel(V11,1093678162)!=1 and GetUnitState(V11,UNIT_STATE_LIFE)>0 and IsUnitType(V11,UNIT_TYPE_STRUCTURE)==false)then
call GroupAddUnit(WVO,V11)
call UnitDamageTarget(R7I,V11,60+GetUnitAbilityLevel(R7I,1093685041)*30,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_METAL_HEAVY_SLICE)
call AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl",V11,"overhead")
endif
endif
call GroupRemoveUnit(GK1,V11)
endloop
call MCI(GK1)
endfunction
function RB2 takes nothing returns nothing
local integer MKI=GetHandleId(GetExpiredTimer())
local unit RC2=(LoadUnitHandle(XY,(MKI),(290))) //дайми
local unit N0I=(LoadUnitHandle(XY,(MKI),(14))) //кастер
//координаты кастера
local real Ax=(LoadReal(XY,(MKI),(284)))
local real Ay=(LoadReal(XY,(MKI),(285)))
//координаты цели
local real Cx=(LoadReal(XY,(MKI),(286)))
local real Cy=(LoadReal(XY,(MKI),(287)))
local real Bx=(LoadReal(XY,(MKI),(288)))
local real By=(LoadReal(XY,(MKI),(289)))
local real a=(LoadReal(XY,(MKI),(137)))
local real b=1-a
local boolean RD2=(LoadBoolean(XY,(MKI),(291)))
local group WVO=(LoadGroupHandle(XY,(MKI),(133)))
local real RE2=RMaxBJ(PAI(Ax,Ay,Cx,Cy)/1300,0.4)
call SetUnitX(RC2,RCI(Ax*a*a+Bx*2*a*b+Cx*b*b))
call SetUnitY(RC2,RGI(Ay*a*a+By*2*a*b+Cy*b*b))
call RA2(N0I,GetUnitX(RC2),GetUnitY(RC2),WVO)
if(RD2)then
call SaveReal(XY,(MKI),(137),((a-.02/RE2)*1.0))
else
call SaveReal(XY,(MKI),(137),((a+.02/RE2)*1.0))
call SaveReal(XY,(MKI),(284),((GetUnitX(N0I))*1.0))
call SaveReal(XY,(MKI),(285),((GetUnitY(N0I))*1.0))
endif
if(a<0 and RD2)then
call SaveBoolean(XY,(MKI),(291),(false))
call SaveReal(XY,(MKI),(288),((Ax+300*Cos(Atan2(Cy-Ay,Cx-Ax)+(LoadReal(XY,(MKI),(292)))))*1.0))
call SaveReal(XY,(MKI),(289),((Ay+300*Sin(Atan2(Cy-Ay,Cx-Ax)+(LoadReal(XY,(MKI),(292)))))*1.0))
endif
if(a>1 and RD2==false)then
call PauseTimer(GetExpiredTimer())
call MCI(WVO)
call FlushChildHashtable(XY,(MKI))
call RemoveUnit(RC2)
call DestroyTimer(GetExpiredTimer())
endif
endfunction
function LGI takes nothing returns nothing
call DisplayTimedTextToPlayer(GetEnumPlayer(),0,U2,YJ,XJ)
endfunction
function LHI takes force LZI,real KLI,string LVI returns nothing
set XJ=LVI
set YJ=KLI
call ForForce(LZI,function LGI)
endfunction
function MDI takes nothing returns group
local integer i=IJ
loop
exitwhen i==IJ-1
if QY[i]==false then
set IJ=i+1
if IJ==120 then
set IJ=0
endif
set QY[i]=true
return PY[i]
endif
set i=i+1
if i==120 then
set i=0
endif
endloop
call LHI(P2,5.00,"|c00ff0303CRITICAL ERROR: FOUND NO AVAILABLE GROUPS|r")
call LHI(P2,5.00,"|c00ff0303Send this replay to IceFrog@gmail.com|r")
return CreateGroup()
endfunction
function QTI takes unit N0I,integer QRI returns nothing
call UnitAddAbility(N0I,QRI)
call UnitMakeAbilityPermanent(N0I,true,QRI)
endfunction
function RF2 takes nothing returns nothing
local unit R7I=GetTriggerUnit()
//координаты кастера
local real Ax=GetUnitX(R7I)
local real Ay=GetUnitY(R7I)
//координаты цели
local real Cx=GetLocationX(GetSpellTargetLoc())
local real Cy=GetLocationY(GetSpellTargetLoc())
//создать dummy
local unit RG2=CreateUnit(GetOwningPlayer(R7I),1697657172,Ax,Ay,270.0)
local unit RH2=CreateUnit(GetOwningPlayer(R7I),1697657172,Ax,Ay,270.0)
//вводят для хэндлов дайми (это нужно для ключа хэша)
local integer RZ2
local integer RV2
//создаем для каждого дайми таймер
local timer RW2=CreateTimer()
local timer RX2=CreateTimer()
if GetSpellTargetUnit()!=null then
set Cx=GetUnitX(GetSpellTargetUnit())
set Cy=GetUnitY(GetSpellTargetUnit())
endif
//добавляет какие-то способности для дайми (видимо дает способность ворона - летать)
call QTI(RG2,1097691750)
call UnitRemoveAbility(RG2,1097691750)
call SetUnitFlyHeight(RG2,150,0)
call QTI(RH2,1097691750)
call UnitRemoveAbility(RH2,1097691750)
call SetUnitFlyHeight(RH2,150,0)
set RZ2=GetHandleId(RW2) //хэндл таймера
call SaveUnitHandle(XY,(RZ2),(14),(R7I)) //кастер
call SaveUnitHandle(XY,(RZ2),(290),(RG2)) //дайми
call SaveGroupHandle(XY,(RZ2),(133),(MDI())) //добавляет созданную группу, функция MDI какие-то счетчики делает и прочую херню
//сохраняем координаты кастера
call SaveReal(XY,(RZ2),(284),((Ax)*1.0))
call SaveReal(XY,(RZ2),(285),((Ay)*1.0))
//сохраняем координаты цели
call SaveReal(XY,(RZ2),(286),((Cx)*1.0))
call SaveReal(XY,(RZ2),(287),((Cy)*1.0))
//сохраняем
call SaveReal(XY,(RZ2),(288),((Ax+300*Cos(Atan2(Cy-Ay,Cx-Ax)+45))*1.0))
call SaveReal(XY,(RZ2),(289),((Ay+300*Sin(Atan2(Cy-Ay,Cx-Ax)+45))*1.0))
call SaveReal(XY,(RZ2),(137),((1)*1.0))
call SaveReal(XY,(RZ2),(292),((-45)*1.0))
call SaveBoolean(XY,(RZ2),(291),(true))
set RV2=GetHandleId(RX2)
call SaveUnitHandle(XY,(RV2),(14),(R7I))
call SaveUnitHandle(XY,(RV2),(290),(RH2))
call SaveGroupHandle(XY,(RV2),(133),(MDI()))
call SaveReal(XY,(RV2),(284),((Ax)*1.0))
call SaveReal(XY,(RV2),(285),((Ay)*1.0))
call SaveReal(XY,(RV2),(286),((Cx)*1.0))
call SaveReal(XY,(RV2),(287),((Cy)*1.0))
call SaveReal(XY,(RV2),(288),((Ax+300*Cos(Atan2(Cy-Ay,Cx-Ax)-45))*1.0))
call SaveReal(XY,(RV2),(289),((Ay+300*Sin(Atan2(Cy-Ay,Cx-Ax)-45))*1.0))
call SaveReal(XY,(RV2),(137),((1)*1.0))
call SaveReal(XY,(RV2),(292),((45)*1.0))
call SaveBoolean(XY,(RV2),(291),(true))
call TimerStart(RW2,.025,true,function RB2)
call TimerStart(RX2,.025,true,function RB2)
endfunction
function Q8I takes nothing returns boolean
return true
endfunction
function Q9I takes trigger t,playerunitevent QAI returns nothing
local integer L9I=0
loop
call TriggerRegisterPlayerUnitEvent(t,Player(L9I),QAI,Condition(function Q8I))
set L9I=L9I+1
exitwhen L9I==16
endloop
endfunction
function V51 takes nothing returns nothing
local trigger t=CreateTrigger()
call Q9I(t,EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t,Condition(function R92))
call TriggerAddAction(t,function RF2)
endfunction
в новой доте в коде еще кучу глобальных переменных намешаны. мне лень короч разбираться что это за переменные. завтра подробно рассмотрю этот код рексара. мне интересно как он там так двигается. проще взять код из старой опен доты и переделать, и постоянно сравнить с новым. Практически одинаков
дождись клампа
Погоди, так, момент, как может быть парабола не по Z, если при параболе юнит летит по прямой, только высота меняется, а тут он должен лететь дугой?
можно одновременно две вещи сделать (поворачивать дугой, и поднимать по оси Z), просто не знал, что тебе надо.
примерно сделал, Ушло 5-10 часов на это математикой занимался, тригонометрию чутка подучил, пытался вставить и прочее.
угол дуги можно отсчитать если знать расстояние между кастером и целью и высоту дуги. Парабола не только для прыжков подходит, но и для 2D движения.
Подойдет? время таймера не забудь изменить, просто для себя в качестве проверки делал.
Можно еще через эллипс сделать, но я так и не понял как там. Перечитывал статьи про эллипс, столько времени на эллипс убил.
раскрыть
Хотел сделать что-то вроде эллипса, используя нашу параболу, Проблема такая, летит плавно. Но эллипс по неведомым причинам становится огромным (юнит частенько за пределы карты вылезает), и поэтому не достигает точки. Проверка не может длину нормально проверить (если задать предел расстояния между кастером и целью 1000, то юнит где-то на половине дуги эллипса останавливается) =( возможно ошибка в моей невнимательности. Поэтому эллипс не смог заюзать
код
function Trig_Cast_Conditions takes nothing returns boolean
return( GetSpellAbilityId() == 'A000' )
endfunction
function ParabolaZ takes real h, real d, real x returns real
return (4 * h / d) * (d - x) * (x / d)
endfunction
function Trig_Cast_Actions1 takes nothing returns nothing
//запущенный таймер и его id-хэндл
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit dummy = LoadUnitHandle(udg_Hash,id,0) //dummy
local real angle = LoadReal(udg_Hash,id,1) //угол поворота
local real h = LoadReal(udg_Hash,id,2) //высота дуги
local real d1 = LoadReal(udg_Hash,id,3) //длина дуги
local real e = LoadReal(udg_Hash,id,4)
//координаты кастера = начальная точка дуги A
local real x1 = LoadReal(udg_Hash,id,5)
local real y1 = LoadReal(udg_Hash,id,6)
//конечная точка дуги A2
local real x2 = LoadReal(udg_Hash,id,7)
local real y2 = LoadReal(udg_Hash,id,8)
//определение длины d2 между dummy и конечной точкой A1
local real dx = x2-GetUnitX(dummy)
local real dy = y2-GetUnitY(dummy)
local real d2 = SquareRoot(dx*dx + dy*dy)
//ввожу переменные для будущих вычислений
local real p //достаю нужную высоту с помощью функции параболы
local real A //угол параболы = не пригодился.
local real D //длина эллипса = не пригодился.
local real x
local real y
//на каждый тик таймера отодвигаем на 50 единиц (можно задать больше или меньше, например 70 или 100 на ваше усмотрение)
//e - пройденная длина от начальной A1 точки дуги, с помощью ее достаем нужную высоту p
set e = e + 50.
set p = ParabolaZ(h,d1,e)
set A = p/e
set D = SquareRoot(e*e* ((1-Cos(A)*2)/2)+ p*p* ((1+Cos(A)*2)/2))
set x = x1 + (e * Cos(angle) - p * Sin(angle)) //e*Cos(angle+A)
set y = y1 + (e * Sin(angle) + p * Cos(angle)) //p*Sin(angle+A)
call SaveReal(udg_Hash,id,4,e) //расстояние от dummy до конечной точки дуги
if GetRectMinX(bj_mapInitialPlayableArea) < x1 and GetRectMaxX(bj_mapInitialPlayableArea) > x1 and GetRectMinY(bj_mapInitialPlayableArea) < y1 and GetRectMaxY(bj_mapInitialPlayableArea) > y1 then
call SetUnitX(dummy,x)
call SetUnitY(dummy,y)
else
set d2 = 0
endif
call BJDebugMsg("дистанция между точками dummy и конечной точки дуги d: " + R2S(d2))
call BJDebugMsg("мнимая дистанция (пройденный путь от начальной точки дуги) e: " + R2S(e))
call BJDebugMsg("длина элипса D: " + R2S(D))
call BJDebugMsg("угол дуги А: " + R2S(A* bj_RADTODEG))
if d2 <= 50 then
call PauseTimer(t)
call DestroyTimer(t)
call FlushChildHashtable(udg_Hash,id)
endif
set t = null
set dummy = null
endfunction
function Trig_Cast_Actions takes nothing returns nothing
//кастер
local unit u = GetTriggerUnit()
//координаты кастера
local real x1 = GetUnitX(u)
local real y1 = GetUnitY(u)
//угол поворота кастера
local real angle = GetUnitFacing(u) * bj_DEGTORAD
//длина дуги = задаем нужную длину дуги
local real d = 1000.
//высота дуги = задаем нужную высоту дуги
local real h = 300
//координаты конечной точки типа цели или точки. В данном случае, берем точку впереди на d
//Примечание: Если вы берете координаты точки каста, то нужно будет высчитать длину дуги
//У дуги две крайние точки: A1 = точка кастера, A2 = конечная точка
local real x2 = x1 + d * Cos(angle)
local real y2 = y1 + d * Sin(angle)
//рандом определяет по какой траектории дуги будет лететь вправо или влево
local integer Random = GetRandomInt(0,1)
//dummy-юнит, снаряд
local unit dummy = CreateUnit(GetTriggerPlayer(),'ewsp',x1,y1,GetUnitFacing(u))
local timer t = CreateTimer()
local integer id = GetHandleId(t)
if Random == 1 then //Если Random равен единице, то делаем высоту отрицательной. Тогда будет лететь в другую сторону
set h = h * (-1)
endif
call SaveUnitHandle(udg_Hash,id,0,dummy)
call SaveReal(udg_Hash,id,1,angle)
call SaveReal(udg_Hash,id,2,h)
call SaveReal(udg_Hash,id,3,d)
call SaveReal(udg_Hash,id,4,0) //счетчик. сохраняем ноль. считывает нужное расстояние от начало A1 до конца A2 дуги
call SaveReal(udg_Hash,id,5,x1)
call SaveReal(udg_Hash,id,6,y1)
call SaveReal(udg_Hash,id,7,x2)
call SaveReal(udg_Hash,id,8,y2)
call TimerStart(t,0.4,true,function Trig_Cast_Actions1)
set u = null
set dummy = null
set t = null
endfunction
//===========================================================================
function InitTrig_Cast takes nothing returns nothing
set gg_trg_Cast = CreateTrigger( )
call TriggerRegisterPlayerUnitEventSimple( gg_trg_Cast, Player(0), EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Cast, Condition( function Trig_Cast_Conditions ) )
call TriggerAddAction( gg_trg_Cast, function Trig_Cast_Actions )
endfunction
Кстати я как всегда немного поспешил, нужно исправить вот тут
раскрыть
if d2 <= 50 then
call PauseTimer(t)
call DestroyTimer(t)
call FlushChildHashtable(udg_Hash,id)
endif
тоже купил бы. Проблема еще в том, что я уже практически не играю в варик, только ради редактора сижу маленько. Что-то делаю, для своей карты. И пока ни разу не выпустил карты....медленно делаю, 5 раз удалял карты до ... Necris делаю, наполеоновские планы насчет нее. Мне нравится идея, но сама карта надоела (сырая), требует скорейшего добавления чего нового. Если это будет в редакторе, то это упростит, этого не хватало в карте
Есть ли возможность сделать то же без перебора группы?
Нативки такой не видел, нет такой. Есть близзардская Bj-функция CountUnitsInGroup, там перебираем всех и складываем. И нативку GetPlayerStructureCount, показывающую, видимо, кол-во здании
отслеживать появление и исчезновение юнитов с карты с помощью счетчика. При появлении +1, при исчезновении -1. Нужно продумать все факторы: например, юнит красного игрока (-1) перешел на сторону синего игрока (+1) (короче смена хозяина). При событии юнит входит в зону может отслеживать москитов, призывников, что может не всегда нужно. Труднее отследить исчезновение, ведь неизвестно, что вам нужно? только живые? смерть отслеживанием событием юнит умирает (-1). Но этот труп можно воскресить (+1). Если нужно отследить исчезновение трупа юзаем (событие - юнит вышел из региона).
Знаю может быть муторным делом, но если проработать, то не нужно циклом будет делать. Сразу из переменной доставать значение будешь. Либо с группой (Bj-функция CountUnitsInGroup или loop с FirstOfGroup, по-другому никак. Но у тебя BJ-функция GetUnitsInRectOfPlayer утекает =(( и группой в конце не удаляем
Мои скиллы не действуют на всю карту, но я должен на будущее знать, будет ли это работать, если прописать радиус меньше дальности скилла. Получается можно удалить строку, отвечающую за радиус?
что тут не понятного. ну ты берешь все итемы в области с помощью Pick every item in ... и начинаешь перебирать. Это обычный же цикл. Как это работает? Эта команда Pick every item in ... - цикл, берет все предметы, затем берет один предмет в переменную Picked Item, что-то с ним делаем, Потом берет второй в переменную Picked Item, и также что-то делаем с этим предметом, и так далее. Но можно внутри этого цикла счетчик намутить. целочисленная переменная count - счетчик. Если у тебя 5 предметов, то можешь 5 действий совершить, короче будет 5 раз прибавлять число в count +1.
Честно, как-то лень объяснять. Если надо, проверить тип. То можно фильтр вставить с проверкой (типа matching item == цветок) или внутри вставить конструкцию if then endif с проверкой типа (Picked item == цветок). В фильтрах используют переменные matching item а в циклах Picked item
С рунами, кстати, есть проблема. Это всякие монетки, книжки, зведолисты и прочее. Когда ты подбираешь, они исчезают, короче ничего в инвентарь себе не положишь. Но на карте эти руны остаются, и поэтому счетчик будет прибавлять и их. Из-за чего будет неправильное количество отображать. Есть даже статья
Чтобы такого не было, при подборе удаляйте руны (они ведь исчезают)
Так для "не смотрит" нужно чтобы юнит попал в большой промежуток?
да, тебе выше скрин даже нарисовал. в твоем случае, как определить видит ли цель кастера, то очень подойдет. для твоего скила "удар в спину". Есть другие примеры, может они то тебе подойдут. Загляни на хабр по ссылке, там точь твой вариант, описывают пример про стражника (если не понятно, смотри у меня скалярные векторы в комменте 6, 7). Конечно, тебе немного переделать надо будет, вместо кастера цель.
Если способность, скажем, через всю карту используется, а тут указывается радиус - если кастер будет за радиусом, что тогда?
если ты про молнии, то тут у меня никакого ограничительного радиуса нет. Есть радиус круга = 800, но это чисто для молнии, не стал молнии растягивать на всю карту.
В первом случае, работы со многими юнитами включает с группой, там есть ограничение радиуса - сам радиус. Когда ты пикаешь вокруг юнитов в группу, есть функции, которые выбирают всех вокруг точки с радиусом. Вот это я и использовал. Если надо убрать ограничение, используй другие функции пика на всю карту, или ставь радиус 99999
В случае, с треугольником. Можно, вместо треугольника вставлять прямоугольник =)
Во втором случае, там с одним юнитом (не работаю с группой). Коммент 7 скинул пример. Там нет ограничения, и можно на всю карту. Есть надо ограничить, тогда надо еще проверять расстояние между двумя юнитами. Если расстояние между двумя юнитами меньше 800, то делать ...
Обзор_в_180_градусовсделано для новичков
На основе взяты выше перечисленные примеры. Можете проверить стоит ли впереди или нет.
Кстати, формула Warden работает не так как хотелось бы. Тестировал. И выяснил, что работает если обзор не слишком большой ( angle < 180, если хотите 180 тогда придется ставить приблизительно 179). Если слишком большой, то не будет работать.
Короче тут формула берет минимальный промежуток между углами, а не большой. Пример на скрине
А так все в норме
Еще не забудьте поставить вместо udg_Target переменную GetSpellTargetUnit()
quq_CCCP, тогда библиотеку всех функции вшить в jngp, включая RenderEdge. Сам хотел попробовать мемхак, так лень разбираться, что надо делать "чтобы это заработало", и не знание чего не дало запустить (обычный мемхак ладно, а RenderEdge...)
как сказал pro100master,
Событие юнит начинает строительство
здание, установлено. Но нужно до конца достроить = (сохраняем true)
Событие юнит прекращает строительство
прервано строительство через кнопку отмена = (сохраняем false)
Событие юнит завершает строительство
здание построенно (сохраняем false)
Событие юнит умирает = с проверкой что это здание и строилось ли оно = (сохраняем ffalse)
true/false - установка в логическую переменную. True говорит о том, что здание строится, а false нет.
можно использовать хэндл + хэш или массивы + цикл для хранения
проще простого, с улучшением здания тоже самое посмотри в гуи - там события про апгрейды (начинает улучшение/прерывает улучшение/ завершает улучшение)
Этого никто не знает. У меня вот ИИ-боты сами новые предметы не могут купить, пока не положишь. Некоторые даже не принимает и продает/выбрасывает (оказывается есть типы итемов, и итемы, которые сделаны на этой основе, ИИ заставляет продавать. Брал другой подходящий тип, который бот не продаст, и им же заменял, или на его основе создавал новый).
не пробовали на триггерах ИИ написать. Это правда может быть сложнее. Щас пробую со системой строительства намутить, пробую полную ветку здании строить. Сами строят. Можно даже отойти чай пить, пока ваши юниты строят. Со строительством может и прокатит, а вот с войсками? Там трудного ничего нет. Нанял, накопил войско. Мне пока не хватает знании, так как классический вар мало играю. Не знаю каких юнитов нужно нанимать и в каких количества, там порядок. В битве какие заклинания применять и прочее? Это оказалось сложнее, много всего
Ред. MpW
» WarCraft 3 / ubersplat
» WarCraft 3 / ubersplat
Ред. MpW
» WarCraft 3 / ubersplat
для тех кто не знает, чтобы появились нужно прописать (в разделе триггеры - текстура земли). для замены: лежат по пути replaceable textures/splats
https://www.xgm.guru/forum/showthread.php?t=40213
https://www.xgm.guru/forum/showthread.php?t=30539
» WarCraft 3 / Высота юнита GetUnitZ
Ред. MpW
» WarCraft 3 / Изменение Последователиносте работы цыкла
» WarCraft 3 / Не работает IsUnitIllusion
Ред. MpW
» WarCraft 3 / Юнит при приземлении после "превращения" поворачивается в 270
с чем связано неизвестно и бесполезно думать об этом
вот скинул наработку. это примерно, на скорую руку. вейты и прочее. нужно точное время отсчитать от каста до окончательного поворота (я от балды поставил вейт 1 сек.), на гуи
» WarCraft 3 / Юнит при приземлении после "превращения" поворачивается в 270
Ред. MpW
» WarCraft 3 / Количество операций в одном потоке
Ред. MpW
» WarCraft 3 / Полет снаряда по дуге
Darknessay, радиус очень сложно вычислить. Это тебе не окружность или сфера, где идеально круглое. там что вроде овала, эллипса. мб есть какие-то способы, но чтобы сделать = надо знать математику хорошо (там геометрия, тригонометрия, матрица и др)
Ред. MpW
» WarCraft 3 / Полет снаряда по дуге
дождись клампаРед. MpW
» WarCraft 3 / Полет снаряда по дуге
угол дуги можно отсчитать если знать расстояние между кастером и целью и высоту дуги.
Парабола не только для прыжков подходит, но и для 2D движения.
Подойдет? время таймера не забудь изменить, просто для себя в качестве проверки делал.
Можно еще через эллипс сделать, но я так и не понял как там. Перечитывал статьи про эллипс, столько времени на эллипс убил.
» WarCraft 3 / Полет снаряда по дуге
Ред. MpW
» WarCraft 3 / Blizzard готовят Producer Update для Warcraft 3
Ред. MpW
» WarCraft 3 / Как на Jass быстро посчитать количество боевых единиц?
отслеживать появление и исчезновение юнитов с карты с помощью счетчика. При появлении +1, при исчезновении -1. Нужно продумать все факторы: например, юнит красного игрока (-1) перешел на сторону синего игрока (+1) (короче смена хозяина). При событии юнит входит в зону может отслеживать москитов, призывников, что может не всегда нужно. Труднее отследить исчезновение, ведь неизвестно, что вам нужно? только живые? смерть отслеживанием событием юнит умирает (-1). Но этот труп можно воскресить (+1). Если нужно отследить исчезновение трупа юзаем (событие - юнит вышел из региона).
Знаю может быть муторным делом, но если проработать, то не нужно циклом будет делать. Сразу из переменной доставать значение будешь. Либо с группой (Bj-функция CountUnitsInGroup или loop с FirstOfGroup, по-другому никак.
Но у тебя BJ-функция GetUnitsInRectOfPlayer утекает =(( и группой в конце не удаляем
» WarCraft 3 / Как создать конусные заклинания?
Ред. MpW
» WarCraft 3 / Функция проверки количества предметов по области
Честно, как-то лень объяснять. Если надо, проверить тип. То можно фильтр вставить с проверкой (типа matching item == цветок) или внутри вставить конструкцию if then endif с проверкой типа (Picked item == цветок). В фильтрах используют переменные matching item а в циклах Picked item
Чтобы такого не было, при подборе удаляйте руны (они ведь исчезают)
» WarCraft 3 / Blizzard готовят Producer Update для Warcraft 3
Ред. MpW
» WarCraft 3 / Функция проверки количества предметов по области
Ред. MpW
» WarCraft 3 / Как создать конусные заклинания?
В первом случае, работы со многими юнитами включает с группой, там есть ограничение радиуса - сам радиус. Когда ты пикаешь вокруг юнитов в группу, есть функции, которые выбирают всех вокруг точки с радиусом. Вот это я и использовал. Если надо убрать ограничение, используй другие функции пика на всю карту, или ставь радиус 99999
Ред. MpW
» WarCraft 3 / Как создать конусные заклинания?
На основе взяты выше перечисленные примеры. Можете проверить стоит ли впереди или нет.
Кстати, формула Warden работает не так как хотелось бы. Тестировал. И выяснил, что работает если обзор не слишком большой ( angle < 180, если хотите 180 тогда придется ставить приблизительно 179). Если слишком большой, то не будет работать.
Короче тут формула берет минимальный промежуток между углами, а не большой. Пример на скрине
Еще не забудьте поставить вместо udg_Target переменную GetSpellTargetUnit()
» WarCraft 3 / Какая то хрень с ифами :(
скидывал тебе это, что не помогло?
и проверяй дебагом, работает = не работает.
Ред. MpW
» WarCraft 3 / Какой должна быть сборка wc3, чтобы делать карту в 2к18?
Ред. MpW
» WarCraft 3 / Как определить, находится ли в процессе постройки/улучшения здан
Событие юнит начинает строительство
здание, установлено. Но нужно до конца достроить = (сохраняем true)
прервано строительство через кнопку отмена = (сохраняем false)
здание построенно (сохраняем false)
проще простого, с улучшением здания тоже самое посмотри в гуи - там события про апгрейды (начинает улучшение/прерывает улучшение/ завершает улучшение)
Ред. MpW
» WarCraft 3 / Заставить ИИ юзать Морф