• 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] Building Fire

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I decided to revisit this old spell I had resting on my drive. Not exactly sure where I want to go with this so any feedback is much appreciated, in particular things that improves the use case flexibility, how to make it more balanced or aestheticly pleasing.

Code improvement is welcome as well, but I'm mostly focusing on how it should work right now.


I'm not really satesfied with how it looks when spreading, but I'm not sure how to improve on it.

Features
  • Passive spell used by units to ignite buildings when sufficient fire damage has been sustained.
  • Fire can spread to nearby buildings.
  • Multiple flames can be created on the same building.
  • Once ignited a building will burn down eventually.
  • Flames can be targeted, currently by firefighters.
  • Burning buildings cannot operate.
  • A building that burns down will detonate and create a number of small flames nearby with the potential to start a new fire on another building (not done yet).
  • Configuration of building fire resistance (not done yet).
  • Level configuration (not done yet)
  • Add Fire Started Event (not done yet)
  • Add Fire Ended Event (not done yet)
    JASS:
    [/LIST]
    function isUnitFireDamaged takes unit u returns boolean
        return GetUnitAbilityLevel(u, udg_FS_BUFF_FIRE) != 0
    endfunction
    
    function isUnitBurning takes unit u returns boolean
        return LoadUnitHandle(udg_FS_hash, GetHandleId(u), 3) != null
    endfunction
    
    function unitIsFlame takes unit u returns boolean
        return GetUnitTypeId(u) == udg_FS_UT_FLAME
    endfunction
    
    function Trig_FireDamage_Conditions takes nothing returns boolean
        return ((isUnitFireDamaged(udg_GDD_DamagedUnit) == true) and IsUnitType(udg_GDD_DamagedUnit, UNIT_TYPE_STRUCTURE) == true)
    endfunction
    
    function Trig_FireDamage_BuildingDeath takes nothing returns boolean
        local unit u = GetTriggerUnit()
        if ((IsUnitType(u, UNIT_TYPE_STRUCTURE) == true) and isUnitBurning(u)) then
        
          call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10., "burning building dies")
        endif
        return false
    endfunction
    
    function FireDamage_TimerExpires takes nothing returns nothing
        local timer t = GetExpiredTimer()
        local integer thid = GetHandleId(t)
        local unit u = LoadUnitHandle(udg_FS_hash, thid, 2)
        local integer uhid = GetHandleId(u)
        set bj_lastCreatedEffect = LoadEffectHandle(udg_FS_hash, uhid, 4)
        call DestroyEffect(bj_lastCreatedEffect)
        call PauseTimer(t)
        call DestroyTimer(t)
        call PauseUnit(u, false)
        call FlushChildHashtable(udg_FS_hash, thid)
        call FlushChildHashtable(udg_FS_hash, uhid)
        call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10., "timer expired")
        set t = null
        set u = null
    endfunction
    
    function FireDamage_CreateFlameOnUnit takes unit target returns nothing
        local real angle
        local real dist
        local real x
        local real y
        local real ratio
      
        if (isUnitBurning(target) == true) then
            set angle = GetRandomReal(0, 360)
            set dist = BlzGetUnitCollisionSize(target) + 36
            set x = GetUnitX(target) + dist*Cos(angle*bj_DEGTORAD)
            set y = GetUnitY(target) + dist*Sin(angle*bj_DEGTORAD)
            set bj_lastCreatedUnit = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), udg_FS_UT_FLAME, x, y, 0)
            set ratio = GetUnitState(bj_lastCreatedUnit, UNIT_STATE_MAX_LIFE)*udg_FS_FLAME_START_HP_CHILD
        else
            call PauseUnit(target, true)
            set x = GetUnitX(target)
            set y = GetUnitY(target)
            call AddSpecialEffect("Objects\\Spawnmodels\\Other\\NeutralBuildingExplosion\\NeutralBuildingExplosion.mdl", x, y)
            set bj_lastCreatedUnit = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), udg_FS_UT_FLAME, x, y, 0)
            set ratio = GetUnitState(bj_lastCreatedUnit, UNIT_STATE_MAX_LIFE)*udg_FS_FLAME_START_HP
        endif
      
        call SetUnitState(bj_lastCreatedUnit, UNIT_STATE_LIFE, ratio)
        call SetUnitScale(bj_lastCreatedUnit, ratio, ratio, ratio)
      
        call GroupAddUnit(udg_FS_flames, bj_lastCreatedUnit)
        if (IsTriggerEnabled(gg_trg_UpdateFlames) == false) then
            call EnableTrigger(gg_trg_UpdateFlames)
        endif
    endfunction
    
    function Trig_FireDamage_Actions takes nothing returns nothing
        local real dmg = udg_GDD_Damage
        local unit u = udg_GDD_DamagedUnit
        local unit attacker = udg_GDD_DamageSource
        local integer uhid
        local real stack_dmg
        local timer t
      
        if (dmg == 0) then
            return
        endif
    
        // Stack damage and reset timer
        set uhid = GetHandleId(u)
        set stack_dmg = LoadReal(udg_FS_hash, uhid, 0) + dmg
        set t = LoadTimerHandle(udg_FS_hash, uhid, 1)
        if (t == null) then
            set t = CreateTimer()
            call SaveTimerHandle(udg_FS_hash, uhid, 1, t)  
            call SaveUnitHandle(udg_FS_hash, GetHandleId(t), 2, u)
            set bj_lastCreatedEffect = AddSpecialEffectTarget("Abilities\\Spells\\Orc\\LiquidFire\\Liquidfire.mdl" , u, "origin")
            call SaveEffectHandle(udg_FS_hash, uhid, 4, bj_lastCreatedEffect)
        endif
        call TimerStart(t, udg_FS_FIRE_DAMAGE_DURATION, false, function FireDamage_TimerExpires)
    
        // If the unit is a flame then give it back life
        if (unitIsFlame(attacker) == true) then
            call SetUnitState(attacker, UNIT_STATE_LIFE, GetUnitState(attacker, UNIT_STATE_LIFE) + dmg*udg_FS_REGEN_FACTOR)
            call SaveUnitHandle(udg_FS_hash, uhid, 3, u)
        endif
      
        // If the conditions are met then spawn a new flame
        if (stack_dmg >= GetUnitState(u, UNIT_STATE_MAX_LIFE)*udg_FS_DMG_REQ) then
            set stack_dmg = stack_dmg - GetUnitState(u, UNIT_STATE_MAX_LIFE)*udg_FS_DMG_REQ
            call FireDamage_CreateFlameOnUnit(u)
        endif
    
        call SaveReal(udg_FS_hash, uhid, 0, stack_dmg)
      
    endfunction
    
    //===========================================================================
    
    function InitTrig_FireDamage takes nothing returns nothing
        local trigger t_dmg = CreateTrigger()
        local trigger t_death = CreateTrigger()
        local integer i
        local player p
      
        call TriggerRegisterVariableEvent(t_dmg, "udg_GDD_Event", EQUAL, 0)
        call TriggerAddCondition(t_dmg, Condition( function Trig_FireDamage_Conditions))
        call TriggerAddAction(t_dmg, function Trig_FireDamage_Actions)
      
        set i = 0
        loop
            set p = Player(i)
            call TriggerRegisterPlayerUnitEvent(t_death, p, EVENT_PLAYER_UNIT_DEATH, null)
            set i = i + 1
            exitwhen i == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t_death, Condition( function Trig_FireDamage_BuildingDeath))
    
        set t_death = null
        set t_dmg = null
        set p = null
    endfunction

    JASS:
    function FlamesIterator takes nothing returns nothing
        local real r
        set bj_lastCreatedUnit = GetEnumUnit()
        set r = GetUnitState(bj_lastCreatedUnit, UNIT_STATE_LIFE)/GetUnitState(bj_lastCreatedUnit, UNIT_STATE_MAX_LIFE)
        call SetUnitScale(bj_lastCreatedUnit, r, r, r)
        set bj_isUnitGroupEmptyResult = false
    endfunction
    
    function Trig_UpdateFlames_Actions takes nothing returns nothing
        set bj_isUnitGroupEmptyResult = true
        call ForGroup(udg_FS_flames, function FlamesIterator)
        if (bj_isUnitGroupEmptyResult == true) then
            call DisableTrigger(gg_trg_UpdateFlames)
        endif
    endfunction
    
    //===========================================================================
    
    function InitTrig_UpdateFlames takes nothing returns nothing
        set gg_trg_UpdateFlames = CreateTrigger()
        call TriggerRegisterTimerEvent(gg_trg_UpdateFlames, 0.5, true)
        call TriggerAddAction(gg_trg_UpdateFlames, function Trig_UpdateFlames_Actions)
        call DisableTrigger(gg_trg_UpdateFlames)
    endfunction

    Feel free to try and burn up some stuff and tell me what you think.
 

Attachments

  • Fire.png
    Fire.png
    2.5 MB · Views: 74
  • FireSystem.w3x
    43.2 KB · Views: 36
Last edited:
Status
Not open for further replies.
Top