• Hi, Guest!
    Some images might be missing as we move away from using embedded images, sorry for the mess!
    From now on, you'll be required to use a third party to host images. You can learn how to add images here, and if your thread is missing images you can request them here.
    Do not use Discord to host any images you post, these links expire quickly!
TM Case

v19 TM Case N/A

This resource pertains to version 19 of Pokémon Essentials.
Pokémon Essentials Version
v19.1 ➖
1618972069897.png

TM Case.gif

While giving TMs their own dedicated pocket was definitely more convenient in the long run, the TM case did have its own little uses in being able to show a move's stats at a glance, and I thought its UI was fun! So, here it is!

This script also lets you sort by move properties! Power, type, name, accuracy, category, or PP!

There's a few steps to putting this together, because I wanted to allow for different possible ways to implement it, so be sure to read through all the instructions!

Part 1: Setting up the UI
This is the easy stuff!

Download the files in the download link, and find the folder that's just labelled "TM Case". Put that folder (the folder itself, not just the contents!) in Graphics/Pictures.

(Please note- this pack only has graphics for the eighteen canon types. If your game is adding any custom types with their own TMs, be sure to put in a file named tm_(type)!)

Paste this in a script section above Main:
Ruby:
ItemHandlers::UseInField    .add(:TMCASE,proc { |item|
  TMCase.new
  next 1
})


class Window_TMCase < Window_DrawableCommand
  attr_reader :pocket

  def initialize(bag,filterlist,pocket,x,y,width,height)
    @bag        = bag
    @filterlist = filterlist
    @pocket     = pocket
    @adapter = PokemonMartAdapter.new
    super(x,y,width,height)
    @selarrow  = AnimatedBitmap.new("Graphics/Pictures/selarrow")
    self.windowskin = nil
  end

  def dispose
    super
  end

  def pocket=(value)
    @pocket = value
    @item_max = (@filterlist) ? @filterlist[@pocket].length+1 : @bag.pockets[@pocket].length+1
    self.index = @bag.getChoice(@pocket)
  end

  def page_row_max; return 5; end
  def page_item_max; return 5; end

  def item
    return 0 if @filterlist && !@filterlist[@pocket][self.index]
    thispocket = @bag.pockets[@pocket]
    item = (@filterlist) ? thispocket[@filterlist[@pocket][self.index]] : thispocket[self.index]
    return (item) ? item[0] : 0
  end

  def itemCount
    return (@filterlist) ? @filterlist[@pocket].length+1 : @bag.pockets[@pocket].length+1
  end

  def itemRect(item)
    if item<0 || item>=@item_max || item<self.top_item ||
       item>self.top_item+self.page_item_max
      return Rect.new(0,0,0,0)
    else
      cursor_width = (self.width-self.borderX-(@column_max-1)*@column_spacing) / @column_max
      x = item % @column_max * (cursor_width + @column_spacing)
      y = item / @column_max * @row_height - @virtualOy
      return Rect.new(x, y, cursor_width, @row_height)
    end
  end

  def drawCursor(index,rect)
    if self.index==index
      bmp = @selarrow.bitmap
      pbCopyBitmap(self.contents,bmp,rect.x,rect.y+24)
    end
  end

  def drawItem(index,_count,rect)
    textpos = []
    rect = Rect.new(rect.x+16,rect.y+16,rect.width-16,rect.height)
    ypos = rect.y+4
    thispocket = @bag.pockets[@pocket]
    if index==self.itemCount-1
      textpos.push([_INTL("CLOSE"),rect.x,ypos,false,self.baseColor,self.shadowColor])
    else
      item = (@filterlist) ? thispocket[@filterlist[@pocket][index]][0] : thispocket[index][0]
      baseColor   = self.baseColor
      shadowColor = self.shadowColor
      textpos.push(
         [@adapter.getDisplayName(item),rect.x,ypos,false,baseColor,shadowColor]
      )
      if !GameData::Item.get(item).is_important?   # Not an HM (or infinite TM)
        qty = (@filterlist) ? thispocket[@filterlist[@pocket][index]][1] : thispocket[index][1]
        qtytext = _ISPRINTF("x{1: 3d}",qty)
        xQty    = rect.x+rect.width-self.contents.text_size(qtytext).width-16
        textpos.push([qtytext,xQty,ypos,false,baseColor,shadowColor])
      end
    end
    pbDrawTextPositions(self.contents,textpos)
  end

  def refresh
    @item_max = itemCount()
    self.update_cursor_rect
    dwidth  = self.width-self.borderX
    dheight = self.height-self.borderY
    self.contents = pbDoEnsureBitmap(self.contents,dwidth,dheight)
    self.contents.clear
    for i in 0...@item_max
      next if i<self.top_item || i>self.top_item+self.page_item_max
      drawItem(i,@item_max,itemRect(i))
    end
    drawCursor(self.index,itemRect(self.index))
  end

  def update
    super
    @uparrow.visible   = false
    @downarrow.visible = false
  end
end




