HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

InjuryEffectScript

03-23-2009, 05:38 PM#1
moyack
Injury Effect Script
By moyack. 2009

Ok, after revising this old resource, I took the freedom to develop something much more stable, configurable, clean and effective.

This script requires Jass New Gen Pack or JassHelper, and Table to work properly.

Installation:
  1. Create a new Trigger
  2. Call it properly. like "Injury Effect Script"
  3. Convert it to custom text
  4. Remove the code posted.
  5. Paste the code above
  6. Save the map.
  7. Voila!!! now it works.

As is, it only will use a single effect per race. If you want to add more FXs to any race, you can use this function:

call SetDamageEffectPath(YOUR_RACE, "your\\effect\\path")


New feature!!

Now you set custom effects per unit type. To do that, these are the commands:
  • AddBloodType("FX\\Path", "attach,point") // returns an integer which will identify that Blood type
  • SetUnitTypeBlood('Unit_ID', BLOOD_TYPE_INDEX) // sets the Blood type for the unit type
  • RemoveUnitTypeBlood('Unit_ID') // removes the Blood type for the unit type


Library Code.

Collapse vJass code:
library InjuryEffectScript initializer init requires Table

//* configuration part
globals
    private constant real   dt          = 0.5 // check & effect rate...
    private constant real   Percentage  = 0.3 // when unit reach 30% of its hitpoints, it will show blood
    private constant string AttachPoint = "chest" // defines where's the attachment point of the effects for units
    private constant string MechEffect  = "Abilities\\Weapons\\FlyingMachine\\FlyingMachineImpact.mdl" // sets the "blood" model effect for mechanical units... 
endglobals
//* End configuration part.
// Do NOT CHANGE THIS... unless you know what are you doing...
globals
    //! textmacro SetGlobals takes Race
    private          string array $Race$Blood
    private          integer $Race$Index = 0
    //! endtextmacro
    //! runtextmacro SetGlobals("HUMAN")
    //! runtextmacro SetGlobals("ORC")
    //! runtextmacro SetGlobals("UNDEAD")
    //! runtextmacro SetGlobals("NIGHTELF")
    //! runtextmacro SetGlobals("DEMON")
    //! runtextmacro SetGlobals("OTHER")
    private          group G = CreateGroup()
    private          rect  R = null
endglobals

private struct BloodType
    static Table T
    string FX
    string AttPoint
    static method Add takes string FX, string AP returns integer 
        local BloodType BT = BloodType.allocate()
        set BT.FX = FX
        set BT.AttPoint = AP
        return integer(BT)
    endmethod
    static method SetBlood takes integer id, integer BloodT returns nothing
        set BloodType.T[id] = BloodT
    endmethod
    static method RemoveBlood takes integer id returns nothing
        call BloodType.T.flush(id)
    endmethod
endstruct

private function DoEffect takes nothing returns boolean
    local unit u = GetFilterUnit()
    if GetWidgetLife(u) / GetUnitState(u, UNIT_STATE_MAX_LIFE) <= Percentage and GetWidgetLife(u) > 0.405 then
        if IsUnitType(u, UNIT_TYPE_MECHANICAL) == true then
            call DestroyEffect(AddSpecialEffectTarget(MechEffect, u, "chest"))
            return false
        endif
        if BloodType.T.exists(GetUnitTypeId(u)) then
            call DestroyEffect(AddSpecialEffectTarget(BloodType(BloodType.T[GetUnitTypeId(u)]).FX, u, BloodType(BloodType.T[GetUnitTypeId(u)]).AttPoint))
            return false
        endif
        //! textmacro DoConds takes Race
        if GetUnitRace(u) == RACE_$Race$ then
            call DestroyEffect(AddSpecialEffectTarget($Race$Blood[GetRandomInt(0,$Race$Index)], u, AttachPoint))
            return false
        endif
        //! endtextmacro
        //! runtextmacro DoConds("HUMAN")
        //! runtextmacro DoConds("ORC")
        //! runtextmacro DoConds("UNDEAD")
        //! runtextmacro DoConds("NIGHTELF")
        //! runtextmacro DoConds("DEMON")
        //! runtextmacro DoConds("OTHER")
    endif
    return false
