Cokemonkey11
Spell Reviewer
- Joined
- May 9, 2006
- Messages
- 3,570
Type /fps
Yes, you can already do that.Could you add a the possibility of letting other units "charge" another unit's attack like the Prism Towers in Red Alert 2 or Spectrum Tower in Red Alert 3?
O o
/¯¯_¯¯_¯_¯__¯__¯¯__¯¯__¯__¯¯_¯__¯__¯_¯_ ¯ _¯ SHOOP DA WHOOP!
\___¯¯_¯_¯¯__¯¯¯¯_¯¯¯__¯¯¯¯_¯¯¯¯_¯¯¯¯_¯ ¯_ ¯
library Attack initializer OnInit requires Damage, Projectile, Event, AttackData, UnitData
globals
private trigger OnDAMAGE = CreateTrigger()
private Event OnAttackEvent = 0
private Event OnProjEndEvent = 0
private AttackData AttackDataX = 0
private unit SourceUnit = null
private unit TargetUnit = null
private Projectile ProjectileData = 0
private damagetype DamageType = DAMAGE_TYPE_NORMAL
private attacktype AttackType = ATTACK_TYPE_NORMAL
private real DamageDealt = 0.00
endglobals
public function RegisterEvent takes trigger whichTrig returns EventReg
return OnAttackEvent.register(whichTrig)
endfunction
public function RegisterProjEndEvent takes trigger whichTrig returns EventReg
return OnProjEndEvent.register(whichTrig)
endfunction
public function GetSource takes nothing returns unit
return SourceUnit
endfunction
public function GetTarget takes nothing returns unit
return TargetUnit
endfunction
public function GetDamage takes nothing returns real
return DamageDealt
endfunction
public function GetDamageType takes nothing returns damagetype
return DamageType
endfunction
public function GetAttackType takes nothing returns attacktype
return AttackType
endfunction
public function GetAttackData takes nothing returns AttackData
return AttackDataX
endfunction
public function GetProjectileData takes nothing returns Projectile
return ProjectileData
endfunction
function AttackDamageTarget takes unit theKiller, unit theVictim, real theDamage, boolean isRanged, attacktype attackType, damagetype damageType returns nothing
local UnitData ud = UnitData[theVictim]
local real origDmg = theDamage
local real dmg = theDamage
if not IsUnitType(theVictim, UNIT_TYPE_DEAD) then
set DamageType = damageType
if GetRandomReal(0., 100.) >= ud.evadeChnc then
if GetRandomReal(0., 100.) < ud.blockChnc then
if dmg - ud.blockMlt >= 5. then
set dmg = dmg - ud.blockMlt
else
set dmg = 5.
endif
call BlockTextTag(theVictim, origDmg - dmg)
endif
call TriggeredAttack(theKiller, theVictim, dmg, isRanged, attackType, damageType)
if (ud.returndamage > .0 or ud.returndamageItem > .0) and IsUnitType(theKiller, UNIT_TYPE_STRUCTURE) == false then
call Damage_Physical(theVictim, theKiller, dmg * (ud.returndamage * .01 + ud.returndamageItem * .01), attackType, false, false)
endif
else
call DodgeTextTag(theVictim)
endif
endif
endfunction
public function OnUnitImpact takes Projectile p, unit whichUnit returns nothing
local AttackData attad = AttackData_GetUnit(GetUnitTypeId(whichUnit))
if whichUnit == p.target then
if p.unitDamage > 0. then
set DamageType = p.damageType
set AttackType = p.attackType
set SourceUnit = p.caster
set TargetUnit = p.target
set DamageDealt = p.unitDamage
set AttackDataX = attad
set ProjectileData = p
call OnProjEndEvent.fire()
call AttackDamageTarget(p.caster, whichUnit, p.unitDamage, true, p.attackType, p.damageType)
endif
call p.terminate()
endif
endfunction
public function OnProjectileLoop takes Projectile p returns nothing
if IsUnitType(p.target, UNIT_TYPE_DEAD) and p.enableHoming then
set p.totalDist = DBPXY(GetUnitX(p.caster), GetUnitY(p.caster), GetUnitX(p.target), GetUnitY(p.target))
set p.toDist = true
set p.enableHoming = false
endif
endfunction
public function GetAttackDamage takes unit u returns real
if u != null then
if IsUnitType(u, UNIT_TYPE_HERO) then
return (UnitData[u].baseDmg + Status[u].getDamageBonus() + GetHeroMainAttValue(u, UnitData[u].mainAtt, true)) + UnitData[u].numberDmg * GetRandomInt(1, UnitData[u].sidesDmg)
else
return (UnitData[u].baseDmg + UnitData[u].upgradeDmg + Status[u].getDamageBonus()) + UnitData[u].numberDmg * GetRandomInt(1, UnitData[u].sidesDmg)
endif
endif
return 0.0
endfunction
private function onDamage takes nothing returns boolean
local unit att = GetEventDamageSource()
local unit trg = GetTriggerUnit()
local real ax = GetUnitX(att)
local real ay = GetUnitY(att)
local real tx = GetUnitX(trg)
local real ty = GetUnitY(trg)
local real ang = Atan2((ty - ay),(tx - ax))
local real dmg = 0.
local AttackData attad = AttackData_GetUnit(GetUnitTypeId(att))
local AttackData trgad = AttackData_GetUnit(GetUnitTypeId(trg))
local UnitData attud = UnitData[att]
local UnitData trgud = UnitData[trg]
local Projectile p = 0
if AttackData_IsRegistered(GetUnitTypeId(att)) and AttackData_IsRegistered(GetUnitTypeId(trg)) and GetEventDamage() > 0 then
if Damage_IsAttack() then
// Blocking all damage done
call Damage_BlockAll()
if GetRandomReal(0., 100.) >= attud.missChnc then
set dmg = GetAttackDamage(att)
if GetRandomReal(0., 100.) < attud.critChnc then
set dmg = dmg * (1. + attud.critMlt)
call CriticalTextTag(att, dmg)
endif
if GetRandomReal(0., 100.) < attud.stunChance then
call BuffStun.create(trg).destroyTimed(attud.stunTime)
endif
if (attud.lifesteal > 0 or attud.lifestealItem > 0) and IsUnitType(trg, UNIT_TYPE_STRUCTURE) == false then
call SetWidgetLife(att, GetWidgetLife(att) + dmg * (attud.lifesteal * .01 + attud.lifestealItem * .01))
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\VampiricAura\\VampiricAuraTarget.mdl", att, "origin"))
endif
else
call MissTextTag(att)
endif
if attud.isRanged then
set p = Projectile.create(ax, ay, attud.missileHgt, ang)
set p.caster = att
set p.target = trg
set p.owner = GetOwningPlayer(att)
set p.effectPath = attud.missileFx
set p.scaleSize = attud.missileScl
set p.unitDamage = dmg
set p.attackType = attud.attackTyp
set p.damageType = DAMAGE_TYPE_NORMAL
set p.unitCollision = attud.missileCol
set p.enableHoming = true
set p.throughGround = true
set p.onUnit = OnUnitImpact
set p.onLoop = OnProjectileLoop
if attud.missileNrm then
call p.projectNormal(tx, ty, GetUnitFlyHeight(trg) + attud.missileHgt, attud.missileSpd)
else
call p.projectArcing(tx, ty, GetUnitFlyHeight(trg) + attud.missileHgt, attud.missileSpd, attud.missileArc)
endif
else
call AttackDamageTarget(att, trg, dmg, false, attud.attackTyp, DAMAGE_TYPE_NORMAL)
endif
set DamageType = DAMAGE_TYPE_NORMAL
set AttackType = attud.attackTyp
set SourceUnit = att
set TargetUnit = trg
set DamageDealt = dmg
set AttackDataX = attad
set ProjectileData = p
call OnAttackEvent.fire()
elseif Damage_IsSpell() then
set dmg = GetEventDamage()
if attud.spellDamage != 0 then
set dmg = dmg * (1.0 + (attud.spellDamage * .01))
endif
if trgud.blockMagic != 0. then
set dmg = dmg * (1.0 - (trgud.blockMagic * .01))
endif
if dmg > GetEventDamage() then
call DisableTrigger(OnDAMAGE)
call Damage_Spell(att, trg, dmg)
call EnableTrigger(OnDAMAGE)
else
call Damage_Block(GetEventDamage() - dmg)
endif
endif
endif
set att = null
set trg = null
return false
endfunction
private function OnInit takes nothing returns nothing
set OnAttackEvent = Event.create()
set OnProjEndEvent = Event.create()
call Damage_RegisterEvent(OnDAMAGE)
call TriggerAddCondition(OnDAMAGE, Condition(function onDamage))
endfunction
endlibrary
Yep, but I didn't want to make system work like you are doing, but now when I see it here, it seems it will work very good, so now I'm up to it.Wow, that looks stupid.
Well, this one also triggers melee attacks instantly..My engine will trigger melee attack instantly,...
I guess so.You'll see it'll be great.
Yep, but I didn't want to make system work like you are doing, but now when I see it here, it seems it will work very good, so now I'm up to it.
AttackOrder.create(attacker, target)
You said you have an missile speed of 9999, and that is not instantly, but has a delay of the interval you check the missiles.Well, this one also triggers melee attacks instantly..
It really willI guess so.
You said you have an missile speed of 9999, and that is not instantly, but has a delay of the interval you check the missiles.
Although, I will have to redo some spells and my whole attack system since my one works differently, I block damage when any unit is damaged and then do my stuff (ranged units have no model for missiles and missile speed 99999)
Yes, you can already do that.
I will make an example spell to make target units attack temporary ranged if you wish.![]()
Not sure if anyone else suggested this, but it's just an idea that popped into mind. What about having the unit taking damage or a crit damage play their death animation for a quick moment, but not fully playing the animation, so that it looks like they're getting hurt?
Yeah, I am thinking about CustomAttack beta being my last project, so I may stop mapping for at least a few years.
Doing that would play the dying unit sound everytime a unit is hit.
"attack recovery" like in Diablo II![]()
Also what I was talking about isn't evasion, but that you can "undo" attacks later. Like a spell that does:
"Removes the last 4 attacks from the unit and will cause the unit to do the same attacks to its attacker".
hashtable
either, in fact it would probably be better/easier if you used AutoIndex to index the units. This would make referencing the last X instances of damage a breeze.And where should I store all the values then?Eh, that's not particularly difficult. You don't need to use a hashtable either, in fact it would probably be better/easier if you used AutoIndex to index the units. This would make referencing the last X instances of damage a breeze.
And where should I store all the values then?![]()
it would probably be better/easier if you used AutoIndex to index the units
struct UnitDamage
real array prevDamage [DAMAGE_INSTANCES]
integer prevDamageN = 0
method addDamage takes real damageAmount returns nothing
local integer i = 0
if prevDamageN < DAMAGE_INSTANCES then
set prevDamage[prevDamageN] = damageAmount
set prevDamageN = prevDamageN + 1
else
loop
exitwhen(i == DAMAGE_INSTANCES-1)
set prevDamage[i] = prevDamage[i+1]
set i = i + 1
endloop
endif
endmethod
implement AutoCreate
implement AutoDestroy
endstruct
SetUnitUserData
I believe. I think there is a configuration boolean that switches to using a hashtable
if using the user-data isn't acceptable, but if you're using an indexing system then there's no point in not using it since custom data can just be saved per struct.