• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Spell Help::Fluid Critical Strike

Status
Not open for further replies.
Level 6
Joined
Jun 30, 2006
Messages
230
The idea is that a hero, in my case one trained to kill weak units, will have a higher chance to do a critical strike when a unit it is attacking has lower life.
I shouldn't think this to be too hard to do, but my JASS skills are lacking and rusty, and I tried to do this and simply got frustrated.

/* ::::: What I Want ::::: */
When a unit that has the critical-strike attacks another unit, the chance of the attacking unit to do a critical-strike increases in several sets based on the percentage of health on the unit being attacked. The first range would be from 65% up to 100% health, which would be the level of ability times by 15%. The second set would be 30%-65% hp, which does the level of ability times by 18%. The third set would be below 30% hp, and the percentage would be the level of the ability times by 21%.

Must be MUI and done in JASS.

So if your level of the ability was 2 your percentages would be as follows:
>65% hp = 30% chance
30%-65% hp = 36% chance
<30% hp = 42% chance

I've tried and fail. I know it should be simple but I'm too rusty and I didn't know a lot of JASS to start with. Can someone help? Please comment your code well so I can learn better! Thanks in advance.

Edit: I just realized I posted this in the wrong place, sorry!
 
Last edited:
Level 6
Joined
Mar 2, 2006
Messages
306
there is an event - A unit is attacked. it is buggy and messed up, but if you insist on the spell, use it.

then we need a condition: Level of Fluid Crit for Attacking unit > 0 it will let the trig execute only when attacking unit has the ability

then we need three IF branches based on Attacked Unit (<-note the function to use) hp.

inside the first branch you'd do: if random number between 1 and 10 < 4 (=30% chance) then cause Attacking Unit to damage Attacked Unit for (3 x Attacking Unit's Agility)...

note 1: triggering unit = attacked unit
note 2: there is no simple way to get damage with bonuses. go with the primary attribute...
 
Level 6
Joined
Jun 30, 2006
Messages
230
If I understand what you just told me, I can't just change the percentage of an existing critical-strike? Before I try anything you just said, I want to be totally sure that I can't simply adjust the percentage an existing critical-strike. I don't want to recreate a critical-strike and its parameters, so I just want to be totally sure.
 
Last edited:
Level 11
Joined
Jul 12, 2005
Messages
764
Fluid Critical Strike - script

I can do this for you, but It'll be 100% bugless only if the unit is a melee one.
It'll be in jass, and will use HandleVars. I'll only upload the script here. Tonight or tomorrow, i don't know how much freetime i'll have.

EDIT
I had time :p
Not much explanation needed, if you just started jass, you won't understand it.. :p
Here it is:
JASS:
//=================================
//Fluid Critical Strike
//by paskovich
//
//To implement, copy the script
//into a converted trigger
//named FluidCriticalStrike.
//
//Requires the HandleVars
//
//Be sure to set the options below.
//
//Give a credit if you use this spell.
//=================================


//=======================
// --- Spell options ---
//=======================

constant function FCS_AbilityRC takes nothing returns integer
    return 'A000'   //The ability's raw code.
endfunction

constant function FCS_DamageMultiplier takes integer level returns real
    return 1 + level * 0.5   //The critical strike damage multiplier.
                             //Now it's 1.5x for level 1
                             //2x for level 2
                             //2.5x for level 3
                             //3x for level 4
                             //...
endfunction

constant function FCS_Effect takes nothing returns string
    //The effect on the target. If you don't want an effect, set this to "" like:
    //return ""
    return "Abilities\\Spells\\Other\\Stampede\\StampedeMissileDeath.mdl"
endfunction


//=======================
//   --- The spell ---
//=======================

function Trig_FluidCriticalStrike_Damage_Conditions takes nothing returns boolean
    return GetEventDamageSource() == GetHandleUnit(GetTriggeringTrigger(), "Attacker")
endfunction

