- Joined
- Apr 8, 2011
- Messages
- 108
JASS:
library AttacksEngine initializer Init requires MainEngine, SkillsDatabase, Movement
// globals
CastData CastStack[]
private trigger Attack = CreateTrigger(), Cast = CreateTrigger()
private int TempSource, Stack = 0
int last_CastData = 0
unit last_CastTargetUnit
real last_Target_X, last_Target_Y
real SpellX, SpellY
group CastGroup = CG
trigger CastBreak = CreateTrigger()
define {
CAST_BAR_UNIT = 'h001'
CAST_CHANNEL_SKILL = 'A01C'
}
struct CastData
unit caster, bar, target
real cast_time, targ_x, targ_y
int skill, level
endstruct
int GetUnitCastData(unit A){
int index = 0
while(index++ < Stack){
if A == CastStack[index].caster { last_CastData = index ;return index }
}
return 0
}
//===========================================================================
void BreakCast(unit A){
int data = GetUnitCastData(A)
UD unit_data = GetData(A)
RemoveUnit(CastStack[data].bar)
GroupRemoveUnit(CastGroup, A)
IssueImmediateOrder(A, "stop")
UnitAddAbility(A, unit_data.last_casted)
unit_data.last_casted = 0
SetMp(A, GetMp(A) + UseMpAmount[CastStack[data].skill][CastStack[data].level])
CastStack[data].destroy()
CastStack[data] = CastStack[Stack]
Stack--
//msg("removed - break")
//msg(I2S(Stack))
}
bool CastBreak_Conditions(){
if IsUnitInGroup(GetTriggerUnit(), CastGroup) {
BreakCast(GetTriggerUnit())
}
return false
}
private void EndCast(CastData cast_data){
UD source = GetData(cast_data.caster)
int index = GetUnitCastData(cast_data.caster)
GroupRemoveUnit(CastGroup, cast_data.caster)
UnitRemoveAbility(cast_data.caster, CAST_CHANNEL_SKILL)
UnitAddAbility(cast_data.caster, source.last_casted)
IssueImmediateOrder(CastStack[index].caster, "stop")
if cast_data.target != null
{ IssueTargetOrderById(cast_data.caster, Order[cast_data.skill], cast_data.target) }
elseif (cast_data.targ_x != 0. and cast_data.targ_y != 0.)
{ IssuePointOrderById(cast_data.caster, Order[cast_data.skill], cast_data.targ_x, cast_data.targ_y) }
else
{ IssueImmediateOrderById(cast_data.caster, Order[cast_data.skill]) }
RemoveUnit(CastStack[index].bar)
CastStack[index].destroy()
CastStack[index] = CastStack[Stack]
Stack--
//msg("removed - end")
}
private void CastUpdate(){
int index = 0
while(index++ < Stack){
if CastStack[index].cast_time <= 0. {
EndCast(CastStack[index])
}
elseif CastStack[index].target != null {
if DBU(CastStack[index].target, CastStack[index].caster) > Range[CastStack[index].skill][CastStack[index].level] + 75. {
//msg("out of range")
BreakCast(CastStack[index].caster)
}
else {
SetUnitFacing(CastStack[index].caster, ABU(CastStack[index].caster, CastStack[index].target))
CastStack[index].cast_time -= 0.1
}
}
else {
CastStack[index].cast_time -= 0.1
}
}
}
void CastInitialize(unit caster, unit victim, int abilityid, real tx, real ty){
UD src = GetData(caster)
int c = GetSkillCell(abilityid), alvl = GetUnitAbilityLevel(caster, abilityid)
real RealSpeed
if c == 0 { return }
// проверка немоты
if src.silence[1] and SkillType[c] {
SimError("Нельзя использовавать физические умения.")
IssueImmediateOrder(caster, "stop")
return
}
elseif src.silence[2] and not SkillType[c] {
SimError("Нельзя использовавать магические умения.")
IssueImmediateOrder(caster, "stop")
return
}
// проверка необходимости бафа
if (BuffCondition[c][alvl] > 0 and GetUnitAbilityLevel(caster, BuffCondition[c][alvl]) > 0) {
SimError("Отсутствует эффект для активации умения.")
IssueImmediateOrder(caster,"stop")
return
}
// проверка на оружие
if (WeaponRequire[c][1] != ANY) {
if (WeaponRequire[c][1] != src.current_weapon.weapon_type and WeaponRequire[c][2] != src.current_weapon.weapon_type and WeaponRequire[c][3] != src.current_weapon.weapon_type) and WeaponRequire[c][1] != SHIELD {
SimError("Неподходящее оружие для активации умения.")
IssueImmediateOrder(caster,"stop")
return
}
elseif (WeaponRequire[c][1] == SHIELD and src.shield == 0){
SimError("Для этого умения необходим щит.")
IssueImmediateOrder(caster,"stop")
return
}
}
// проверка на здоровье
if HpCondition[c][alvl] > 0. {
if HpConditionPolarity[c][alvl] {
if GetMaxHp(caster) * HpCondition[c][alvl] < HpCondition[c][alvl] {
SimError("Недостаточный запас здоровья для активации умения.")
IssueImmediateOrder(caster, "stop")
return
}
}
else {
if GetMaxHp(caster) * HpCondition[c][alvl] > HpCondition[c][alvl] {
SimError("Недостаточный запас здоровья для активации умения.")
IssueImmediateOrder(caster, "stop")
return
}
}
}
// проверка на положение
if (UseCondition[c][alvl] == BACK_CONDITION and not IsUnitBack(caster,victim)){
SimError("Нужно находиться за спиной для активации этого умения.")
IssueImmediateOrder(caster, "stop")
return
}
src.full_time = CastTime[c][alvl] * src.casting_speed
src.cast_break_time = src.full_time - RMinBJ(0.5 / src.casting_speed, 0.5)
Stack++
CastStack[Stack].create()
CastStack[Stack].bar = CreateUnit(GetOwningPlayer(caster), CAST_BAR_UNIT, Gx(caster) + 45., Gy(caster), 270.)
SetUnitFlyHeight(CastStack[Stack].bar, GetUnitFlyHeight(caster) + 100., 0.)
SetUnitVertexColor(CastStack[Stack].bar, 100, 100, 255, 255)
SetUnitTimeScale(CastStack[Stack].bar, 1. / src.full_time)
UnitApplyTimedLife(CastStack[Stack].bar, 'BTLF', src.full_time)
CastStack[Stack].caster = caster
CastStack[Stack].target = victim
CastStack[Stack].level = alvl
CastStack[Stack].skill = c
CastStack[Stack].targ_x = tx
CastStack[Stack].targ_y = ty
CastStack[Stack].cast_time = src.full_time
// instant spells
if CastTime[c][alvl] == 0. {
EndCast(CastStack[Stack])
return
}
if src.full_time < 0.1 { src.full_time = 0.1 }
src.last_casted = abilityid
UnitRemoveAbility(caster, abilityid)// <======= this
UnitAddAbility(caster, CAST_CHANNEL_SKILL)
IssueImmediateOrderById(caster, order_web)
GroupAddUnit(CastGroup, caster)
}
//============================================================================
private void ReversCooldown(){
UD caster = GetTimerAttach(GetExpiredTimer())
if caster.current_weapon.relation == 1 { UnitAddAbility(caster.Owner, ATTACK_ID) }
else { UnitAddAbility(caster.Owner, RANGE_ATTACK_ID) }
}
private void DamageAll(){
UD source = TempSource
UD victim = GetData(GetEnumUnit())
int status = PhysicalDamage(source.Owner, victim.Owner, 0., true, true, false, true, 0)
BroadcastDamage(status, Last_Damage, victim.Owner)
}
private void Damage(){
UD source = GetTimerAttach(GetExpiredTimer())
group g = CG
if LoadInteger(hash, H2I(source.damage_delay_timer), 0) == 1 {
ForFilter1 = source.Owner
GroupEnumUnitsInRange(g, Gx(source.Owner) + Rx(source.current_weapon.range, Ga(source.Owner)), Gy(source.Owner) + Ry(source.current_weapon.range, Ga(source.Owner)), source.current_weapon.range, Filter(function EnemiesFilter))
TempSource = source
ForGroup(g, function DamageAll)
}
else {
FireWeaponShell(source.Owner, LoadReal(hash, H2I(source.damage_delay_timer), 0), LoadReal(hash, H2I(source.damage_delay_timer), 1))
}
GC(g)
DG(g)
g = null
}
private void Back(){
UD source = GetTimerAttach(GetExpiredTimer())
if source.alternate_effect == 0 {
PauseUnit(source.Owner, false)
SetUnitAnimation(source.Owner, "stand ready")
SetUnitTimeScale(source.Owner, 1.)
}
}
private void Attack_Act(){
UD caster = GetData(GetSpellAbilityUnit())
int h = H2I(caster.damage_delay_timer)
real x = SpellX, y = SpellY
TimerStartEx(caster.cooldown, caster.attack_speed, function ReversCooldown, caster)
TimerStartEx(caster.back_delay_timer, caster.back_delay, function Back, caster)
TimerStartEx(caster.damage_delay_timer, caster.damage_delay, function Damage, caster)
SaveInteger(hash, h, 0, caster.current_weapon.relation)
SaveReal(hash, h, 0, SpellX)
SaveReal(hash, h, 1, SpellY)
if GetUnitAbilityLevel(caster.Owner, ATTACK_ID) > 0 {
UnitRemoveAbility(caster.Owner, ATTACK_ID)
}
else {
UnitRemoveAbility(caster.Owner, RANGE_ATTACK_ID)
}
SetUnitAnimation(caster.Owner, "attack")
SetUnitTimeScale(caster.Owner, caster.animation_speed)
PauseUnit(caster.Owner, true)
}
private bool Attack_Cond() {
if (GetSpellAbilityId() == ATTACK_ID or GetSpellAbilityId() == RANGE_ATTACK_ID) {
SpellX = GetSpellTargetX(); SpellY = GetSpellTargetY()
IssueImmediateOrderById(GetTriggerUnit(), order_stop)
return true
}
return false
}
private bool Cast_Act(){
UD caster = GetData(GetSpellAbilityUnit())
if GetSkillCell(GetSpellAbilityId()) > 0 {
if caster.last_casted != GetSpellAbilityId() {
CastInitialize(caster.Owner, GetSpellTargetUnit(), GetSpellAbilityId(), GetSpellTargetX(), GetSpellTargetY())
}
else {
caster.last_casted = 0
SetMp(caster.Owner, GetMp(caster.Owner) + UseMpAmount[last_FindedSkill][GetUnitAbilityLevel(caster.Owner, GetSpellAbilityId())])
}
}
return false
}
//============================================================================
private void Init(){
TriggerRegisterAnyUnitEventBJ(Attack, EVENT_PLAYER_UNIT_SPELL_EFFECT)
TriggerAddCondition(Attack, Condition(function Attack_Cond))
TriggerAddAction(Attack, function Attack_Act)
TriggerRegisterAnyUnitEventBJ(Cast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
TriggerAddCondition(Cast, Condition(function Cast_Act))
TriggerRegisterAnyUnitEventBJ( CastBreak, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER )
TriggerRegisterAnyUnitEventBJ( CastBreak, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER )
TriggerRegisterAnyUnitEventBJ( CastBreak, EVENT_PLAYER_UNIT_ISSUED_ORDER )
TriggerAddCondition( CastBreak, Condition( function CastBreak_Conditions ) )
TimerStart(CT, 0.1, true, function CastUpdate)
}
endlibrary