[XP] Cool Damage

Started by ThallionDarkshine, January 23, 2013, 07:43:11 pm

Previous topic - Next topic

ThallionDarkshine

January 23, 2013, 07:43:11 pm Last Edit: April 24, 2013, 02:53:28 pm by ThallionDarkshine
Cool Damage
Authors: ThallionDarkshine
Version: 0.4
Type: Graphical Damage Add-on
Key Term: Battle Add-on



Introduction

As you all should have noticed, the default damage display in battles is pretty pathetic. If any of you have seen Blizz's game Chaos Project, then you'll get what I mean when I say that you can never appreciate the default again after playing CP. So, I made my own version of it, complete with four different text appearance styles and four different text disappearance styles. I also included a few other features, including changing the font properties of the text.


Features


  • Gives damage text cool animation!

  • Choose from six different appearance styles and four different disappearance styles.

  • Customize font properties of the text.




Screenshots

Spoiler: ShowHide

Spoiler: ShowHide



Demo

None yet.


Script

Spoiler: ShowHide

module RPG
  class Sprite
    # whether to use the cool damage (set it to false if you never wanted this
    #   script)
    COOL_DAMAGE = true
    # the font name of the damage text
    DAMAGE_FONT_NAME = "Times New Roman"
    # the font size of the damage text
    DAMAGE_FONT_SIZE = 32
    # whether to make the damage text bold
    DAMAGE_FONT_BOLD = true
    # whether to make the damage text italic
    DAMAGE_FONT_ITALIC = true
    # the colors for the damage text
    #   directions for setup will be found in the script topic on Chaos Project
    DAMAGE_COLORS = [
      [proc { |val, crit| val.is_a?(Numeric) and val < 0 }, Color.new(176, 255, 144)],
      [proc { |val, crit| crit }, Color.new(255, 0, 0)]
    ]
    # the horizontal and vertical distance between the letters at the end of
    #   their movement
    LETTER_SEPARATION = [0, 5]
    # how much the damage's actual position can differ from the normal position
    #   (can help with scripts that show multiple damage numbers in quick
    #   succession)
    POSITION_VARIANCE = [0..0, 0..0]
    # the duration of the appearance of the damage
    APPEAR_DURATION = 20
    # the duration of the fading in of the damage
    #   note - should be less than APPEAR_DURATION
    APPEAR_FADE_DURATION = 5
    # the amount of frames of movement between each letter
    APPEAR_OFFSET = 5
    # the amplitude of the letters' movement
    #   suggested values
    #     modes 0 and 1
    #       5 - 15
    #     modes 2, 4
    #       -0.5 - 0 or 0.0 - 2
    #     mode 3
    #       0.5 - 1.5
    #     mode 4
    #       0.5 - 2.0
    #     mode 5
    #       Color.new(FLASH_RED, FLASH_GREEN, FLASH_BLUE, FLASH_AMOUNT)
    APPEAR_AMP = 10
    # how far the letters should rotate when appearing (degrees)
    APPEAR_ANGLE = 0
    # the appearance mode
    #  letter animations:
    #   0 - float
    #   1 - bounce
    #   2 - sink in
    #   3 - 3d-spin
    #  non-letter animations:
    #   4 - sink in
    #   5 - flash (can be used with a color with an alpha of 0 to achieve some
    #     cool effects by setting APPEAR_ANGLE)
    APPEAR_MODE = 0
    # whether to have the letters enter in a random order
    # note - no effect on non-letter animations
    APPEAR_RANDOM = false
    # how long to show the letters before they begin to disappear
    WAIT_DURATION = 10
    # the duration of the disappearance of the damage
    DISAPPEAR_DURATION = 15
    # the duration of the fading out of the damage
    #   note - should be less than DISAPPEAR_DURATION
    DISAPPEAR_FADE_DURATION = 12
    # the amount of frames of movement between each letter
    DISAPPEAR_OFFSET = 2
    # the amplitude of the letters' movement
    #   suggested values
    #     modes 0 and 1
    #       5 - 15
    #     mode 2
    #       1 - 2
    #     mode 3
    #       0.5 - 1.5
    DISAPPEAR_AMP = 1.5
    # how far the letters should rotate when disappearing (degrees)
    DISAPPEAR_ANGLE = 100
    # which way to have the letters disappear
    #  letter animations:
    #   0 - float
    #   1 - bounce
    #   2 - fall away
    #   3 - 3d-spin
    DISAPPEAR_MODE = 2
    # whether to have the letters exit in a random order
    DISAPPEAR_RANDOM = false
   
    alias tdks_dmg_txt_init initialize
    def initialize(viewport = nil)
      tdks_dmg_txt_init(viewport)
      @_cdamage_duration = 0
    end
   
    alias tdks_dmg_txt_dmg damage
    def damage(value, critical)
      unless RPG::Sprite::COOL_DAMAGE
        return tdks_dmg_txt_dmg(value, critical)
      end
      dispose_damage
      if value.is_a?(Numeric)
        damage_string = value.abs.to_s
      else
        damage_string = value.to_s
      end
      obmp = bitmap
      bmp = Bitmap.new(1, 1)
      bmp.font.name = RPG::Sprite::DAMAGE_FONT_NAME
      bmp.font.size = RPG::Sprite::DAMAGE_FONT_SIZE
      bmp.font.bold = RPG::Sprite::DAMAGE_FONT_BOLD
      bmp.font.italic = RPG::Sprite::DAMAGE_FONT_ITALIC
      bmp.font.color.set(0, 0, 0)
      @_cdamage_sprites = []
      size = bmp.text_size(damage_string)
      usep_bmp = Bitmap.new(size.width + 2 + RPG::Sprite::LETTER_SEPARATION[0] * (damage_string.length - 1), size.height + 2 + RPG::Sprite::LETTER_SEPARATION[1] * (damage_string.length - 1))
      x = 0
      y = 0
      rx = (160 - size.width) / 2 - 80
      pv = RPG::Sprite::POSITION_VARIANCE.map { |i| i.first + rand(i.last - i.first + 1) }
      damage_string = damage_string.split('')
      ofsx = damage_string.length * RPG::Sprite::LETTER_SEPARATION[0] / 2
      ofsy = damage_string.length * RPG::Sprite::LETTER_SEPARATION[1] / 2
      damage_string.each_with_index { |i, ind|
        r = bmp.text_size(i)
        r.x += 1
        r.y += 1
        bitmap = Bitmap.new(r.width+2, r.height+2)
        bitmap.font = bmp.font
        usep_bmp.font = bmp.font
        (-1..1).each{|v|
          next if v==0
          bitmap.draw_text(r.x + v, r.y, r.width, r.height, i, 1)
          bitmap.draw_text(r.x, r.y + v, r.width, r.height, i, 1)
          usep_bmp.draw_text(x + RPG::Sprite::LETTER_SEPARATION[0] * ind + 1 + v, RPG::Sprite::LETTER_SEPARATION[1] * ind + 1, r.width, r.height, i, 1)
          usep_bmp.draw_text(x + RPG::Sprite::LETTER_SEPARATION[0] * ind + 1, RPG::Sprite::LETTER_SEPARATION[1] * ind + 1 + v, r.width, r.height, i, 1)
        }
        bitmap.font.color.set(255, 255, 255)
        usep_bmp.font.color.set(255, 255, 255)
        RPG::Sprite::DAMAGE_COLORS.each { |col|
          if col[0].call(value, critical)
            bitmap.font.color = col[1]
            usep_bmp.font.color = col[1]
          end
        }
        bitmap.draw_text(r, i, 1)
        usep_bmp.draw_text(x + RPG::Sprite::LETTER_SEPARATION[0] * ind + 1, RPG::Sprite::LETTER_SEPARATION[1] * ind + 1, r.width, r.height, i, 1)
        sprite = ::Sprite.new(self.viewport)
        sprite.z = 3000
        sprite.bitmap = bitmap
        case RPG::Sprite::APPEAR_MODE
        when 0,1, 3:
          sprite.ox = bitmap.width / 2
          sprite.oy = bitmap.height / 2
        when 2:
          sprite.ox = 0
          sprite.oy = bitmap.height
        end
        sprite.x = self.x + rx + x + sprite.ox + RPG::Sprite::LETTER_SEPARATION[0] * ind - ofsx + pv[0]
        sprite.y = self.y - self.oy / 2 - 20 + 12 + sprite.oy + RPG::Sprite::LETTER_SEPARATION[1] * ind - ofsy + pv[1]
        sprite.opacity = 0
        x += r.width
        @_cdamage_sprites.push(sprite)
      }
      sprite = Sprite.new(self.viewport)
      sprite.bitmap = usep_bmp
      case RPG::Sprite::APPEAR_MODE
      when 4:
        sprite.ox = sprite.bitmap.width / 2
        sprite.oy = sprite.bitmap.height / 2
      end
      sprite.x = self.x + rx - ofsx + sprite.ox + pv[0]
      sprite.y = self.y - self.oy / 2 - 20 + 12 - ofsy + sprite.oy + pv[1]
      sprite.opacity = 0
      sprite.z = 3000
      if RPG::Sprite::APPEAR_MODE.between?(0, 3)
        sprite.visible = false
      else
        @_cdamage_sprites.each{|i|i.visible=false}
      end
      @_cdamage_sprites.push(sprite)
     
      l = @_cdamage_sprites.length
      tmp = Array.new(l) { |i| i }
      @_cdamage_rind = Array.new(l) { v=tmp[rand(tmp.length)];tmp.delete(v);v }
      @_cdamage_spos = @_cdamage_sprites.map { |i| [i.x, i.y] }
      @_cdamage_duration = RPG::Sprite::APPEAR_DURATION + RPG::Sprite::WAIT_DURATION + RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ((RPG::Sprite::DISAPPEAR_MODE.between?(0, 3) ? RPG::Sprite::DISAPPEAR_OFFSET : 0) + (RPG::Sprite::APPEAR_MODE.between?(0, 3) ? RPG::Sprite::APPEAR_OFFSET : 0))
      @_damage_duration = 0
    end
   
    alias tdks_dmg_txt_effect? effect?
    def effect?
      return tdks_dmg_txt_effect?() || @_cdamage_duration > 0
    end
   
    alias tdks_dmg_txt_updt update
    def update
      tdks_dmg_txt_updt
      if @_cdamage_duration > 0
        @_cdamage_duration -= 1
        amnt = 50
        ofs = RPG::Sprite::APPEAR_OFFSET
        ofs2 = RPG::Sprite::DISAPPEAR_OFFSET
        l = @_cdamage_sprites.length - 1
        if @_cdamage_duration > RPG::Sprite::DISAPPEAR_DURATION + RPG::Sprite::WAIT_DURATION + (l - 1) * (RPG::Sprite::DISAPPEAR_MODE.between?(0, 3) ? ofs2 : 0)
          frames = @_cdamage_duration - RPG::Sprite::DISAPPEAR_DURATION - RPG::Sprite::WAIT_DURATION - (l - 1) * (RPG::Sprite::DISAPPEAR_MODE.between?(0, 3) ? ofs2 : 0)
          if RPG::Sprite::APPEAR_MODE.between?(0, 3)
            @_cdamage_sprites[0...l].each_with_index { |i, ind|
              rind = ind
              ind = @_cdamage_rind[ind] if RPG::Sprite::APPEAR_RANDOM
              if RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs > 0 and (l - 1 - ind) * ofs - frames < 0
                fadedur = [RPG::Sprite::APPEAR_FADE_DURATION, RPG::Sprite::APPEAR_DURATION].min
                if RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs <= fadedur - 1
                  i.opacity = 255 * (RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs + 1) / fadedur
                end
                case RPG::Sprite::APPEAR_MODE
                when 0:
                  s = 0-Math.cos(Math::PI * 3 * (RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs) / (RPG::Sprite::APPEAR_DURATION - 1) / 2)
                  i.y = @_cdamage_spos[rind][1] - RPG::Sprite::APPEAR_AMP * s
                when 1:
                  s = 2 * Math.cos(Math::PI * 4 * (RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs) / (RPG::Sprite::APPEAR_DURATION - 1) / 3).abs - 1
                  i.y = @_cdamage_spos[rind][1] - RPG::Sprite::APPEAR_AMP * s
                when 2:
                  i.zoom_x = i.zoom_y = RPG::Sprite::APPEAR_AMP - (RPG::Sprite::APPEAR_AMP - 1) * (RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs).to_f / (RPG::Sprite::APPEAR_DURATION - 1)
                when 3:
                  angle = (360 * RPG::Sprite::APPEAR_AMP * (RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs).to_f / (RPG::Sprite::APPEAR_DURATION - 1) - RPG::Sprite::APPEAR_AMP * 360) % 360
                  while angle < 0;angle += 360;end
                  if angle < 90
                    i.mirror = false
                    i.zoom_x = Math.sin((90 - angle) * Math::PI / 180)
                  elsif angle < 180
                    i.mirror = true
                    i.zoom_x = Math.sin((angle - 90) * Math::PI / 180)
                  elsif angle < 270
                    i.mirror = true
                    i.zoom_x = Math.sin((270 - angle) * Math::PI / 180)
                  else
                    i.mirror = false
                    i.zoom_x = Math.sin((angle - 270) * Math::PI / 180)
                  end
                end
                i.angle = (RPG::Sprite::APPEAR_ANGLE) * (RPG::Sprite::APPEAR_DURATION + (l - 1) * ofs - frames - ind * ofs) / (RPG::Sprite::APPEAR_DURATION - 1) - RPG::Sprite::APPEAR_ANGLE
              end
            }
          else
            sprite = @_cdamage_sprites[-1]
            sprite.angle = (RPG::Sprite::APPEAR_ANGLE) * (RPG::Sprite::APPEAR_DURATION - frames) / (RPG::Sprite::APPEAR_DURATION - 1) - RPG::Sprite::APPEAR_ANGLE
            fadedur = [RPG::Sprite::APPEAR_FADE_DURATION, RPG::Sprite::APPEAR_DURATION].min
            if RPG::Sprite::APPEAR_DURATION - frames <= fadedur - 1
              sprite.opacity = 255 * (RPG::Sprite::APPEAR_DURATION - frames + 1) / fadedur
            end
            case RPG::Sprite::APPEAR_MODE
            when 4:
              sprite.zoom_x = sprite.zoom_y = 1.0 + RPG::Sprite::APPEAR_AMP.to_f * (frames - 1) / RPG::Sprite::APPEAR_DURATION
            when 5:
              col = RPG::Sprite::APPEAR_AMP.clone
              col.alpha *= 1-(2 * (RPG::Sprite::APPEAR_DURATION + 1.0 - frames) / RPG::Sprite::APPEAR_DURATION - 1).abs
              sprite.color = col
            end
          end
          if @_cdamage_duration == RPG::Sprite::DISAPPEAR_DURATION + RPG::Sprite::WAIT_DURATION + (l - 1) * ofs2 + 1
            tmp = Array.new(l) { |e| e }
            @_cdamage_rind = Array.new(l) { v=tmp[rand(tmp.length)];tmp.delete(v);v }
            @_cdamage_sprites.each_with_index { |e, tind|
              oox = e.ox
              ooy = e.oy
              case RPG::Sprite::DISAPPEAR_MODE
              when 0,1,2:
                e.ox = 0
                e.oy = e.bitmap.height
              when 3:
                e.ox = e.bitmap.width / 2
                e.oy = e.bitmap.height / 2
              end
              e.x += e.ox - oox
              e.y += e.oy - ooy
              @_cdamage_spos[tind] = [e.x, e.y]
            }
            if RPG::Sprite::DISAPPEAR_MODE.between?(0, 3)
              @_cdamage_sprites[-1].visible = false
              @_cdamage_sprites[0...l].each { |i| i.visible = true;i.opacity = 255 }
            else
              @_cdamage_sprites[-1].visible = true
              @_cdamage_sprites[-1].opacity = 255
              @_cdamage_sprites[0...l].each { |i| i.visible = false }
            end
          end
        elsif @_cdamage_duration.between?(1, RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2)
          @_cdamage_sprites[0...l].each_with_index { |i, ind|
            rind = ind
            ind = @_cdamage_rind[ind] if RPG::Sprite::DISAPPEAR_RANDOM
            frames = @_cdamage_duration
            if RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2 > 0 and RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2 < RPG::Sprite::DISAPPEAR_DURATION
              case RPG::Sprite::DISAPPEAR_MODE
              when 0:
                s = Math.sin(Math::PI * 2 * (RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2) / (RPG::Sprite::DISAPPEAR_DURATION - 1) / 3)
                i.y = @_cdamage_spos[rind][1] - RPG::Sprite::DISAPPEAR_AMP * s
              when 1:
                s = Math.sin(Math::PI * (RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2) / (RPG::Sprite::DISAPPEAR_DURATION - 1)).abs
                i.y = @_cdamage_spos[rind][1] + RPG::Sprite::DISAPPEAR_AMP * s
              when 2:
                i.y += RPG::Sprite::DISAPPEAR_AMP * 1.2 ** ((RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2) / (RPG::Sprite::DISAPPEAR_DURATION - 1))
              when 3:
                angle = (360 * RPG::Sprite::DISAPPEAR_AMP * (RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2).to_f / (RPG::Sprite::DISAPPEAR_DURATION - 1)) % 360
                while angle < 0;angle += 360;end
                if angle < 90
                  i.mirror = false
                  i.zoom_x = Math.sin((90 - angle) * Math::PI / 180)
                elsif angle < 180
                  i.mirror = true
                  i.zoom_x = Math.sin((angle - 90) * Math::PI / 180)
                elsif angle < 270
                  i.mirror = true
                  i.zoom_x = Math.sin((270 - angle) * Math::PI / 180)
                else
                  i.mirror = false
                  i.zoom_x = Math.sin((angle - 270) * Math::PI / 180)
                end
              end
              i.angle = (RPG::Sprite::DISAPPEAR_ANGLE) * (RPG::Sprite::DISAPPEAR_DURATION + (l - 1) * ofs2 - frames - ind * ofs2) / (RPG::Sprite::DISAPPEAR_DURATION - 1)
            end
            fadedur = [RPG::Sprite::DISAPPEAR_FADE_DURATION, RPG::Sprite::DISAPPEAR_DURATION].min
            if frames - (l - 1 - ind) * ofs2 < fadedur
              i.opacity = 255 * (frames - (l - 1 - ind) * ofs2) / fadedur
            end
          }
        end
        if @_cdamage_duration == 0
          @_cdamage_sprites.each{|i|i.bitmap.dispose;i.dispose}
        end
      end
    end
  end