endfunction 

private function Check takes nothing returns nothing
    call GroupEnumUnitsInRect(G, R, Condition(function DoEffect))
endfunction

//* Public functions
//* Sets the damage effect for a specific race
function SetDamageEffectPath takes race r, string path returns nothing
    //! textmacro DoCond takes Race
    if r == RACE_$Race$ then
        set $Race$Index = $Race$Index + 1
        set $Race$Blood[$Race$Index] = path
        return
    endif
    //! endtextmacro
    //! runtextmacro DoCond("HUMAN")
    //! runtextmacro DoCond("ORC")
    //! runtextmacro DoCond("UNDEAD")
    //! runtextmacro DoCond("NIGHTELF")
    //! runtextmacro DoCond("DEMON")
    //! runtextmacro DoCond("OTHER")
endfunction
//* Adds a new and custom Blood type effect to the database... it returns the Blood Type index
function AddBloodType takes string fx, string attachpoint returns integer
    return BloodType.Add(fx, attachpoint)
endfunction
//* Sets a custom blood effect for a specific unit type...
function SetUnitTypeBlood takes integer uid, integer bloodtype returns nothing
    call BloodType.SetBlood(uid, bloodtype)
endfunction
//* Removes to an specific unit type the custom Blood types, it will use instead the ones defined by race...
function RemoveUnitTypeBlood takes integer uid returns nothing
    call BloodType.RemoveBlood(uid)
endfunction
//* End public functions

private function init takes nothing returns nothing
    set BloodType.T = Table.create()
    set R = GetWorldBounds()
    call SetDamageEffectPath(RACE_HUMAN   , "Objects\\Spawnmodels\\Other\\HumanBloodCinematicEffect\\HumanBloodCinematicEffect.mdl")
    call SetDamageEffectPath(RACE_ORC     , "Objects\\Spawnmodels\\Other\\OrcBloodCinematicEffect\\OrcBloodCinematicEffect.mdl")
    call SetDamageEffectPath(RACE_UNDEAD  , "Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodAbomination.mdl")
    call SetDamageEffectPath(RACE_NIGHTELF, "Objects\\Spawnmodels\\NightElf\\NightElfBlood\\NightElfBloodArcher.mdl")
    call SetDamageEffectPath(RACE_DEMON   , "Abilities\\Spells\\NightElf\\Immolation\\ImmolationDamage.mdl")
    call SetDamageEffectPath(RACE_OTHER   , "Objects\\Spawnmodels\\Undead\\UndeadBlood\\UndeadBloodNecromancer.mdl")
    call TimerStart(CreateTimer(), dt, true, function Check)
endfunction
endlibrary

Usage example for custom blood types:

Collapse JASS:
scope TestingTime initializer init

globals
    private integer BLOOD_TYPE_NAGA // this global variable will store the index of this type of blood
endglobals
//===========================================================================
private function init takes nothing returns nothing
    //* Creates a custom blood type, in this case one for nagas
    set BLOOD_TYPE_NAGA = AddBloodType("Objects\\Spawnmodels\\Demon\\DemonBlood\\DemonBloodPitlord.mdl", "origin")
    call SetUnitTypeBlood('nwgs', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nnmg', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nnsw', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nsnp', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nmyr', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nnrg', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nhyc', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('nmpe', BLOOD_TYPE_NAGA)
    call SetUnitTypeBlood('Hvsh', BLOOD_TYPE_NAGA)
endfunction

endscope

Changelog:
  • (23/03/2009): First Release
  • (24/03/2009): now it works with all the races defined by the WC3 engine. Added a function to add more effects to any race. simplified the code and now it doesn't requires additional libraries.
  • (05/04/2009): Added the possibility to set a custom blood type per unit type, check the new functions you can use here. Now it requires Table.
03-23-2009, 10:14 PM#2
The Grey Knight
cool, i think i might use this.
might also wanna note that you need to install TimerUtils as well...
03-23-2009, 11:47 PM#3
moyack
Quote:
Originally Posted by The Grey Knight
cool, i think i might use this.
might also wanna note that you need to install TimerUtils as well...
WEll, if you install TimedEffects, then TimerUtils is required too :)
03-23-2009, 11:50 PM#4
Fledermaus
What's the point of the SetFX function? Why not just do that in the init trigger?
03-23-2009, 11:51 PM#5
moyack
For configuration sake, so users can set the FX paths at the top of the code.
03-24-2009, 05:04 PM#6
Anitarf
Quote:
Originally Posted by moyack
For configuration sake, so users can set the FX paths at the top of the code.
But it's not in the configuration section.