function Trig_FluidCriticalStrike_Damage_Actions takes nothing returns nothing
    local trigger tr = GetTriggeringTrigger()
    local unit u = GetTriggerUnit()
    local unit a = GetEventDamageSource()
    local texttag t = CreateTextTag()
    local real dmg = GetEventDamage()*FCS_DamageMultiplier(GetUnitAbilityLevel(a,FCS_AbilityRC()))
    
    call TriggerRemoveCondition(tr,GetHandleTriggerCondition(tr,"Condition"))
    call TriggerRemoveAction(tr,GetHandleTriggerAction(tr,"Action"))
    call FlushHandleLocals(tr)
    call DestroyTrigger(tr)
    call SetHandleHandle(a, "DamageTrig", null)
    
    call UnitDamageTarget(a, u, dmg-GetEventDamage(), true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
    
    call SetTextTagText(t, I2S(R2I(dmg))+"!",0.024)
    call SetTextTagPos(t,GetUnitX(a),GetUnitY(a), 0.00)
    call SetTextTagColor(t,255,0,0,255)
    call SetTextTagVelocity(t,0,0.04)
    call SetTextTagFadepoint(t, 1.2)
    call SetTextTagLifespan(t, 4.5)
    call SetTextTagPermanent(t, false)
    call SetTextTagVisibility(t, true)
    
    if FCS_Effect() != "" then
        call DestroyEffect(AddSpecialEffectTarget(FCS_Effect(),u,"chest"))
    endif
    
    set tr = null
    set u = null
    set a = null
    set t = null
endfunction

function Trig_FluidCriticalStrike_Conditions takes nothing returns boolean
    return GetUnitAbilityLevel(GetAttacker(),FCS_AbilityRC()) > 0 and not IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) and GetHandleTrigger(GetAttacker(), "DamageTrig") == null
endfunction

function Trig_FluidCriticalStrike_Actions takes nothing returns nothing
    local unit a = GetAttacker()
    local unit u = GetTriggerUnit()
    local real hp = GetUnitState(u,UNIT_STATE_LIFE) / GetUnitState(u,UNIT_STATE_MAX_LIFE)
    local integer chc
    local trigger t
    local boolexpr be
    
    if hp < 0.35 then
        set chc = GetUnitAbilityLevel(a,FCS_AbilityRC()) * 15
    elseif 0.65 < hp then
        set chc = GetUnitAbilityLevel(a,FCS_AbilityRC()) * 21
    else
        set chc = GetUnitAbilityLevel(a,FCS_AbilityRC()) * 18
    endif
    
    if chc >= GetRandomInt(1,100) then
        set t = CreateTrigger()
        call SetHandleHandle(a, "DamageTrig", t)
        call SetHandleHandle(t, "Attacker", a)
        
        call TriggerRegisterUnitEvent(t, u, EVENT_UNIT_DAMAGED)
        set be = Condition(function Trig_FluidCriticalStrike_Damage_Conditions)
        call SetHandleHandle(t,"Condition", TriggerAddCondition(t, be))
        call DestroyBoolExpr(be)
        set be = null
        call SetHandleHandle(t,"Action", TriggerAddAction(t, function Trig_FluidCriticalStrike_Damage_Actions))
        
        call TriggerSleepAction(1.5)
        call FlushHandleLocals(t)
        call DestroyTrigger(t)
        call SetHandleHandle(a, "DamageTrig", null)
        set t = null
    endif
    
    set a = null
    set u = null
endfunction

//===========================================================================
function InitTrig_FluidCriticalStrike takes nothing returns nothing
    set gg_trg_FluidCriticalStrike = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_FluidCriticalStrike, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddCondition( gg_trg_FluidCriticalStrike, Condition( function Trig_FluidCriticalStrike_Conditions ) )
    call TriggerAddAction( gg_trg_FluidCriticalStrike, function Trig_FluidCriticalStrike_Actions )
endfunction

Also, be sure you have these functions in your map's custom script section:
JASS:
function H2I takes handle h returns integer
    return h
    return 0
endfunction
function LocalVars takes nothing returns gamecache
    return InitGameCache("udg_TestCache")
endfunction
function SetHandleHandle takes handle subject, string name, handle value returns nothing
    if value==null then
        call FlushStoredInteger(LocalVars(),I2S(H2I(subject)),name)
    else
        call StoreInteger(LocalVars(), I2S(H2I(subject)), name, H2I(value))
    endif
