On this tutorial, I will talk in detail about the Windowskins in RPG maker XP.
The Windowskin is the graphic used to draw the windows that appear in the game.
PART 1. Parts of the Windowskin
Here you can see the limits of each part of the graphic
A. This part is the back of the windowskin. B. This part is the frame of the window. C. Those are the scroll arrows that appear on item lists. D. This part is the cursor. E. Those little squares are each one of the 4 frames of that little icon that appears at the bottom of the message window. That icon is called pause. F. Those are the 2 frames of the battle arrow that appears over the sprites when you pick them.
The display of most of those parts (A-E) is defined in the internal class Window, and that means you can't access the code that controls how they're displayed, but don't lose your hope; you can overwrite that class with a RGSS script, paste it over Main and customize that one instead.
The last arrows (F) have their own non-internal class called Arrow_Base. Even if they are on the same graphic, it may be easier to consider they're not part of the window themselves.
Something I want to highlight about the template is that, as you can see, the cursor actually has a small border around it that is not stretched, unlike the central part. I'll talk a bit more about this later.
Spoiler: Cursor's border
It doesn't matter how big the cursor is, the border mantains its thickness.
PART 2. Windowskin properties
The window has some properties that define how those parts are displayed.
Some can be modified (for example the window's opacity), but others are internal.
Modifiable:
Non modifiable:
PART 3. Stretch and tiling
When the window is bigger that the graphic, some parts of the graphic are stretched and some tile until they fill all that plane.
Spoiler: Example
[/quote]
On this example, the parts I painted with green blinds aren't stretched, but those with grey blinds are.
You can change the back stretch mode with a little script over Main, that changes the "stretch" variable commented before. That means you can also change that on each window independly or based on the current windowskin.
Ruby:
class Window alias stretch_mode_ini initialize unless $@ def initialize(*args) stretch_mode_ini(*args) self.stretch = false end end
In summary, the back has no border and its stretch depends on a variable, frames have a 16px border and don't stretch, and the cursor has a 2px border and stretches.
Spoiler: Example of windowskins with tiling background[quote]Here are some windowskins that will only look good with the stretch mode disabled.
PART 4. RGSS Rewrite of the Window Class
In order to modify some of the window properties more freely, you can use a script that overwrites the window methods in RGSS. That makes their displaying a bit more slow, but we have much more control over them. There are many scripts that overwrite that class, but since I'm as cool as a cucumber I've made one specially for this tutorial, free to use. I used Selwyn's rewrite as a reference.
Ruby:
#============================================================================== # ** [XP] Window - Hidden RGSS Class #------------------------------------------------------------------------------ # Author: Wecoc (no credits required) #------------------------------------------------------------------------------ # I used Selwyn's Window rewrite as reference. #============================================================================== #============================================================================== # * Bitmap #============================================================================== class Bitmap #-------------------------------------------------------------------------- # * Erase #-------------------------------------------------------------------------- def erase(*args) if args.size == 1 rect = args[0] elsif args.size == 4 rect = Rect.new(*args) end fill_rect(rect, Color.new(0, 0, 0, 0)) end #-------------------------------------------------------------------------- # * Cut #-------------------------------------------------------------------------- def cut(*args) case args.size when 1 # (rect) rect = args[0] x, y, width, height = *rect.size when 4 # (x, y, width, height) x, y, width, height = *args end return Bitmap.new(1, 1) if width <= 0 or height <= 0 bitmap = Bitmap.new(width, height) bitmap.blt(0, 0, self, Rect.new(x, y, width, height)) return bitmap end end #============================================================================== # * Tiled_Sprite #============================================================================== class Tiled_Sprite attr_reader :bitmap, :skin, :margin, :stretch #-------------------------------------------------------------------------- # * Initialize #-------------------------------------------------------------------------- def initialize(bitmap, m=1, stretch=true) w = bitmap.width h = bitmap.height @margin = m @stretch = stretch @skin = {} @skin[7] = bitmap.cut( 0, 0, m, m) @skin[9] = bitmap.cut(w-m, 0, m, m) @skin[1] = bitmap.cut( 0, h-m, m, m) @skin[3] = bitmap.cut(w-m, h-m, m, m) @skin[8] = bitmap.cut( m, 0, w-(m*2), m) @skin[4] = bitmap.cut( 0, m, m, h-(m*2)) @skin[6] = bitmap.cut(w-m, m, m, h-(m*2)) @skin[2] = bitmap.cut( m, h-m, w-(m*2), m) @skin[5] = bitmap.cut( m, m, w-(m*2), h-(m*2)) end end #============================================================================== # * Bitmap #============================================================================== class Bitmap #-------------------------------------------------------------------------- # * Draw Tiled Sprite #-------------------------------------------------------------------------- def draw_tiled(sprite) for i in 1..9 draw_tiled_part(sprite, i) end end #-------------------------------------------------------------------------- # * Draw Tiled Sprite (each part) #-------------------------------------------------------------------------- def draw_tiled_part(sprite, id) src_bitmap = sprite.skin[id] m = sprite.margin bx = (self.width - m * 2).to_f / src_bitmap.width by = (self.height - m * 2).to_f / src_bitmap.height dx = (src_bitmap.width * (bx.ceil.to_f - bx)).floor dy = (src_bitmap.height * (by.ceil.to_f - by)).floor case id when 1 blt(0, self.height - m, src_bitmap, src_bitmap.rect) when 3 blt(self.width - m, self.height - m, src_bitmap, src_bitmap.rect) when 7 blt(0, 0, src_bitmap, src_bitmap.rect) when 9 blt(self.width - m, 0, src_bitmap, src_bitmap.rect) when 2 if sprite.stretch == false for i in 0..bx.ceil rect = src_bitmap.rect rect.width = dx if i == bx.ceil blt(m + i * src_bitmap.width, self.height - m, src_bitmap, rect) end else dest_rect = Rect.new(m, self.height - m, self.width - m * 2, m) stretch_blt(dest_rect, src_bitmap, src_bitmap.rect) end when 4 if sprite.stretch == false for i in 0..by.ceil rect = src_bitmap.rect rect.height = dy if i == by.ceil blt(0, m + i * src_bitmap.height, src_bitmap, rect) end else dest_rect = Rect.new(0, m, m, self.height - m * 2) stretch_blt(dest_rect, src_bitmap, src_bitmap.rect) end when 6 if sprite.stretch == false for i in 0..by.ceil rect = src_bitmap.rect rect.height = dy if i == by.ceil blt(self.width - m, m + i * src_bitmap.height, src_bitmap, rect) end else dest_rect = Rect.new(self.width - m, m, m, self.height - m * 2) stretch_blt(dest_rect, src_bitmap, src_bitmap.rect) end when 8 if sprite.stretch == false for i in 0..bx.ceil rect = src_bitmap.rect rect.width = dx if i == bx.ceil blt(m + i * src_bitmap.width, 0, src_bitmap, rect) end else dest_rect = Rect.new(m, 0, self.width - m * 2, m) stretch_blt(dest_rect, src_bitmap, src_bitmap.rect) end when 5 if sprite.stretch == false for iy in 0..by.ceil for ix in 0..bx.ceil rect = src_bitmap.rect rect.width = dx if ix == bx.ceil rect.height = dy if iy == by.ceil blt(m + ix * src_bitmap.width, m + iy * src_bitmap.height, src_bitmap, rect) end end else dest_rect = Rect.new(m, m, self.width - m * 2, self.height - m * 2) stretch_blt(dest_rect, src_bitmap, src_bitmap.rect) end end end end #============================================================================== # * Cursor_Rect #============================================================================== class Cursor_Rect < ::Sprite attr_reader :width, :height, :skin, :margin, :sprite #-------------------------------------------------------------------------- # * Initialize #-------------------------------------------------------------------------- def initialize(viewport) super(viewport) @width = 0 @height = 0 @margin = 16 @skin = nil @sprite = nil end #-------------------------------------------------------------------------- # * Margin #-------------------------------------------------------------------------- def margin=(margin) @margin = margin get_cursor_sprite set(x, y, width, height) end #-------------------------------------------------------------------------- # * Skin #-------------------------------------------------------------------------- def skin=(skin) @skin = skin get_cursor_sprite end #-------------------------------------------------------------------------- # * Get Cursor Sprite #-------------------------------------------------------------------------- def get_cursor_sprite return if @skin == nil src_bitmap = @skin.cut(128, 64, 32, 32) @sprite = Tiled_Sprite.new(src_bitmap, 2, true) end #-------------------------------------------------------------------------- # * Set Width #-------------------------------------------------------------------------- def width=(width) return if @width == width @width = width if @width == 0 and self.bitmap != nil self.bitmap.dispose self.bitmap = nil end draw_rect end #-------------------------------------------------------------------------- # * Set Height #-------------------------------------------------------------------------- def height=(height) return if @height == height @height = height if @height == 0 and self.bitmap != nil self.bitmap.dispose self.bitmap = nil end draw_rect end #-------------------------------------------------------------------------- # * Set Coords #-------------------------------------------------------------------------- def set(x, y, width, height) self.x = x + @margin self.y = y + @margin if @width != width or @height != height @width = width @height = height if width > 0 and height > 0 draw_rect end end end #-------------------------------------------------------------------------- # * Clear cursor #-------------------------------------------------------------------------- def empty self.x = 0 self.y = 0 self.width = 0 self.height = 0 end #-------------------------------------------------------------------------- # * Draw cursor #-------------------------------------------------------------------------- def draw_rect return if @skin == nil or @sprite == nil if @width > 0 and @height > 0 self.bitmap = Bitmap.new(@width, @height) self.bitmap.draw_tiled(@sprite) end end end #============================================================================== # * Window #============================================================================== class Window attr_reader :x, :y, :z, :width, :height, :ox, :oy attr_reader :opacity, :back_opacity, :contents_opacity attr_reader :stretch, :visible, :pause, :margin attr_accessor :active #-------------------------------------------------------------------------- # * Initialize #-------------------------------------------------------------------------- def initialize @viewport = Viewport.new(0, 0, 0, 0) @cr_vport = Viewport.new(0, 0, 0, 0) @width = 0 @height = 0 @ox = 0 @oy = 0 @opacity = 255 @back_opacity = 255 @contents_opacity = 255 @margin = 16 @frame = Sprite.new @bg = Sprite.new @window = Sprite.new(@viewport) @pause_s = Sprite.new @arrows = [] for i in 0...4 @arrows.push(Sprite.new(@cr_vport)) @arrows.bitmap = Bitmap.new(16, 16) @arrows.visible = false end @cursor_rect = Cursor_Rect.new(@cr_vport) @cursor_fade = true @pause_s.visible = false @pause = false @active = true @stretch = true @visible = true self.x = 0 self.y = 0 self.z = 100 self.windowskin = RPG::Cache.windowskin($game_system.windowskin_name) end #-------------------------------------------------------------------------- # * Set Contents #-------------------------------------------------------------------------- def contents=(bmp) @window.bitmap = bmp if bmp != nil if bmp.width > @viewport.rect.width or bmp.height > @viewport.rect.height draw_arrows end end end #-------------------------------------------------------------------------- # * Get Contents #-------------------------------------------------------------------------- def contents return @window.bitmap end #-------------------------------------------------------------------------- # * Dispose #-------------------------------------------------------------------------- def dispose @bg.dispose @frame.dispose @window.dispose @cursor_rect.dispose @viewport.dispose @pause_s.dispose @cr_vport.dispose for arrow in @arrows arrow.dispose end end #-------------------------------------------------------------------------- # * Update #-------------------------------------------------------------------------- def update @window.update @cursor_rect.update @viewport.update @cr_vport.update update_pause update_visible update_arrows update_cursor end #-------------------------------------------------------------------------- # * Update Pause #-------------------------------------------------------------------------- def update_pause id = (Graphics.frame_count / 8) % 4 rect = Rect.new(160, 64, 16, 16) src_bitmap = Bitmap.new(rect.width, rect.height) px = rect.x + (id % 2) * rect.width py = rect.y + (id.to_f / 2).floor * rect.height src_bitmap.blt(0, 0, @skin, Rect.new(px, py, rect.width, rect.height)) @pause_s.bitmap = src_bitmap @pause_s.update end #-------------------------------------------------------------------------- # * Update Visible #-------------------------------------------------------------------------- def update_visible @frame.visible = @visible @bg.visible = @visible @window.visible = @visible @cursor_rect.visible = @visible if @pause @pause_s.visible = @visible else @pause_s.visible = false end end #-------------------------------------------------------------------------- # * Set Pause Mode #-------------------------------------------------------------------------- def pause=(pause) @pause = pause update_visible end #-------------------------------------------------------------------------- # * Update Arrows #-------------------------------------------------------------------------- def update_arrows if @window.bitmap == nil or @visible == false for arrow in @arrows arrow.visible = false end else @arrows[0].visible = @oy > 0 @arrows[1].visible = @ox > 0 @arrows[2].visible = (@window.bitmap.width - @ox) > @viewport.rect.width @arrows[3].visible = (@window.bitmap.height - @oy) > @viewport.rect.height end end #-------------------------------------------------------------------------- # * Update Cursor #-------------------------------------------------------------------------- def update_cursor if self.active == true if @cursor_fade @cursor_rect.opacity -= 10 @cursor_fade = false if @cursor_rect.opacity <= 100 else @cursor_rect.opacity += 10 @cursor_fade = true if @cursor_rect.opacity >= 255 end else @cursor_rect.opacity = 100 @cursor_fade = false end end #-------------------------------------------------------------------------- # * Set Visible #-------------------------------------------------------------------------- def visible=(visible) @visible = visible update_visible update_arrows end #-------------------------------------------------------------------------- # * Set X #-------------------------------------------------------------------------- def x=(x) @x = x @bg.x = x + 2 @frame.x = x @viewport.rect.x = x + @margin @cr_vport.rect.x = x @pause_s.x = x + (@width / 2) - 8 set_arrows end #-------------------------------------------------------------------------- # * Set Y #-------------------------------------------------------------------------- def y=(y) @y = y @bg.y = y + 2 @frame.y = y @viewport.rect.y = y + @margin @cr_vport.rect.y = y @pause_s.y = y + @height - @margin set_arrows end #-------------------------------------------------------------------------- # * Set Z #-------------------------------------------------------------------------- def z=(z) @z = z @bg.z = z - 1 @frame.z = z @cr_vport.z = z + 2 @viewport.z = z + 3 @pause_s.z = z + 4 end #-------------------------------------------------------------------------- # * Set OX #-------------------------------------------------------------------------- def ox=(ox) return if @ox == ox @ox = ox @viewport.ox = ox update_arrows end #-------------------------------------------------------------------------- # * Set OY #-------------------------------------------------------------------------- def oy=(oy) return if @oy == oy @oy = oy @viewport.oy = oy update_arrows end #-------------------------------------------------------------------------- # * Set Width #-------------------------------------------------------------------------- def width=(width) @width = width @viewport.rect.width = width - @margin * 2 @cr_vport.rect.width = width draw_window if @width > 0 and @height > 0 self.x = @x self.y = @y end #-------------------------------------------------------------------------- # * Set Height #-------------------------------------------------------------------------- def height=(height) @height = height @viewport.rect.height = height - @margin * 2 @cr_vport.rect.height = height draw_window if @height > 0 and @width > 0 self.x = @x self.y = @y end #-------------------------------------------------------------------------- # * Set Opacity #-------------------------------------------------------------------------- def opacity=(opacity) value = [[opacity, 255].min, 0].max @opacity = value @contents_opacity = value @back_opacity = value @frame.opacity = value @bg.opacity = value @window.opacity = value end #-------------------------------------------------------------------------- # * Set Back Opacity #-------------------------------------------------------------------------- def back_opacity=(opacity) value = [[opacity, 255].min, 0].max @back_opacity = value @bg.opacity = value end #-------------------------------------------------------------------------- # * Set Contents Opacity #-------------------------------------------------------------------------- def contents_opacity=(opacity) value = [[opacity, 255].min, 0].max @contents_opacity = value @window.opacity = value end #-------------------------------------------------------------------------- # * Get Cursor Rect #-------------------------------------------------------------------------- def cursor_rect return @cursor_rect end #-------------------------------------------------------------------------- # * Set Cursor Rect #-------------------------------------------------------------------------- def cursor_rect=(rect) @cursor_rect.x = rect.x @cursor_rect.y = rect.y if @cursor_rect.width != rect.width or @cursor_rect.height != rect.height @cursor_rect.set(@cursor_rect.x, @cursor_rect.y, rect.width, rect.height) end end #-------------------------------------------------------------------------- # * Get Windowskin #-------------------------------------------------------------------------- def windowskin return @skin end #-------------------------------------------------------------------------- # * Set Windowskin #-------------------------------------------------------------------------- def windowskin=(windowskin) return if windowskin == nil if @skin != windowskin @skin = windowskin @cursor_rect.skin = windowskin draw_window draw_arrows end end #-------------------------------------------------------------------------- # * Set Margin #-------------------------------------------------------------------------- def margin=(margin) if @margin != margin @margin = margin self.x = @x self.y = @y temp = @height self.height = 0 self.width = @width self.height = temp @cursor_rect.margin = margin set_arrows end end #-------------------------------------------------------------------------- # * Set Stretch #-------------------------------------------------------------------------- def stretch=(stretch) if @stretch != stretch @stretch = stretch draw_window end end #-------------------------------------------------------------------------- # * Set Arrow Positions #-------------------------------------------------------------------------- def set_arrows @arrows[0].x = @width / 2 - 8 @arrows[0].y = 8 @arrows[1].x = 8 @arrows[1].y = @height / 2 - 8 @arrows[2].x = @width - 16 @arrows[2].y = @height / 2 - 8 @arrows[3].x = @width / 2 - 8 @arrows[3].y = @height - 16 end #-------------------------------------------------------------------------- # * Draw Window Basics #-------------------------------------------------------------------------- def draw_window return if @skin == nil return if @width == 0 or @height == 0 draw_back draw_frame end #-------------------------------------------------------------------------- # * Draw Back #-------------------------------------------------------------------------- def draw_back @bg.bitmap = Bitmap.new(@width - 4, @height - 4) src_bitmap = @skin.cut(0, 0, 128, 128) sprite = Tiled_Sprite.new(src_bitmap, 0, @stretch) @bg.bitmap.draw_tiled(sprite) end #-------------------------------------------------------------------------- # * Draw Frame #-------------------------------------------------------------------------- def draw_frame @frame.bitmap = Bitmap.new(@width, @height) m = 16 src_bitmap = @skin.cut(128, 0, 64, 64) src_rect = Rect.new(m, m, 64 - m * 2, 64 - m * 2) src_bitmap.fill_rect(src_rect, Color.new(0, 0, 0, 0)) sprite = Tiled_Sprite.new(src_bitmap, m, false) @frame.bitmap.draw_tiled(sprite) end #-------------------------------------------------------------------------- # * Draw Arrows #-------------------------------------------------------------------------- def draw_arrows return if @skin == nil @arrows[0].bitmap = @skin.cut(152, 16, 16, 8) @arrows[1].bitmap = @skin.cut(144, 24, 8, 16) @arrows[2].bitmap = @skin.cut(168, 24, 8, 16) @arrows[3].bitmap = @skin.cut(152, 40, 16, 8) update_arrows end end
PART 5. Script adaptations
The Window script posted above defines in a single method the drawing of the sprites (used as a shortcut), this way it's easier to customize it taking into account both the border and the stretch mode.
That property is defined in Back, Frames, Cursor, and finally in Blind if you're using the Window Blind Add-On (see below).
It's also possible to change the cursor's windowskin independently, using cursor_rect.skin = name
This dynamic cursor skin can be useful if you want to change it based on a condition (for example, when the current choice is disabled).
Therefore, we can make other basic changes, implemented as "AddOns" below this base script.
The method update_pause defines how the pause graphic is loaded. There you can change it easily so that graphic is loaded using an independent graphic instead, for example this one. This way it can be as big as you want, and have more frames.
Ruby:
#============================================================================== # ** Window - Pause Frame Edit #============================================================================== class Window def update_pause #------------------------------------------------------------------------ # Number of frames per frame frames = 8 # Graphic used pause_bmp = RPG::Cache.picture("pause") #------------------------------------------------------------------------ h = pause_bmp.height i = pause_bmp.width / h id = (Graphics.frame_count / frames) % i rect = Rect.new(0, 0, h, h) src_bitmap = Bitmap.new(rect.width, rect.height) px = rect.x + id * rect.width src_bitmap.blt(0, 0, pause_bmp, Rect.new(px, 0, rect.width, rect.height)) @pause_s.bitmap = src_bitmap @pause_s.update end end
The method update_cursor defines the blinking of the cursor and its opacity when it's disabled. Disabling its blinking is very simple.
Ruby:
#============================================================================== # ** Window - Cursor Fade Fix #============================================================================== class Window def update_cursor if self.active == true @cursor_rect.opacity = 255 else @cursor_rect.opacity = 100 end end end
You could also make a cursor with multiple frames as in RM2k/3, to do that you can use the previous script for pause as a reference. Similarly, on the method draw_arrows you can change how the scroll arrows are displayed, in case you want them bigger, or animated, etc.
Inside the methods that define X and Y, you can find these:
@pause_s.x = x + (@width / 2) - 8
@pause_s.y = y + @height - @margin
That controls the position of the pause, so you can easily change it as well, like this:
Ruby:
#============================================================================== # ** Window - Pause position #============================================================================== class Window alias pause_pos_x x= unless $@ alias pause_pos_y y= unless $@ def x=(x) pause_pos_x(x) # Set Pause X @pause_s.x = x + @width - 24 end def y=(y) pause_pos_y(y) # Set Pause Y @pause_s.y = y + @height - 20 end end
Now margin is a modifiable property too, but I recommend not changing that.
The method set_arrows defines the position of the scroll arrows, which I don't recommend changing either.
The method draw_back defines how the background is displayed.
It gets the graphic with the rect (0, 0, 128, 128) from the windowskin and then uses this
sprite = Tiled_Sprite.new(src_bitmap, 0, @stretch)
That 0 is the margin, which means changing it you can make things like this image.
Ruby:
#============================================================================== # ** Window - Back margin #============================================================================== class Window def draw_back @bg.bitmap = Bitmap.new(@width - 4, @height - 4) src_bitmap = @skin.cut(0, 0, 128, 128) sprite = Tiled_Sprite.new(src_bitmap, 24, @stretch) @bg.bitmap.draw_tiled(sprite) end end
Right after that, the Frame is defined in a very similar way inside the method draw_frame, where m = 16 is the margin.
sprite = Tiled_Sprite.new(src_bitmap, m, false)
Changing that to true allows the borders of the frames to stretch, which may be interesting in some cases. You can check it here.
Ruby:
#============================================================================== # ** Window - Frame Stretch #============================================================================== class Window def draw_frame @frame.bitmap = Bitmap.new(@width, @height) m = 16 src_bitmap = @skin.cut(128, 0, 64, 64) src_rect = Rect.new(m, m, 64 - m * 2, 64 - m * 2) src_bitmap.fill_rect(src_rect, Color.new(0, 0, 0, 0)) sprite = Tiled_Sprite.new(src_bitmap, m, true) @frame.bitmap.draw_tiled(sprite) end end
Finally (this is getting long), the last interesting method is get_cursor_sprite, which defines the display of the cursor. The default 2px border is very limiting, so you can now change it to something more wide. You can also make it tile.
As before, all that is defined on this line:
@sprite = Tiled_Sprite.new(src_bitmap, 2, true)
Here's my version
Ruby:
#============================================================================== # ** Window - Cursor Sprite #============================================================================== class Cursor_Rect < ::Sprite def get_cursor_sprite return if @skin == nil src_bitmap = @skin.cut(128, 64, 32, 32) @sprite = Tiled_Sprite.new(src_bitmap, 14, true) end end
Spoiler: AddOns - Window Blind
More recent RPG maker versions have an extra part on the graphic with blinds, so you can define at once a tiling and a stretching part for the back of your windows. I've made a little AddOn for this script that allows doing that, but you'll need a Picture called blind.
Ruby:
#============================================================================== # ** Window Blind Add-On #------------------------------------------------------------------------------ # This script requires the Window - Hidden RGSS Class by Wecoc #============================================================================== class Window alias blind_ini initialize unless $@ def initialize @blind = Sprite.new @blind.blend_type = 0 blind_ini end alias blind_dis dispose unless $@ def dispose blind_dis @blind.dispose end alias blind_visible update_visible unless $@ def update_visible blind_visible @blind.visible = @visible end alias blind_x x= unless $@ def x=(x) blind_x(x) @blind.x = x + 2 end alias blind_y y= unless $@ def y=(y) blind_y(y) @blind.y = y + 2 end def z=(z) @z = z @bg.z = z @blind.z = z + 1 @frame.z = z + 2 @cr_vport.z = z + 3 @viewport.z = z + 4 @pause_s.z = z + 5 end alias blind_opacity opacity= unless $@ def opacity=(opacity) value = [[opacity, 255].min, 0].max blind_opacity(value) @blind.opacity = value end alias blind_back_opacity back_opacity= unless $@ def back_opacity=(opacity) value = [[opacity, 255].min, 0].max blind_back_opacity(value) @blind.opacity = value end alias blind_draw_back draw_back def draw_back blind_draw_back @blind.bitmap = Bitmap.new(@width - 4, @height - 4) src_bitmap = RPG::Cache.picture("blind") sprite = Tiled_Sprite.new(src_bitmap, 0, false) @blind.bitmap.draw_tiled(sprite) end end
Spoiler: AddOns - Chrono Trigger Windowskin
The windows of Chrono Trigger have two separated backs, similar to VX body and blind, but the other way around; the top part is the stretched one. You can see it here.
You could try to modify the stretch modes in the Blind Addon, but it wouldn't look exactly the same, so I made it a separate AddOn instead.
Ruby:
#============================================================================== # ** Window Chrono Trigger #------------------------------------------------------------------------------ # This script requires the Window - Hidden RGSS Class by Wecoc #============================================================================== class Window alias chrono_ini initialize unless $@ def initialize @chrono_lighten = Sprite.new @chrono_darken = Sprite.new @chrono_lighten.blend_type = 1 @chrono_darken.blend_type = 2 chrono_ini self.stretch = false end alias chrono_dis dispose unless $@ def dispose chrono_dis @chrono_lighten.dispose @chrono_darken.dispose end alias chrono_visible update_visible unless $@ def update_visible chrono_visible @chrono_lighten.visible = @visible @chrono_darken.visible = @visible end def update_cursor if self.active == true @cursor_rect.opacity = 255 else @cursor_rect.opacity = 100 end end alias chrono_x x= unless $@ def x=(x) chrono_x(x) @bg.x = x @chrono_lighten.x = x @chrono_darken.x = x end alias chrono_y y= unless $@ def y=(y) chrono_y(y) @bg.y = y @chrono_lighten.y = y @chrono_darken.y = y end def z=(z) @z = z @bg.z = z @frame.z = z + 1 @chrono_lighten.z = z + 2 @chrono_darken.z = z + 2 @cr_vport.z = z + 3 @viewport.z = z + 4 @pause_s.z = z + 5 end alias chrono_opacity opacity= unless $@ def opacity=(opacity) value = [[opacity, 255].min, 0].max chrono_opacity(value) @chrono_lighten.opacity = value @chrono_darken.opacity = value end def draw_back @bg.bitmap = Bitmap.new(@width, @height) src_bitmap = @skin.cut(0, 0, 128, 128) sprite = Tiled_Sprite.new(src_bitmap, 16, @stretch) @bg.bitmap.draw_tiled(sprite) @chrono_lighten.bitmap = Bitmap.new(@width, @height) src_bitmap = RPG::Cache.picture("chrono_lighten") sprite = Tiled_Sprite.new(src_bitmap, 0, true) @chrono_lighten.bitmap.draw_tiled(sprite) @chrono_darken.bitmap = Bitmap.new(@width, @height) src_bitmap = RPG::Cache.picture("chrono_darken") sprite = Tiled_Sprite.new(src_bitmap, 0, true) @chrono_darken.bitmap.draw_tiled(sprite) end end
In this case it requires two extra images in the Pictures folder; chrono_lighen and chrono_lighten. I also made a skin in case you want to try it (don't use it on your game, it's just for testing purposes).