class TMCase

  BASE=Color.new(248,248,248)
  SHADOW=Color.new(96,96,96)
  STATBASE=Color.new(64,64,64)
  STATSHADOW=Color.new(216,216,192)
  MOVE = true #set to false if you don't want the position of the disc to move


  def initialize
    @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
    @viewport.z = 99999
    @sprites = {}
    @sprites["bg"] = Sprite.new(@viewport)
    @sprites["bg"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/bg")
    @sprites["overlay"] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport)
    @sprites["doverlay"] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport)
    pbSetSystemFont(@sprites["overlay"].bitmap)
    pbSetSystemFont(@sprites["bg"].bitmap)
    pbSetSystemFont(@sprites["doverlay"].bitmap)
    @power="---"
    @accuracy="---"
    @pp="---"
    @description="---"
    @type="normal"
    @category=0
    @sprites["case"] = Sprite.new(@viewport)
    @sprites["case"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/TM Case")
    @sprites["case"].x = 24
    @sprites["case"].y = 112
    @sprites["case"].z = 3
    @sprites["disc"] = Sprite.new(@viewport)
    @sprites["disc"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/tm_#{@type}")
    @sprites["disc"].x = 58
    @sprites["disc"].y = 76
    @sprites["disc"].z = 1
    @sprites["disc"].visible = false
    @sprites["sticker"] = Sprite.new(@viewport)
    @sprites["sticker"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/hmsticker")
    @sprites["sticker"].x = @sprites["disc"].x
    @sprites["sticker"].y = @sprites["disc"].y
    @sprites["sticker"].z = 2
    @sprites["sticker"].visible = false
    @sprites["itemlist"] = Window_TMCase.new($PokemonBag,nil,4,188,-22,344,40+32+7*32)
    @sprites["itemlist"].viewport    = @viewport
    @sprites["itemlist"].pocket      = 4
    @sprites["itemlist"].index       = 0
    @sprites["itemlist"].baseColor   = Color.new(96,96,96)
    @sprites["itemlist"].shadowColor = Color.new(208,208,200)
    @typebitmap    = AnimatedBitmap.new(_INTL("Graphics/Pictures/types"))
    @catbitmap    = AnimatedBitmap.new(_INTL("Graphics/Pictures/category"))
    overlay = @sprites["overlay"].bitmap
    pbDrawTextPositions(@sprites["bg"].bitmap,[[_INTL("TM CASE"),86,6,2,BASE,SHADOW]])
    overlay.font.size=26
    itemlist=@sprites["itemlist"]
    if itemlist.index<itemlist.itemCount-1
        movestats
        @sprites["disc"].visible = true
    else
        @power = "---"
        @accuracy= "---"
        @pp = "---"
        @description = "---"
    end
    textpos = [
         [_INTL("#{@power}   "),154,292,2,STATBASE,STATSHADOW],
         [_INTL("#{@accuracy}%  "),154,317,2,STATBASE,STATSHADOW],
         [_INTL("#{@pp} PP"),154,343,2,STATBASE,STATSHADOW]
    ]
    drawTextEx(@sprites["doverlay"].bitmap,192,244,320,4,@description,BASE,SHADOW)
    pbDrawTextPositions(overlay,textpos)
    pbFadeInAndShow(@sprites)
    main
  end


  def movestats
      overlay=@sprites["overlay"].bitmap
      itemlist=@sprites["itemlist"]
      move = GameData::Item.get(itemlist.item).move
    # Get data for selected move
      if move
        moveData = GameData::Move.try_get(move)
        @power = moveData.base_damage
        @power = "---" if @power == 0 || @power == 1
        @category = moveData.category
        @accuracy = moveData.accuracy
        @accuracy = "---" if @accuracy == 0
        @pp   = moveData.total_pp
        @pp = "---" if @pp == 0
        @description   = moveData.description
        type = moveData.type
        type = 0 if type == nil
        @category = 0 if @category == nil
        @description = "" if @description == nil
        type = GameData::Type.try_get(type)
        @type = type.real_name.downcase
        typerect = Rect.new(0,type.id_number*28,64,28)
        overlay.blt(114,244,@typebitmap.bitmap,typerect)
        catrect = Rect.new(0,@category*28,64,28)
        overlay.blt(114,272,@catbitmap.bitmap,catrect)
        @sprites["disc"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/tm_#{@type}")
      else
        @power = "---"
        @accuracy= "---"
        @pp = "---"
        @category = 0
        @description = ""
      end
  end


  def main
    loop do
      @sprites["doverlay"].bitmap.clear
      overlay=@sprites["overlay"].bitmap
      overlay.clear
      itemlist=@sprites["itemlist"]
      @sprites["disc"].visible=(itemlist.index<itemlist.itemCount-1)
      if itemlist.index<itemlist.itemCount-1
        movestats
      else
          @power = ""
          @accuracy= ""
          @pp = ""
          @description = ""
      end
      @sprites["sticker"].visible = (GameData::Item.get(itemlist.item).is_HM?) if itemlist.index<itemlist.itemCount-1
      @sprites["sticker"].x = @sprites["disc"].x
      @sprites["sticker"].y = @sprites["disc"].y
      textpos = [
         [_INTL("#{@power}   "),154,292,2,STATBASE,STATSHADOW],
         [_INTL("#{@accuracy}%  "),154,317,2,STATBASE,STATSHADOW],
         [_INTL("#{@pp} PP"),154,343,2,STATBASE,STATSHADOW]
        ]
      pbDrawTextPositions(overlay,textpos)
      drawTextEx(@sprites["doverlay"].bitmap,192,244,320,4,@description,BASE,SHADOW)
      Graphics.update
      Input.update
      if Input.trigger?(Input::RIGHT) && $game_variables[1]==8
        $game_variables[1]=1
        break
      elsif Input.trigger?(Input::LEFT) && $game_variables[1]==8
        $game_variables[1]=0
        break
      elsif Input.trigger?(Input::DOWN)  || Input.repeat?(Input::DOWN)
          if itemlist.itemCount>1
            pbPlayCursorSE
            if itemlist.index<itemlist.itemCount-1
              itemlist.index+=1
            else
              itemlist.index=0
              @sprites["disc"].x = 58
              @sprites["disc"].y = 76
            end
          end
          if itemlist.index<itemlist.itemCount-1 && itemlist.index>0 &&
            MOVE==true && @sprites["disc"].x > 24
              @sprites["disc"].x -= 1
              @sprites["disc"].y += 1
          end
      elsif Input.trigger?(Input::UP)  || Input.repeat?(Input::UP)
        if itemlist.itemCount>1
            pbPlayCursorSE
            if itemlist.index>0
              itemlist.index-=1
              if @sprites["disc"].x < 58  && MOVE==true && itemlist.index < 35
                  @sprites["disc"].x += 1
                  @sprites["disc"].y -= 1
                end
            else
              itemlist.index=itemlist.itemCount-1
              if MOVE==true
                  @sprites["disc"].x = (58-[itemlist.itemCount,34].min)
                  @sprites["disc"].y = (76+[itemlist.itemCount,34].min)
             end
            end
        end
      elsif Input.trigger?(Input::C)
        if itemlist.index<itemlist.itemCount-1
          pbUseItem($PokemonBag,itemlist.item)
          itemlist.refresh
        else
          break
        end
      elsif Input.trigger?(Input::A)
        choice = pbMessage(_INTL("Sort by"),
                [_INTL("Number"),
                _INTL("Type"),
                _INTL("Category"),
                _INTL("Base Power"),
                _INTL("Accuracy"),
                _INTL("Name"),
                _INTL("Cancel")
                ])
        sortarray = []
          for i in 0...$PokemonBag.pockets[4].length
            item = $PokemonBag.pockets[4][i][0]
            move = GameData::Item.get(item).move
            moveData = GameData::Move.try_get(move)
            type = moveData.type
            cat = moveData.category
            power =  moveData.base_damage
            accuracy =  moveData.accuracy
            name = moveData.real_name
            sortarray.push [item,type,cat,power,accuracy,name]
          end
        if choice == 0
          $PokemonBag.pockets[4].sort!
        else
          sortarray.sort!  { |a,b| (a[choice]==b[choice]) ? a[0]<=>b[0] : a[choice]<=>b[choice] }
          for i in 0...$PokemonBag.pockets[4].length
            $PokemonBag.pockets[4][i][0]=sortarray[i][0]
          end
          itemlist.refresh
        end
      elsif Input.trigger?(Input::B)
        break
      end
    end
    pbSEPlay("GUI menu close",80)
    pbFadeOutAndHide(@sprites)
    $PokemonBag.pockets[4].sort!
    dispose
  end

  def dispose
    pbDisposeSpriteHash(@sprites)
    @viewport.dispose
  end
end

Ruby:
ItemHandlers::UseInField    .add(:TMCASE,proc { |item|
  TMCase.new
  next 1
})


class Window_TMCase < Window_DrawableCommand
  attr_reader :pocket

  def initialize(bag,filterlist,pocket,x,y,width,height)
    @bag        = bag
    @filterlist = filterlist
    @pocket     = pocket
    @adapter = PokemonMartAdapter.new
    super(x,y,width,height)
    @selarrow  = AnimatedBitmap.new("Graphics/Pictures/selarrow")
    self.windowskin = nil
  end

  def dispose
    super
  end

  def pocket=(value)
    @pocket = value
    @item_max = (@filterlist) ? @filterlist[@pocket].length+1 : @bag.pockets[@pocket].length+1
    self.index = @bag.getChoice(@pocket)
  end

  def page_row_max; return 5; end
  def page_item_max; return 5; end

  def item
    return 0 if @filterlist && !@filterlist[@pocket][self.index]
    thispocket = @bag.pockets[@pocket]
    item = (@filterlist) ? thispocket[@filterlist[@pocket][self.index]] : thispocket[self.index]
    return (item) ? item[0] : 0
  end

  def itemCount
    return (@filterlist) ? @filterlist[@pocket].length+1 : @bag.pockets[@pocket].length+1
  end

  def itemRect(item)
    if item<0 || item>=@item_max || item<self.top_item ||
       item>self.top_item+self.page_item_max
      return Rect.new(0,0,0,0)
    else
      cursor_width = (self.width-self.borderX-(@column_max-1)*@column_spacing) / @column_max
      x = item % @column_max * (cursor_width + @column_spacing)
      y = item / @column_max * @row_height - @virtualOy
      return Rect.new(x, y, cursor_width, @row_height)
    end
  end

  def drawCursor(index,rect)
    if self.index==index
      bmp = @selarrow.bitmap
      pbCopyBitmap(self.contents,bmp,rect.x,rect.y+20)
    end
  end

  def drawItem(index,_count,rect)
    textpos = []
    rect = Rect.new(rect.x+16,rect.y+16,rect.width-16,rect.height)
    ypos = rect.y+4
    thispocket = @bag.pockets[@pocket]
    if index==self.itemCount-1
      textpos.push([_INTL("CLOSE"),rect.x,ypos,false,self.baseColor,self.shadowColor])
    else
      item = (@filterlist) ? thispocket[@filterlist[@pocket][index]][0] : thispocket[index][0]
      baseColor   = self.baseColor
      shadowColor = self.shadowColor
      textpos.push(
         [@adapter.getDisplayName(item),rect.x,ypos,false,baseColor,shadowColor]
      )
      if !pbIsImportantItem?(item)   # Not an HM (or infinite TM)
        qty = (@filterlist) ? thispocket[@filterlist[@pocket][index]][1] : thispocket[index][1]
        qtytext = _ISPRINTF("x{1: 3d}",qty)
        xQty    = rect.x+rect.width-self.contents.text_size(qtytext).width-16
        textpos.push([qtytext,xQty,ypos,false,baseColor,shadowColor])
      end
    end
    pbDrawTextPositions(self.contents,textpos)
  end

  def refresh
    @item_max = itemCount()
    self.update_cursor_rect
    dwidth  = self.width-self.borderX
    dheight = self.height-self.borderY
    self.contents = pbDoEnsureBitmap(self.contents,dwidth,dheight)
    self.contents.clear
    for i in 0...@item_max
      next if i<self.top_item || i>self.top_item+self.page_item_max
      drawItem(i,@item_max,itemRect(i))
    end
    drawCursor(self.index,itemRect(self.index))
  end

  def update
    super
    @uparrow.visible   = false
    @downarrow.visible = false
  end
end




class TMCase

  BASE=Color.new(248,248,248)
  SHADOW=Color.new(96,96,96)
  STATBASE=Color.new(64,64,64)
  STATSHADOW=Color.new(216,216,192)


  def initialize
    @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
    @viewport.z = 99999
    @move = true #set to false if you don't want the position of the disc to move
    @sprites = {}
    @sprites["bg"] = Sprite.new(@viewport)
    @sprites["bg"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/bg")
    @sprites["overlay"] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport)
    @sprites["doverlay"] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport)
    pbSetSystemFont(@sprites["overlay"].bitmap)
    pbSetSystemFont(@sprites["bg"].bitmap)
    pbSetSystemFont(@sprites["doverlay"].bitmap)
    @power="---"
    @accuracy="---"
    @pp="---"
    @description="---"
    @type="normal"
    @category=0
    @sprites["case"] = Sprite.new(@viewport)
    @sprites["case"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/TM Case")
    @sprites["case"].x = 24
    @sprites["case"].y = 112
    @sprites["case"].z = 3
    @sprites["disc"] = Sprite.new(@viewport)
    @sprites["disc"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/tm_#{@type}")
    @sprites["disc"].x = 58
    @sprites["disc"].y = 76
    @sprites["disc"].z = 1
    @sprites["disc"].visible = false
    @sprites["sticker"] = Sprite.new(@viewport)
    @sprites["sticker"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/hmsticker")
    @sprites["sticker"].x = @sprites["disc"].x
    @sprites["sticker"].y = @sprites["disc"].y
    @sprites["sticker"].z = 2
    @sprites["sticker"].visible = false
    @sprites["itemlist"] = Window_TMCase.new($PokemonBag,nil,4,188,-17,344,40+32+7*32)
    @sprites["itemlist"].viewport    = @viewport
    @sprites["itemlist"].pocket      = 4
    @sprites["itemlist"].index       = 0
    @sprites["itemlist"].baseColor   = Color.new(96,96,96)
    @sprites["itemlist"].shadowColor = Color.new(208,208,200)
    @typebitmap    = AnimatedBitmap.new(_INTL("Graphics/Pictures/types"))
    @catbitmap    = AnimatedBitmap.new(_INTL("Graphics/Pictures/category"))
    overlay = @sprites["overlay"].bitmap
    pbDrawTextPositions(@sprites["bg"].bitmap,[[_INTL("TM CASE"),86,15,2,BASE,SHADOW]])
    overlay.font.size=24
    itemlist=@sprites["itemlist"]
    if itemlist.index<itemlist.itemCount-1
        movestats
        @sprites["disc"].visible = true
    else
        @power = "---"
        @accuracy= "---"
        @pp = "---"
        @description = "---"
    end
    textpos = [
         [_INTL("#{@power}   "),154,297,2,STATBASE,STATSHADOW],
         [_INTL("#{@accuracy}%  "),154,322,2,STATBASE,STATSHADOW],
         [_INTL("#{@pp} PP"),154,348,2,STATBASE,STATSHADOW]
      ]
    drawTextEx(@sprites["doverlay"].bitmap,192,244,320,4,@description,BASE,SHADOW)
    pbDrawTextPositions(overlay,textpos)
    pbFadeInAndShow(@sprites)
    main
  end


  def movestats
      overlay=@sprites["overlay"].bitmap
      itemlist=@sprites["itemlist"]
      moveid = pbGetMachine(itemlist.item)
    # Get data for selected move
      moveData = pbGetMoveData(moveid)
      @power = moveData[MOVE_BASE_DAMAGE]
      if @power == 0
        @power = "---"
      end
      @category   = moveData[MOVE_CATEGORY]
      @accuracy   = moveData[MOVE_ACCURACY]
      if @accuracy == 0
        @accuracy= "---"
      end
      @pp   = moveData[MOVE_TOTAL_PP]
      if @pp == 0
        @pp = "---"
      end
      @description   = moveData[MOVE_DESCRIPTION]
      type = moveData[MOVE_TYPE]
      if type == nil
        type = 0
      end
      if @category == nil
        @category = 0
      end
      if @description == nil
        @description = "---"
      end
      @type = PBTypes.getName(type).downcase
      typerect = Rect.new(0,type*28,64,28)
      overlay.blt(114,244,@typebitmap.bitmap,typerect)
      catrect = Rect.new(0,@category*28,64,28)
      overlay.blt(114,272,@catbitmap.bitmap,catrect)

      @sprites["disc"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/tm_#{@type}")
  end


  def main
    loop do
      @sprites["doverlay"].bitmap.clear
      overlay=@sprites["overlay"].bitmap
      overlay.clear
      itemlist=@sprites["itemlist"]
      @sprites["disc"].visible=(itemlist.index<itemlist.itemCount-1)
      if itemlist.index<itemlist.itemCount-1
        movestats
      else
          @power = "---"
          @accuracy= "---"
          @pp = "---"
          @description = "---"
      end
      @sprites["sticker"].visible = (pbIsHiddenMachine?(itemlist.item))
      @sprites["sticker"].x = @sprites["disc"].x
      @sprites["sticker"].y = @sprites["disc"].y
      pbDrawTextPositions(@sprites["bg"].bitmap,[[_INTL("TM CASE"),86,15,2,BASE,SHADOW]])
      overlay.font.size=24
      textpos = [
         [_INTL("#{@power}   "),154,297,2,STATBASE,STATSHADOW],
         [_INTL("#{@accuracy}%  "),154,322,2,STATBASE,STATSHADOW],
         [_INTL("#{@pp} PP"),154,348,2,STATBASE,STATSHADOW]
        ]
      pbDrawTextPositions(overlay,textpos)
      drawTextEx(@sprites["doverlay"].bitmap,192,244,320,4,@description,BASE,SHADOW)
      Graphics.update
      Input.update
      if Input.trigger?(Input::RIGHT) && $game_variables[1]==8
        $game_variables[1]=1
        break
      elsif Input.trigger?(Input::LEFT) && $game_variables[1]==8
        $game_variables[1]=0
        break
      elsif Input.trigger?(Input::DOWN)  || Input.repeat?(Input::DOWN)
        if @sprites["disc"].x > 24 && @move==true
          if itemlist.itemCount>1
            pbPlayCursorSE
            if itemlist.index<itemlist.itemCount-1
              itemlist.index+=1
            else
              itemlist.index=0
              @sprites["disc"].x = 58
              @sprites["disc"].y = 76
            end
          end
          if itemlist.index<itemlist.itemCount-1 && itemlist.index>0 && @move==true
            @sprites["disc"].x -= 1
            @sprites["disc"].y += 1
          end
        end
      elsif Input.trigger?(Input::UP)  || Input.repeat?(Input::UP)
        if itemlist.itemCount>1
            pbPlayCursorSE
            if itemlist.index>0
              itemlist.index-=1
              if @sprites["disc"].x < 58  && @move==true
                  @sprites["disc"].x += 1
                  @sprites["disc"].y -= 1
                end
            else
              itemlist.index=itemlist.itemCount-1
              if @move==true
                  @sprites["disc"].x = (58-itemlist.itemCount)
                  @sprites["disc"].y = (76+itemlist.itemCount)
             end
            end
        end
      elsif Input.trigger?(Input::C)
        if itemlist.index<itemlist.itemCount-1
          pbUseItem($PokemonBag,itemlist.item)
          itemlist.refresh
        else
          break
        end
      elsif Input.trigger?(Input::A)
        choice = pbMessage(_INTL("Sort by"),
                [_INTL("Number"),
                _INTL("Type"),
                _INTL("Category"),
                _INTL("Base Power"),
                _INTL("Accuracy"),
                _INTL("Name"),
                _INTL("Cancel")
                ])
        sortarray = []
          for i in 0...$PokemonBag.pockets[4].length
            item = $PokemonBag.pockets[4][i][0]
            moveid = pbGetMachine(item)
            moveData = pbGetMoveData(moveid)
            type = moveData[MOVE_TYPE]
            cat = moveData[MOVE_CATEGORY]
            power =  moveData[MOVE_BASE_DAMAGE]
            accuracy =  moveData[MOVE_ACCURACY]
            name = PBMoves.getName(moveid)
            sortarray.push [item,type,cat,power,accuracy,name]
          end
        if choice == 0
          $PokemonBag.pockets[4].sort!
        else
          sortarray.sort!  { |a,b| (a[choice]==b[choice]) ? a[0]<=>b[0] : a[choice]<=>b[choice] }
          for i in 0...$PokemonBag.pockets[4].length
            $PokemonBag.pockets[4][i][0]=sortarray[i][0]
          end
          itemlist.refresh
        end
      elsif Input.trigger?(Input::B)
        break
      end
    end
    pbSEPlay("GUI menu close",80)
    pbFadeOutAndHide(@sprites)
    $PokemonBag.pockets[4].sort!
    dispose
  end

  def dispose
    pbDisposeSpriteHash(@sprites)
    @viewport.dispose
  end
end

In the games, the TMs would move back as you flipped through them, but if you don't want that, you can just change MOVE = true to MOVE = false! (It's @move in the v18 version because I made a dumb choice)

Now, maybe you really crave that FRLG authenticity and don't want to display the category of the moves. I disagree with your life choices, but here's alternate code for that anyways! (Currently only works for v18, I'll make a v19 version if someone requests it)
Ruby:
ItemHandlers::UseInField    .add(:TMCASE,proc { |item|
  TMCase.new
  next 1
})


class Window_TMCase < Window_DrawableCommand
  attr_reader :pocket

  def initialize(bag,filterlist,pocket,x,y,width,height)
    @bag        = bag
    @filterlist = filterlist
    @pocket     = pocket
    @adapter = PokemonMartAdapter.new
    super(x,y,width,height)
    @selarrow  = AnimatedBitmap.new("Graphics/Pictures/selarrow")
    self.windowskin = nil
  end

  def dispose
    super
  end

  def pocket=(value)
    @pocket = value
    @item_max = (@filterlist) ? @filterlist[@pocket].length+1 : @bag.pockets[@pocket].length+1
    self.index = @bag.getChoice(@pocket)
  end

  def page_row_max; return 6; end
  def page_item_max; return 6; end

  def item
    return 0 if @filterlist && !@filterlist[@pocket][self.index]
    thispocket = @bag.pockets[@pocket]
    item = (@filterlist) ? thispocket[@filterlist[@pocket][self.index]] : thispocket[self.index]
    return (item) ? item[0] : 0
  end

  def itemCount
    return (@filterlist) ? @filterlist[@pocket].length+1 : @bag.pockets[@pocket].length+1
  end

  def itemRect(item)
    if item<0 || item>=@item_max || item<self.top_item ||
       item>self.top_item+self.page_item_max
      return Rect.new(0,0,0,0)
    else
      cursor_width = (self.width-self.borderX-(@column_max-1)*@column_spacing) / @column_max
      x = item % @column_max * (cursor_width + @column_spacing)
      y = item / @column_max * @row_height - @virtualOy
      return Rect.new(x, y, cursor_width, @row_height)
    end
  end

  def drawCursor(index,rect)
    if self.index==index
      bmp = @selarrow.bitmap
      pbCopyBitmap(self.contents,bmp,rect.x,rect.y+20)
    end
  end

  def drawItem(index,_count,rect)
    textpos = []
    rect = Rect.new(rect.x+16,rect.y+16,rect.width-16,rect.height)
    ypos = rect.y+4
    thispocket = @bag.pockets[@pocket]
    if index==self.itemCount-1
      textpos.push([_INTL("CLOSE"),rect.x,ypos,false,self.baseColor,self.shadowColor])
    else
      item = (@filterlist) ? thispocket[@filterlist[@pocket][index]][0] : thispocket[index][0]
      baseColor   = self.baseColor
      shadowColor = self.shadowColor
      textpos.push(
         [@adapter.getDisplayName(item),rect.x,ypos,false,baseColor,shadowColor]
      )
      if !pbIsImportantItem?(item)   # Not an HM (or infinite TM)
        qty = (@filterlist) ? thispocket[@filterlist[@pocket][index]][1] : thispocket[index][1]
        qtytext = _ISPRINTF("x{1: 3d}",qty)
        xQty    = rect.x+rect.width-self.contents.text_size(qtytext).width-16
        textpos.push([qtytext,xQty,ypos,false,baseColor,shadowColor])
      end
    end
    pbDrawTextPositions(self.contents,textpos)
  end

  def refresh
    @item_max = itemCount()
    self.update_cursor_rect
    dwidth  = self.width-self.borderX
    dheight = self.height-self.borderY
    self.contents = pbDoEnsureBitmap(self.contents,dwidth,dheight)
    self.contents.clear
    for i in 0...@item_max
      next if i<self.top_item || i>self.top_item+self.page_item_max
      drawItem(i,@item_max,itemRect(i))
    end
    drawCursor(self.index,itemRect(self.index))
  end

  def update
    super
    @uparrow.visible   = false
    @downarrow.visible = false
  end
end




class TMCase

  BASE=Color.new(248,248,248)
  SHADOW=Color.new(96,96,96)
  STATBASE=Color.new(64,64,64)
  STATSHADOW=Color.new(216,216,192)


  def initialize
    @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
    @viewport.z = 99999
    @move = true #set to false if you don't want the position of the disc to move
    @sprites = {}
    @sprites["bg"] = Sprite.new(@viewport)
    @sprites["bg"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/bg")
    @sprites["overlay"] = BitmapSprite.new(Graphics.width,Graphics.height,@viewport)
    pbSetSystemFont(@sprites["overlay"].bitmap)
    pbSetSystemFont(@sprites["bg"].bitmap)
    @power="---"
    @accuracy="---"
    @pp="---"
    @description="---"
    @type="normal"
    @sprites["case"] = Sprite.new(@viewport)
    @sprites["case"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/TM Case")
    @sprites["case"].x = 24
    @sprites["case"].y = 112
    @sprites["case"].z = 3
    @sprites["disc"] = Sprite.new(@viewport)
    @sprites["disc"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/tm_#{@type}")
    @sprites["disc"].x = 58
    @sprites["disc"].y = 76
    @sprites["disc"].z = 1
    @sprites["disc"].visible = false
    @sprites["sticker"] = Sprite.new(@viewport)
    @sprites["sticker"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/hmsticker")
    @sprites["sticker"].x = @sprites["disc"].x
    @sprites["sticker"].y = @sprites["disc"].y
    @sprites["sticker"].z = 2
    @sprites["sticker"].visible = false
    @sprites["itemlist"] = Window_TMCase.new($PokemonBag,nil,4,188,-17,344,40+32+7*32)
    @sprites["itemlist"].viewport    = @viewport
    @sprites["itemlist"].pocket      = 4
    @sprites["itemlist"].index       = 0
    @sprites["itemlist"].baseColor   = Color.new(96,96,96)
    @sprites["itemlist"].shadowColor = Color.new(208,208,200)
    @typebitmap    = AnimatedBitmap.new(_INTL("Graphics/Pictures/types"))
    overlay = @sprites["overlay"].bitmap
    pbDrawTextPositions(@sprites["bg"].bitmap,[[_INTL("TM CASE"),86,15,2,BASE,SHADOW]])
    overlay.font.size=24
    itemlist=@sprites["itemlist"]
    if itemlist.index<itemlist.itemCount-1
        movestats
        @sprites["disc"].visible = true
    else
        @power = "---"
        @accuracy= "---"
        @pp = "---"
        @description = "---"
    end
    textpos = [
         [_INTL("#{@power}   "),154,297,2,STATBASE,STATSHADOW],
         [_INTL("#{@accuracy}%  "),154,322,2,STATBASE,STATSHADOW],
         [_INTL("#{@pp} PP"),154,348,2,STATBASE,STATSHADOW]
      ]
    drawTextEx(overlay,192,268,320,4,@description,BASE,SHADOW)
    pbDrawTextPositions(overlay,textpos)
    pbFadeInAndShow(@sprites)
    main
  end


  def movestats
      overlay=@sprites["overlay"].bitmap
      itemlist=@sprites["itemlist"]
      moveid = pbGetMachine(itemlist.item)
    # Get data for selected move
      moveData = pbGetMoveData(moveid)
      @power = moveData[MOVE_BASE_DAMAGE]
      if @power == 0
        @power = "---"
      end
      @accuracy   = moveData[MOVE_ACCURACY]
      if @accuracy == 0
        @accuracy= "---"
      end
      @pp   = moveData[MOVE_TOTAL_PP]
      if @pp == 0
        @pp = "---"
      end
      @description   = moveData[MOVE_DESCRIPTION]
      type = moveData[MOVE_TYPE]
      if type == nil
        type = 0
      end
      if @description == nil
        @description = "---"
      end
      @type = PBTypes.getName(type).downcase
      typerect = Rect.new(0,type*28,64,28)
      overlay.blt(114,268,@typebitmap.bitmap,typerect)
      @sprites["disc"].bitmap = Bitmap.new("Graphics/Pictures/TM Case/tm_#{@type}")
  end


  def main
    loop do
      overlay=@sprites["overlay"].bitmap
      overlay.clear
      itemlist=@sprites["itemlist"]
      @sprites["disc"].visible=(itemlist.index<itemlist.itemCount-1)
      if itemlist.index<itemlist.itemCount-1
        movestats
      else
          @power = "---"
          @accuracy= "---"
          @pp = "---"
          @description = "---"
      end
      @sprites["sticker"].visible = (pbIsHiddenMachine?(itemlist.item))
      @sprites["sticker"].x = @sprites["disc"].x
      @sprites["sticker"].y = @sprites["disc"].y
      pbDrawTextPositions(@sprites["bg"].bitmap,[[_INTL("TM CASE"),86,15,2,BASE,SHADOW]])
      overlay.font.size=24
      textpos = [
         [_INTL("#{@power}   "),154,297,2,STATBASE,STATSHADOW],
         [_INTL("#{@accuracy}%  "),154,322,2,STATBASE,STATSHADOW],
         [_INTL("#{@pp} PP"),154,348,2,STATBASE,STATSHADOW]
        ]
      pbDrawTextPositions(overlay,textpos)
      drawTextEx(overlay,192,268,320,4,@description,BASE,SHADOW)
      Graphics.update
      Input.update
      if Input.trigger?(Input::RIGHT) && $game_variables[1]==8
        $game_variables[1]=1
        break
      elsif Input.trigger?(Input::LEFT) && $game_variables[1]==8
        $game_variables[1]=0
        break
      elsif Input.trigger?(Input::DOWN)  || Input.repeat?(Input::DOWN)
        if @sprites["disc"].x > 24 && @move==true
          if itemlist.itemCount>1
            pbPlayCursorSE
            if itemlist.index<itemlist.itemCount-1
              itemlist.index+=1
            else
              itemlist.index=0
              @sprites["disc"].x = 58
              @sprites["disc"].y = 76
            end
          end
          if itemlist.index<itemlist.itemCount-1 && itemlist.index>0 && @move==true
            @sprites["disc"].x -= 1
            @sprites["disc"].y += 1
          end
        end
      elsif Input.trigger?(Input::UP)  || Input.repeat?(Input::UP)
        if itemlist.itemCount>1
            pbPlayCursorSE
            if itemlist.index>0
              itemlist.index-=1
              if @sprites["disc"].x < 58  && @move==true
                  @sprites["disc"].x += 1
                  @sprites["disc"].y -= 1
                end
            else
              itemlist.index=itemlist.itemCount-1
              if @move==true
                  @sprites["disc"].x = (58-itemlist.itemCount)
                  @sprites["disc"].y = (76+itemlist.itemCount)
             end
            end
        end
      elsif Input.trigger?(Input::C)
        if itemlist.index<itemlist.itemCount-1
          pbUseItem($PokemonBag,itemlist.item)
          itemlist.refresh
        else
          break
        end
      elsif Input.trigger?(Input::A)
        choice = pbMessage(_INTL("Sort by"),
                [_INTL("Number"),
                _INTL("Type"),
                _INTL("Base Power"),
                _INTL("Accuracy"),
                _INTL("Name"),
                _INTL("Cancel")
                ])
        sortarray = []
          for i in 0...$PokemonBag.pockets[4].length
            item = $PokemonBag.pockets[4][i][0]
            moveid = pbGetMachine(item)
            moveData = pbGetMoveData(moveid)
            type = moveData[MOVE_TYPE]
            power =  moveData[MOVE_BASE_DAMAGE]
            accuracy =  moveData[MOVE_ACCURACY]
            name = PBMoves.getName(moveid)
            sortarray.push [item,type,power,accuracy,name]
          end
        if choice == 0
          $PokemonBag.pockets[4].sort!
        else
          sortarray.sort!  { |a,b| (a[choice]==b[choice]) ? a[0]<=>b[0] : a[choice]<=>b[choice] }
          for i in 0...$PokemonBag.pockets[4].length
            $PokemonBag.pockets[4][i][0]=sortarray[i][0]
          end
          itemlist.refresh
        end
      elsif Input.trigger?(Input::B)
        break
      end
    end
    pbSEPlay("GUI menu close",80)
    pbFadeOutAndHide(@sprites)
    $PokemonBag.pockets[4].sort!
    dispose
  end

  def dispose
    pbDisposeSpriteHash(@sprites)
    @viewport.dispose
  end
end
And if that's what you're doing, replace the bg.png in the folder with the bgfrlg!

Part 2: Where to access the TM case?
The TM case can be called from anywhere with TMCase.new, but we're going to have to work around our UI a bit, since it displays the TM pocket, so we'll need to go to PScreen_Bag.

If we want to just replace the TM pocket's usual display with this, then we'll just find this section:
Ruby:
          # Change pockets
          if Input.trigger?(Input::LEFT)
            newpocket = itemwindow.pocket
            loop do
              newpocket = (newpocket==1) ? PokemonBag.numPockets : newpocket-1
              break if !@choosing || newpocket==itemwindow.pocket
              if @filterlist; break if @filterlist[newpocket].length>0
              else; break if @bag.pockets[newpocket].length>0
              end
            end
            if itemwindow.pocket!=newpocket
              itemwindow.pocket = newpocket
              @bag.lastpocket   = itemwindow.pocket
              thispocket = @bag.pockets[itemwindow.pocket]
              pbPlayCursorSE
              pbRefresh
            end
          elsif Input.trigger?(Input::RIGHT)
            newpocket = itemwindow.pocket
            loop do
              newpocket = (newpocket==PokemonBag.numPockets) ? 1 : newpocket+1
              break if !@choosing || newpocket==itemwindow.pocket
              if @filterlist; break if @filterlist[newpocket].length>0
              else; break if @bag.pockets[newpocket].length>0
              end
            end
            if itemwindow.pocket!=newpocket
              itemwindow.pocket = newpocket
              @bag.lastpocket   = itemwindow.pocket
              thispocket = @bag.pockets[itemwindow.pocket]
              pbPlayCursorSE
              pbRefresh
            end
Right before each if itemwindow.pocket!=newpocket, paste this:
Ruby:
            if newpocket == 4
              $game_variables[1]=8
              TMCase.new
              case $game_variables[1]
              when 1
                newpocket = 5
              when 0
                newpocket = 3
              else
                return 0
              end
            end


But you might be uninterested in that- maybe you want the player to access TMs through the case as an item, or through the PC, or a dedicated event.

In that case, we'll go to the same section and make a similar change, but instead of pasting that bit of code, we'll paste this in the LEFT section:
Ruby:
            if newpocket == 4
              newpocket = 3
            end
And this in the right-
Ruby:
            if newpocket == 4
              newpocket = 5
            end

Further up in the script, find def pbRefresh, and replace it with this:

Ruby:
  def pbRefresh
    # Set the background image
    @sprites["background"].setBitmap(sprintf("Graphics/Pictures/Bag/bg_#{@bag.lastpocket}"))
    # Set the bag sprite
    fbagexists = pbResolveBitmap(sprintf("Graphics/Pictures/Bag/bag_#{@bag.lastpocket}_f"))
    if $Trainer.female? && fbagexists
      @sprites["bagsprite"].setBitmap("Graphics/Pictures/Bag/bag_#{@bag.lastpocket}_f")
    else
      @sprites["bagsprite"].setBitmap("Graphics/Pictures/Bag/bag_#{@bag.lastpocket}")
    end
    # Draw the pocket icons
    @sprites["pocketicon"].bitmap.clear
    if @choosing && @filterlist
      for i in 1...@bag.pockets.length
        if @filterlist[i].length==0
          if i<4
          @sprites["pocketicon"].bitmap.blt(6+(i-1)*26,6,
            @pocketbitmap.bitmap,Rect.new((i-1)*20,28,20,20))
          else
          @sprites["pocketicon"].bitmap.blt(6+(i-2)*26,6,
            @pocketbitmap.bitmap,Rect.new((i-1)*20,28,20,20))
          end
        end
      end
    end
    if @sprites["itemlist"].pocket <4
    @sprites["pocketicon"].bitmap.blt((@sprites["itemlist"].pocket-1)*26,2,
       @pocketbitmap.bitmap,Rect.new((@sprites["itemlist"].pocket-1)*28,0,28,28))
    else
    @sprites["pocketicon"].bitmap.blt((@sprites["itemlist"].pocket-2)*26,2,
    @pocketbitmap.bitmap,Rect.new((@sprites["itemlist"].pocket-1)*28,0,28,28))
    end
    # Refresh the item window
    @sprites["itemlist"].refresh
    # Refresh more things
    pbRefreshIndexChanged
  end

Finally, take the files in the folder "No TM Pocket" and paste them into Pictures/Bag, erasing the BGs already there.

It should come out looking like this!
tmless.gif


So, now that that's out of the way, let's set up a new way to use the TM case!

Like I said before, you can call it from pretty much anywhere via TMCase.new, but I'll just be showing the item as an example here. The script has the item handler coded at the top-
Ruby:
ItemHandlers::UseInField    .add(:TMCASE,proc { |item|
  TMCase.new
  next 1
})

So all we need to do is add the TM Case to the items PBS! Here's a little line set up for that!
XXX,TMCASE,TM Case,TM Cases,8,0,"A case that holds TMs and HMs. It is attached to the bag's compartment for important items.",2,0,6

Just replace XXX with an unused item ID! Make the itemXXX file match, and move that file to Graphics/Icons, and you're all set to use the TM Case as an item! Personally, it's my favorite way of doing so, because you can register it to the F key, but there's plenty of other interesting/useful ways to do it!

Future Goals
  • Smooth out the transitions a bit more
  • The original script had slightly different text appear-
    1618974599853.png
    - but I'm not super concerned about setting that up right now.​
Credits
Credit to TechSkylander1518, please!
Author
TechSkylander1518
Downloads
840
Views
3,802
First release
Last update
Rating
5.00 star(s) 1 ratings

More resources from TechSkylander1518

Latest updates

  1. v19 Update

    v19.1-compatible now! I think some of the instructions for accessing it are still v18, though...

Latest reviews

Thank you so much for your help in applying this to what I needed for my game, it works fabulously.
Back
Top