| 02-12-2009, 12:02 PM | #1 |
Ok guys, remember my Light Shield spell? If you don't, I remind you that it was rejected because, apparently, although working well, I was not using any Damage Detection system, thus not following any standards. However, those who know me well, know I am persistent (sometimes) and so I decided not to forget that case and decided to remake the spell using ABuff and ADamage. The code is fairly simple, I intend to place it on the spell pack with the other spells. JASS://=========================================================================== //A JESP spell that allows the hero to cast a shield on a not Ud ally or on an //Ud enemy (just like Holy Light). The shield will absorb an amount of damage for //the allied unit thus protecting it from harm, or it will amplify the damage caused //to the unit if it is enemy. //When the shield dies, the shield unit will get healed by the remaining energies //of teh shield if it is an ally, or it will be damage by the remaining energies if //it is an enemy. // //Requires: // - TimerUtils // - Table // - ABuff // - ADamage // - SimError // - LastOrder // - AbortSpell // //@author Flame_Phoenix // //@credits // - Vexorian, for TimerUtils, Table and SimError // - Anitarf, for ABuff and ADamage // - Rising_Dusk, for LastOrder and AbortSpell // - Moyack, for the tip on how to prevent infinite loops // - the_Immortal, the original creator of the spell gave me the idea for making my own // //@version 1.7 //=========================================================================== scope LightShield initializer Init //=========================================================================== //=============================SETUP START=================================== //=========================================================================== globals private constant integer AID = 'A001' //raw of the ability of teh hero private constant integer AURA_ID = 'A002' //raw of the aura with the buff private constant integer AURA_BUFF = 'B000' //raw of the buff of the aura private constant string HEAL_EFFECT = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl" //the effect that appears to heal allies or damage Ud private constant string BLOCK_EFFECT = "Abilities\\Weapons\\FlyingMachine\\FlyingMachineImpact.mdl" //the effect that appears to block damage private constant string AMPLIFY_EFFECT = "Objects\\Spawnmodels\\Orc\\Orcblood\\BattrollBlood.mdl" //the effect that appears when damage is amplified private constant integer SHIELD_PRIORITY = 0 //the priority of the damage prevention shield private constant string ERR_MESSAGE_1 = "\n|cffffcc00Can not cast on Undead allies.|r" private constant string ERR_MESSAGE_2 = "\n|cffffcc00The enemy must be Undead.|r" private constant string HOTKEY = "L" endglobals private constant function Duration takes integer level returns real //the duration of the spell return level * 15. endfunction private constant function ShieldAbsorb takes integer level returns real //the damage the shield can absorb return level * 100. endfunction private constant function BlockPercent takes integer level returns real //the percentage of the damage that will be blocked return .2 * level endfunction private constant function AmplifyPercent takes integer level returns real //the percentage of extra damage that the undead unit will take return .2 * level endfunction //the units that can be affected by the shield private function ShieldCond_1 takes unit caster, unit targ returns boolean //In this case we do not allow the shield to be cast on undead allies return IsUnitAlly(targ, GetOwningPlayer(caster)) and IsUnitType(targ, UNIT_TYPE_UNDEAD) endfunction private function ShieldCond_2 takes unit caster, unit targ returns boolean //In this case we do not allow the shield to be cast on enemies that are not undead return IsUnitEnemy(targ, GetOwningPlayer(caster)) and not(IsUnitType(targ, UNIT_TYPE_UNDEAD)) endfunction private function setupDamageOptions takes xedamage d returns nothing set d.dtype = DAMAGE_TYPE_UNIVERSAL set d.atype = ATTACK_TYPE_NORMAL endfunction //=========================================================================== //=============================SETUP END===================================== //=========================================================================== globals public aBuffType id = 0 private xedamage damageOptions endglobals //=========================================================================== //damage shield struct private struct lightShield extends ADamage_shield real prevented //the prevented damage real life //life of the shield unit shielded //the unit with the shield integer level boolean isUndead unit caster //this boolean prevents us from dealing extra damage when the shield dies //remember that when the shield dies, if it has energy, it will damage //the undead unit. This boolean is the last shield damage the undead unit //will receive, and we don't want it to be amplified boolean lastDamage static method create takes unit u, unit cast, integer level returns lightShield local lightShield shieldData = lightShield.allocate(u, SHIELD_PRIORITY) set shieldData.caster = cast set shieldData.shielded = u set shieldData.level = level set shieldData.life = ShieldAbsorb(level) set shieldData.isUndead = IsUnitType(u, UNIT_TYPE_UNDEAD) set shieldData.lastDamage = false return shieldData endmethod method damaged takes unit damageSource, real damage returns real //here we see if the unit is ud or not. //if Ud, we set prevented to 0, because we won't prevent anything //instead we calculate the extra damage in the Damage function //if not Ud it means it is an ally, and so we calculate the damage //it will block if .isUndead and not(.lastDamage) then set .prevented = 0 else set .prevented = damage * BlockPercent(.level) endif //If the damage would be enough to kill our shield, then we only block //the damage that the shield can, and we let the rest pass. if .prevented > .life then set .prevented = .life endif set .life = .life - .prevented return this.prevented endmethod method onDestroy takes nothing returns nothing //here we heal the unit with the shield with the remaining //energies of the shield, or damage it for the remaining energies //of the shield if it is Ud if .life > 0 and GetWidgetLife(.shielded) > 0.405 then if .isUndead then //to prevent infinite loop if (damageOptions.isInUse() == false) then set .lastDamage = true call damageOptions.damageTarget(.caster, .shielded, .life) endif else call SetWidgetLife(.shielded, GetWidgetLife(.shielded) + .life) endif call DestroyEffect(AddSpecialEffectTarget(HEAL_EFFECT, .shielded, "chest")) endif endmethod endstruct //=========================================================================== private function Create takes aBuff eventBuff returns nothing //Add the aura to the shielded unit call UnitAddAbility(eventBuff.target.u, AURA_ID) //our buff aura only has 1 level, so we don't need this line //call SetUnitAbilityLevel(eventBuff.target.u, AURA_ID, eventBuff.level) //prevent morphing from removing the ability call UnitMakeAbilityPermanent(eventBuff.target.u, true, AURA_ID) //create the shield and attach it to the buff set eventBuff.data = integer(lightShield.create(eventBuff.target.u, eventBuff.caster, eventBuff.level)) endfunction //=========================================================================== private function Refresh takes aBuff eventBuff returns nothing call SetUnitAbilityLevel(eventBuff.target.u, AURA_ID, eventBuff.level) //get the old shield from the buff and destroy it call lightShield(eventBuff.olddata).destroy() //create the shield and attach it to the buff set eventBuff.data = lightShield.create(eventBuff.target.u, eventBuff.caster, eventBuff.level) //by remaking the shield instead of keeping the old one we make sure that //the shields follow the order defined by the NEW_SHIELD_ON_TOP boolean //this of course only matters if the map has multiple shields with the same priority endfunction //=========================================================================== private function Cleanup takes aBuff eventBuff returns nothing //remove the aura ability call UnitRemoveAbility(eventBuff.target.u, AURA_ID) //we also remove the buff, so we don't have to wait 2 seconds for it to disappear call UnitRemoveAbility(eventBuff.target.u, AURA_BUFF) //get the shield from the buff data and destroy it call lightShield(eventBuff.data).destroy() endfunction //=========================================================================== private function Damaged takes aBuff eventBuff, real damage, unit damageSource returns nothing local lightShield shieldData = lightShield(eventBuff.data) local real vicLife = GetWidgetLife(shieldData.shielded) local real bonus = damage * AmplifyPercent(shieldData.level) //if the shielded unit is undead, we damage it even more //else we do nothing because ADamage will heal it if shieldData.isUndead and not(shieldData.lastDamage) then if vicLife - (damage + bonus) <= 0.405 then // if the damage is enough to kill the target call SetWidgetLife(shieldData.shielded, damage * 0.9) // sets the life of the target unit in such way that the damage dealt will kill it else call SetWidgetLife(shieldData.shielded, vicLife - bonus) // Reduce the life of the unit by the damage bonus endif //here we damage the shield for the bonus amount of damage caused set shieldData.life = shieldData.life - bonus call DestroyEffect(AddSpecialEffectTarget(AMPLIFY_EFFECT, eventBuff.target.u, "chest")) else if shieldData.prevented > 0.0 then call DestroyEffect(AddSpecialEffectTarget(BLOCK_EFFECT, eventBuff.target.u, "chest")) endif endif //if the shield has no life, we destroy it if shieldData.life <= 0. then call ABuffDestroy(eventBuff) endif endfunction //=========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //=========================================================================== private function Actions takes nothing returns nothing local unit caster = GetTriggerUnit() local integer level = GetUnitAbilityLevel(caster, AID) call ABuffApply(id, GetSpellTargetUnit(), caster, Duration(level), level, 0) set caster = null endfunction //=========================================================================== private function B4_Actions takes nothing returns nothing local unit caster = GetTriggerUnit() local unit targ = GetSpellTargetUnit() if ShieldCond_1(caster, targ) then call AbortSpell(caster, ERR_MESSAGE_1, HOTKEY) elseif ShieldCond_2(caster, targ) then call AbortSpell(caster, ERR_MESSAGE_2, HOTKEY) endif set caster = null set targ = null endfunction //=========================================================================== private function Init takes nothing returns nothing //when the hero casts the spell local trigger LightShieldTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( LightShieldTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( LightShieldTrg, Condition( function Conditions ) ) call TriggerAddAction(LightShieldTrg, function Actions) //in case the minimum range is not met set LightShieldTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ(LightShieldTrg, EVENT_PLAYER_UNIT_SPELL_CAST ) call TriggerAddCondition(LightShieldTrg, Condition(function Conditions )) call TriggerAddAction(LightShieldTrg, function B4_Actions ) //Setting ABuff set id = aBuffType.create() set id.eventCreate = ABuffEvent_Create.Create set id.eventRefresh = ABuffEvent_Refresh.Refresh set id.eventCleanup = ABuffEvent_Cleanup.Cleanup set id.eventDamaged = ABuffEvent_BUnitDamaged.Damaged // Initializing the damage options: set damageOptions = xedamage.create() // first instanciate a xeobject. call setupDamageOptions(damageOptions) // now call the function we saw before. //Preloading our effects call Preload(HEAL_EFFECT) call Preload(BLOCK_EFFECT) call Preload(AMPLIFY_EFFECT) endfunction endscope I am open to critics, if you have any suggestions, go ahead and shoot them. There is also the stand alone version that only uses TimerUtils and Table, for those who are interested. I also attached a map for those of you who are curious. |
| 02-12-2009, 01:56 PM | #2 |
Maybe you should replace the 'buff' model to that used for the ability of the item Staff of Sanctuary. The current model is blue; my suggestion is yellow and bright. Looks more Holy Lightish. edit: nm i opened the map and saw that the effect is not as in the picture. |
| 02-13-2009, 02:35 PM | #3 | |
Quote:
If you have more suggestions go ahead =) EDIT EDIT EDIT Ok main thread updated, now the images are correct =) Also, added +rep for fx, for being the first person with a suggestion. You can be the next! =P EDIT EDIT EDIT Update 1.7, the spell was heavily improved and changed. Now it is more spicy ! =P |
| 02-17-2009, 06:41 AM | #4 |
Due to the downside time of the website, I will wait until today's night (GMT) 00:00 and will only release the map for a submission tomorrow. I am still open for suggestions =P |
| 02-17-2009, 08:35 AM | #5 |
I'd replace the deflection special effect with that for casting Essence of Blight: the yellow dome thing. It is discernible and it looks like a shield. |
| 02-17-2009, 08:36 AM | #6 | |
Quote:
|
| 02-17-2009, 12:51 PM | #7 |
Abilities\Spells\Undead\ReplenishHealth\ReplenishHealthCasterOverhead.mdl |
| 02-17-2009, 01:55 PM | #8 |
Thx for the path, I tested it with the spell but I think it makes it to spammy. I won't use it, thx for the suggestion anyway =P |