Also, the models used don't really require TimedEffects.
03-24-2009, 09:47 PM#7
moyack
Quote:
Originally Posted by Anitarf
But it's not in the configuration section.

Also, the models used don't really require TimedEffects.
you're right, I just used TimedEffects because the user could use other kind of effects where the birth animation is important.

I can add to the first post one version with the famous DestroyEffect(AddSpecialEffect*()) code.
03-24-2009, 10:27 PM#8
Rising_Dusk
It would be really cool if you redid it a bit, right now it's really not that configurable.

You should add a private constant integer (Let us call it MAX_EFFECTS for this discussion) for the maximum number of effects in a specific race and then use that where right now you have the following:
Expand JASS:

You should also ebb away from human/orc/undead/nightelf. Why can't you have some overhead that will permit users to do the following:
Collapse JASS:
set INTEGER_VALUE_MYRACE =  CreateRacialInjuryRace(RealPercentToDoEffect, Condition(function SomeBoolExprtoCheckTheRace))
And then they could up to MAX_EFFECTS effects to the race by the following function:
Collapse JASS:
call AddRacialInjuryEffect(INTEGER_VALUE_MYRACE, "Some//Path//Thing//Rawr.mdx")
This way it eliminates how hard-coded the races are right now. I think it would be much more useful if done that way and would certainly be an upgrade over the previous one in the database in more ways than just syntax.
03-25-2009, 12:32 AM#9
Anitarf
Quote:
Originally Posted by moyack
you're right, I just used TimedEffects because the user could use other kind of effects where the birth animation is important.
No, they couldn't, because the effect paths aren't part of the calibration section (and if they were, you'd have to make declaring them a lot less error prone than it is now).

Also, even if someone uses custom models, it's unlikely that they'd behave considerably differently from the default models. In fact, if the custom models did have a looping stand animation (which would require a delayed destruction), you wouldn't need to periodically create and destroy them in the first place and the whole code would have to look a lot different.

Quote:
Originally Posted by Rising_Dusk
You should also ebb away from human/orc/undead/nightelf. Why can't you have some overhead that will permit users to do the following:
Adding custom races doesn't make much sense because GetUnitRace can only return ingame races anyway. The system should support all of those, though, like Demon, Naga etc.
03-25-2009, 02:12 AM#10
moyack
updated.
03-25-2009, 05:56 AM#11
Rising_Dusk
Quote:
Originally Posted by anitarf
Adding custom races doesn't make much sense because GetUnitRace can only return ingame races anyway. The system should support all of those, though, like Demon, Naga etc.
Why use GetUnitRace? Just have a user-specified boolexpr for each race the user wants to make. Then the user can have "IsUnitType(GetFilterUnit(), UNIT_TYPE_SUICIDAL)" or something if he wants as a 'check' for a specific race.
03-25-2009, 05:05 PM#12
Magissia
How i can make

all SetInjuryEffectPath(RACE_OTHER

Work only on Naga race ?
03-25-2009, 07:00 PM#13
moyack
Hmmm, I did it in such way that it works with the standard races, but Naga is considered as creep (RACE_OTHER).

In order to do that, I should add an additional function to specify a blood effect per unit type (Damn!! why all the stuff I do turns out in other stuff more complex :( ).
03-26-2009, 05:09 PM#14
Magissia
:p ^^
04-05-2009, 07:03 PM#15
moyack
Updated.