end



Instructions

Configure the script and that's pretty much it. I'll put in a little on how to configure the damage color section soon.

And here are the instructions:
To add a new damage color, use this template:
[proc { |val, crit| CONDITION }, Color.new(RED, GREEN, BLUE[, ALPHA])]

The ALPHA/opacity parameter is optional. The condition is pretty easy to set up: all you have to do is insert a condition statement, such as:
val > 0

which would check if the damage was greater than 0.
Note - If you are going to use a condition to compare the damage to a number, add this to the start of your condition:
val.is_a?(Numeric) and 

Other than that, the parameters are all pretty much self-explanatory.


Compatibility

Should be compatible with anything that utilizes the default damage method.


Credits and Thanks


  • ThallionDarkshine

  • Blizz for the inspiration to write this




Author's Notes

Nothing

ThallionDarkshine

Update to v0.2. A bunch of bug fixes as well as a new appearance style.

Blizzard

*fixes post* Please use spoilers for images.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ThallionDarkshine


Heretic86

Minor bug

Changing APPEAR_MODE to bounce or float, when animation stops, last character snaps up and out of position.

Suggestion:  Needs a few more Appear Mode options.  There are some scripts that allow multiple hits to occur very quickly, so having the damage text move out of its initial position could be quite useful for displaying all of the damage text at the same time.

Handling each Damage Character individually is quite cool!  Oh, thats what the name of the script implies!
Current Scripts:
Heretic's Moving Platforms

Current Demos:
Collection of Art and 100% Compatible Scripts

(Script Demos are all still available in the Collection link above.  I lost some individual demos due to a server crash.)

ThallionDarkshine

January 30, 2013, 08:49:07 pm #5 Last Edit: April 24, 2013, 02:54:54 pm by ThallionDarkshine
Ill probably add in new animations soon, including some that dont use multiple sprites and look good with shorter durations. Im actually sitting on an update right now that ill post in the morning.

And a quick sidenote: i figured out why all my dll functions lag so much. Ive been reloading the functions every frame, which takes a lot of time i guess. Anyway, i am coming out with an update for my battler transitions script to allow virtually lagless use of rmxp transition graphics to transition sprites in and out.

Edit - And here's the update to v0.3
I've been too busy with midterms and working on v0.4 to post it, but here it is. 4 of each type of animation now.

Edit - Update to v0.4.

I've just been sitting on this update for forever, and I finally realized that this wasn't up to date when I got the script from this topic, so here's the update. There are several non-letter animations in this update.