endfunction
function GetHandleUnit takes handle subject, string name returns unit
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTrigger takes handle subject, string name returns trigger
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTriggerCondition takes handle subject, string name returns triggercondition
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function GetHandleTriggerAction takes handle subject, string name returns triggeraction
    return GetStoredInteger(LocalVars(), I2S(H2I(subject)), name)
    return null
endfunction
function FlushHandleLocals takes handle subject returns nothing
    call FlushStoredMission(LocalVars(), I2S(H2I(subject)) )
endfunction
 
Last edited:
Level 6
Joined
Jun 30, 2006
Messages
230
JASS:
constant function FCS_DamageMultiplier takes integer level returns real
  return 1 + level * 0.5 //The critical strike damage multiplier.
  //Now it's 1.5x for level 1
  //2x for level 2
  //2.5x for level 3
  //3x for level 4
  //... 
endfunction
I'm guessing if I wanted it always to be 2x then I would just say:
JASS:
constant function FCS_DamageMultiplier takes integer level returns real
  return 2
endfunction
?
I made sense of some of that. What's HandleVars? Thanks for your time!
Did you test it, by the way? Cuz I got Compile Errors(99)... may be my fault, but I don't think so.

Why can't you target data of an existing spell? It seems if it was possible it would be a lot easier than creating a new critical-strike...
I'd give paskovich more rep if I could.... :)
 
Last edited by a moderator:
Level 6
Joined
Jun 30, 2006
Messages
230
I know that, that's why Axe spins sometimes even if he wasn't hit :) I've quit playing dota though. Too many people who don't have any patience or tolerance for people who have a bad game once in a while.
 
Level 6
Joined
Jun 30, 2006
Messages
230
I fixed the error(s). It was all because I change 'return 1 + level * 0.5' to 'return 2' and didn't change the type from real to integer. That fixed the rest of the errors too!
 
Level 6
Joined
Mar 2, 2006
Messages
306
I might be wrong, but that seems like a very complicated function, for a simple thing, why not just create a trigger with "Unit is Attacked", then check the "Attacked Unit"'s health%...
so far, that is what BOTH solutions do...
...and set the level of the critical strike according? :)
that would do no good since you can neither detect nor fire the passive event like critical strike. he has to do the damage manually, and show the floating thext above unit manually.
 
Level 21
Joined
Aug 3, 2004
Messages
710
Abusable.
Not really, since it's a fixed chance based on the opponents life. That would mean that repeately doing attack stop, will just set the chance to the same all the times.
Can't detect damage with A Unit Is Attacked
You don't need to detect the damage, since the Critical Strike ability will handle that. To get the attacked unit's life in percent, use something like this:
JASS:
    local unit u           = GetTriggerUnit()
    local real value       = GetUnitState(u, UNIT_STATE_LIFE)
    local real maxValue    = GetUnitState(u, UNIT_STATE_MAX_LIFE)
    local real lifepercent = value / maxValue * 100.0
>65% hp = 30% chance
30%-65% hp = 36% chance
<30% hp = 42% chance
JASS:
function something takes nothing returns nothing
    local unit u           = GetTriggerUnit()
    local real value       = GetUnitState(u, UNIT_STATE_LIFE)
    local real maxValue    = GetUnitState(u, UNIT_STATE_MAX_LIFE)
    local real lifepercent = value / maxValue * 100.0
    if(lifepercent > 65) then
        //set the critical strike ability to 30%
    elseif(lifepercent < 30) then
        //set the critical strike ability to 42%
    else
        //set the critical strike ability to 36%
    endif
    set u = null
endfunction
Done from the top of my head, so haven't tested it yet. But that should work.

Now, tell me what's wrong with that, and how that's abusable?
 
Level 11
Joined
Jul 12, 2005
Messages
764
My trigger takes care of bugs.. Detects damage only taken from the attacking unit, does not create a new trigger if another one for the same unit is "active" (when the attacker misses for example). It is leakless, and as i said, bugless for melee units. 90% bugless for ranged attackers (if the projectile does not hit the target in the "detecting time" (1.5 second), it will cause a bug).
However, with an artifitial critical strike you can also apply an effect on the target.
 
Status
Not open for further replies.
Top