Chaos Project

RPG Maker => RPG Maker Scripts => RMXP Script Database => Topic started by: KK20 on November 02, 2014, 05:53:24 am

Title: [XP] XP Ace Tilemap
Post by: KK20 on November 02, 2014, 05:53:24 am
XP Ace Tilemap
Authors: KK20
Version: 0.42
Type: Tilemap Rewrite
Key Term: Game Utility



Introduction

In light of recent discoveries regarding the usage of RGSS3 in RPG Maker XP games (http://forum.chaos-project.com/index.php/topic,12899.0.html), many users were left with a dilemma in choosing which Tilemap rewrite to use due to the vast differences between RGSS1's and RGSS3's Tilemap classes that would cause complications in this transition. I aimed to find the best Tilemap rewrite and decided that I would have to make my own. Like every other Tilemap rewrite before it, this implementation is in no ways perfect, boasting PROs and CONs.

This script is intended to be used for RPG Maker XP games using the RGSS3 library (unofficially coined RPG Maker XP Ace); however, it is entirely compatible with RPG Maker XP games in the RGSS1 library.

This work is protected by the following license:
Quote
Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported
( http://creativecommons.org/licenses/by-nc-sa/3.0/ )

You are free:

to Share - to copy, distribute and transmit the work
to Remix - to adapt the work

Under the following conditions:

Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).

Noncommercial. You may not use this work for commercial purposes.

Share alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one.

- For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.

- Any of the above conditions can be waived if you get permission from the copyright holder.

- Nothing in this license impairs or restricts the author's moral rights.



Features

About the script:

Add-ons:



Screenshots

None


Demo

None


Script

Includes script, DLL, and source code for the DLL:
v0.42 (https://www.dropbox.com/s/sx3izwzot2demx2/XPAT_v0.42.zip?dl=0) *NEW*
v0.41 (https://www.dropbox.com/s/2gb27r0zvpsxpmb/XPAT_v0.41.zip?dl=0)
v0.4 (https://www.dropbox.com/s/xslll0b5yztqplm/XPAT_v0.4.zip?dl=0)
v0.36 (https://www.dropbox.com/s/x9x0mittmbzjfvr/XPAT_v0.36.zip?dl=0)


Instructions




Compatibility

The script is still in its infancy. Thorough testing has not been conducted. Posting your observations would be greatly appreciated.
Users have reported Screen Flash to not work in their XPA games which I have yet to reproduce. It is unclear if my Tilemap script is causing the incompatibility or its the change in logic in RGSS3.

Transitions for larger resolutions are not supported as of yet, but a default fade-in/out exists. Consider using a transitions script.
I still have not thoroughly tested v0.3+ in XP so please advise that there may be potential bugs.

Screen Tone changes can lower the FPS of your game if using a larger resolution. This is further amplified if your tone uses a Gray value greater than 0. Tone changes are an expensive post-processing operation. Remember that RGSS was designed with 640x480 in mind--performance was built around that size.

Most scripts were designed with a resolution of 640x480 in mind. Here are a collection of fixes (http://forum.chaos-project.com/index.php/topic,7947.0.html) to address some of the more popular scripts like Blizz-ABS. You will need to replace all instances of SCREEN with SCREEN_RESOLUTION.


Credits and Thanks




Author's Notes

Known Bugs:


I would appreciate it if you, the user, would be able to test this script for compatibility issues. This is a side-project of mine that I would like to see evolve over time. If you have any suggestions as well, post them.

Things currently planned:

Title: Re: [XP] XP Ace Tilemap
Post by: noixez on November 02, 2014, 05:55:28 am
First! (http://smileys.smilchat.net/smiley/sport/coupe-bravo/cheerleaders.gif)
GOOOOOOOOOOOO KK20

But srs, liek awersome job on this mang
Title: Re: [XP] XP Ace Tilemap
Post by: G_G on November 04, 2014, 10:05:46 am
Looking forward to seeing this improve. Still setting up all the software and whatnot on my computer, RPG Maker is one of them not installed. I'll leave some feedback as soon as I can both XP and Ace running.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 04, 2014, 06:22:21 pm
Other than just making it a bit more compatible, I'm not sure if there is a way to make it "faster". I've tried different approaches and this was the best I could manage. Anything else and we lose basic design features. Or if someone knew how to use a better graphics library in conjunction with RPG Maker, I'd love to hear. Otherwise, we'll have to wait for ARC or RPG.NET.

I am liking this Tilemap implementation though. Switching out Custom Resolution v96 for this in Advance Wars Engine brought the FPS back to 60. And I can still create multiple Tilemap objects and still maintain that 60 if I only use 1 level of priority, which it really is all it needs.

Transitions are going to be tricky. It seems they only apply to a 1024x768 area in XPA (and probably still 640x480 in XP, iirc). Tried importing a Transitions script, but it didn't help cover an area of 1200x800.

Still bug squashing as well. Zex said screen flash doesn't work, but I don't see what's wrong.
Title: Re: [XP] XP Ace Tilemap
Post by: G_G on November 04, 2014, 06:41:21 pm
I don't really understand how transitions work so I can't really help you there. I myself may still end up trying to do a tilemap used the Tiled map editor. Already have a decent idea on how to tackle it. I'll obviously have to rely on Ace for this since XP/VX parse JSON or XML far too slowly, though I suppose I could always do a one time parse and convert it to Ruby format. If we could actually draw on top of the window I might be able to do something.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 12, 2014, 03:47:14 am
Bug report:

this will happen when screen is shaking:
(http://i.imgur.com/kOl1wTws.jpg) (http://i.imgur.com/kOl1wTw.jpg) (http://i.imgur.com/4MmQjpYs.jpg) (http://i.imgur.com/4MmQjpY.jpg)

also when using a lot of animation / bitmap effects, the game will crash  :uhm:
(http://i.imgur.com/ME7JaNRs.jpg) (http://i.imgur.com/ME7JaNR.jpg)
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 12, 2014, 04:14:16 am
Would you like to give me that demo? I spent a good number of days trying to perfect screen shaking.
You sure it's not something to do with floats in the equations?

Animation/effects of...what? More specific please. I don't see how that could cause the Tilemap to crash.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 12, 2014, 07:08:58 am
どうぞ: *links removed*
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 12, 2014, 02:00:16 pm
I can confirm that it has something to do with XAS, but we all know how much of a nightmare that battle system is to navigate through.
I created an event with the script call:

$game_screen.start_shake(5,10,200)

and proceeded to walk up and down to force vertical screen scrolling. In XAS, I could get the disjointed tilemap in the pictures. In a clean project, I can't get it to happen.

Okay, it seems to be happening when along the map's edges. Performing a shake in the middle of the map wasn't doing anything.

EDIT: Put this at the beginning of Tilemap#ox=

    if !$game_screen.shaking? && -(@ox % 32) != @ground_sprite.x
      @first_update = true
    end

Title: Re: [XP] XP Ace Tilemap
Post by: PhoenixFire on November 13, 2014, 07:57:24 am
Well, I placed in the current collaboration I'm working on, and it flows very smoothly. I like it! Great job KK!

Now to update the XPA download package with this..
Title: Re: [XP] XP Ace Tilemap
Post by: MetalZelda on November 13, 2014, 10:26:18 am
Well well well this is a interesting script but I'm having issues

Spoiler: ShowHide
(http://i.imgur.com/RScna1J.png)

THIS LOOKS LIKE A VINESAUCE CORRUPTION THIS IS AMAZING 20/20 FOR ORIGINALITY
Spoiler: ShowHide
(http://i.imgur.com/uGFxGSl.png)


Perhaps it is due to XAS ... Or layers ... I don't really know
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 13, 2014, 10:34:48 am
It's due to xas, see above ^
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 13, 2014, 11:45:11 pm
@MetalZelda:
Did you try doing what I last said?

@Phoenix:
Appreciate it :) Was wondering where you went :U

Also need to explain how to define custom autotile graphics. I'll probably have a different method when I get around to finalizing this.
Anyways, for you smart people, you know how you can see the autotile patterns by double clicking an autotile in your tile palette and how it creates a window of 8x6 tiles? You have to make your autotile look like that. It won't look as pretty in the editor though, so I was thinking of putting like a keyword in the filename for the script to find and replace it with in-game.
Title: Re: [XP] XP Ace Tilemap
Post by: PhoenixFire on November 14, 2014, 07:47:04 am
@kk20 ~ Yeah, I haven't been all too active in the way of topics, but I've been lurking occassionally. IO also just got put as a donator, RMRK+ and Extra Access at RMRK, so I've had alot of reading to do there as well (I think we might be doing another contest soon). Additionally, I've been working on 13 Ghosts alot lately, because it is now a co-operative project with myself, an old member from here (tSwitch) one of our other coworkers (professional graphics desiner) and my wifeyness; needless to say, combine that with being a parent and having a job, and it equals out to being really busy lmao

In regards to the tilemap specifically, do you know off the top of your head what the maximum number of specific auto-tile custom update rules are that it accepts before it starts to lag a little bit? I haven't had any issues yet, but, I'm thinking about also releasing a preliminary "demo" of the game as a starter kit of sorts (think similar to the harvest moon, or zelda starter kits) and I would love to be able to include as much detail as is possible about all aspects of the kit within the documentation I would provide with it.
Title: Re: [XP] XP Ace Tilemap
Post by: MetalZelda on November 14, 2014, 08:30:07 am
Quote from: KK20 on November 13, 2014, 11:45:11 pm
@MetalZelda:
Did you try doing what I last said?


Yup, tried, it works when I walk left / right but only on a map edge, and it's pretty much laggy (under 20 FPS), but some tricks might make this work 100% with XAS
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 14, 2014, 05:56:06 pm
Think I can take a look at your Scripts.rxdata? I mainly want to check for anything that changes Tilemap.ox and .oy since that is really the only explanation for such an effect to take place.

What FPS were you getting before and with what Tilemap? I'd think that XAS, like BlizzABS, is process heavy and is prone to number-crunching lag regardless of the Tilemap rewrite chosen.

Drago, I cannot seem to replicate the effect where the upper layers are drawn higher than they should be. I need to know the specifics of what you are doing and what is happening.

Phoenix, as a general pointer, having the autotiles update with very few frames in between causes more calls to the DLL and, in general, more lag. As for the custom autotile graphics, there shouldn't be any problem with lag in that department. Of course having 20 frame autotile animations everywhere would probably take up a good chunk of RAM.

Also, while messing around in Advance Wars Engine, changing the Sprite#color of the tilemap dropped the frame rate significantly (almost 20FPS drop), and this was just a 640x480 resolution with 1 priority layer.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 15, 2014, 02:23:41 am
I'm just jumping normally (jump up / jump down) and I get that glitch
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 15, 2014, 03:20:28 am
My suspicion was correct: it's float values modifying the Tilemap#ox/oy. Can't do that since I'm relying on those values to move the sprites that are drawing the tilemap.

sprite.x = 50
sprite.x += 0.0000000000000001 #=> 50
sprite.x -= 0.0000000000000001 #=> 49

I have a feeling that, for both of you guys, the pixel movement system you are using is causing this.

Anyways, you can try converting the ox and oy values being passed into integers and see if that works.

def ox=(ox)
  ox = ox.round
  ...
end

def oy=(oy)
  oy = oy.round
  ...
end
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 15, 2014, 11:19:20 am
zoom implemented : http://pastebin.com/XwScRzim

Spoiler: ShowHide
$game_map.start_zoom(x, y, zoom, duration = 20) # of course zoom had to be integer or else tilemap will glitch
$resolution.resize_screen(width,height)
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 15, 2014, 11:43:18 am
Oh sweet ima try that out
Edit: Um, for some reason my game window doesn't go larger than 640x480
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 15, 2014, 11:54:33 am
@^ use RGSS300.dll or try delete this line

    return Graphics.resize_screen(w,h) if Graphics.respond_to?(:resize_screen)
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 15, 2014, 11:57:52 am
It was because I didn't use the script call you mentioned $resolution.resize_screen(width,height).
The zoom thing is totes awesome though, perfect for my cutscenes :D

Edit: oh wait, I just noticed that it doesn't affect character/event sprites
Title: Re: [XP] XP Ace Tilemap
Post by: MetalZelda on November 15, 2014, 12:03:47 pm
Quote from: Zexion on November 15, 2014, 11:57:52 am
Edit: oh wait, I just noticed that it doesn't affect character/event sprites


Not using the same engine but same problem
Anyway it got heavily improved, no more probs
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 15, 2014, 12:08:43 pm
It's kinda funny how such a small thing like floats can cause such destruction xD
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 15, 2014, 12:10:24 pm
Quote from: Zexion on November 15, 2014, 11:57:52 am
Edit: oh wait, I just noticed that it doesn't affect character/event sprites


search in all your script that rewrites zoom_x & zoom_y in Sprite_Character#update
then below that try to add this
    self.zoom_x = $game_map.zoom_x
    self.zoom_y = $game_map.zoom_y
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 15, 2014, 12:23:32 pm
Alright it's working, but just a heads up *= in the update method caused it to keep zooming forever so I just did =
Is there anyway to keep the resolution from changing back to 640,480?
At the moment, it begins at 640x480 resolution. I head over to the event and call the zoom and resolution changes, which works initially, but the resolution then changes back leaving excess black space.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 15, 2014, 12:44:02 pm
Quote from: Zexion on November 15, 2014, 12:23:32 pm
Is there anyway to keep the resolution from changing back to 640,480?


try replace resize_screen method with :

*--deleted--*
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 15, 2014, 12:49:30 pm
It still happens :\
Maybe it's something in the update method?
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 15, 2014, 12:55:00 pm
probably something in your script keeping the resolution back again? (search all Graphics.resize_screen in your script)
or maybe you really should change your dll to RGSS300.dll
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 15, 2014, 01:00:39 pm
The thing is, it works with the version on the first post. I have the rgss300.dll, and I'm only calling Graphics.resize_screen in main, which is to set the screen to 854x480 for the dll. I searched all my scripts and none of them call resize_screen D:
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 15, 2014, 04:10:51 pm
wooo~ thanks for that Drago! I'll have to take a look at it later this week.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 16, 2014, 12:45:43 am
@zexion
try redownloading the script, if it still persist, send me a demo so I can look at it
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 16, 2014, 12:41:00 pm
You fixed it :D
Title: Re: [XP] XP Ace Tilemap
Post by: MetalZelda on November 17, 2014, 11:05:40 am
Still have probs with zoom, and I know it's due to the XAS engine I'm using, but after hours and hours of tweaks of the XAS main scripts I wasn't able to make it to work  :???:
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 17, 2014, 12:31:23 pm
Is it still the sporadic column shifting and what not or is it something else?
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 17, 2014, 10:28:49 pm
Quote from: MetalZelda on November 17, 2014, 11:05:40 am
Still have probs with zoom, and I know it's due to the XAS engine I'm using, but after hours and hours of tweaks of the XAS main scripts I wasn't able to make it to work  :???:


try cut this part from the script and place it in a new slot below XAS and above main

#==============================================================================
# ** Sprite_Character
#------------------------------------------------------------------------------
#  This sprite is used to display the character.It observes the Game_Character
#  class and automatically changes sprite conditions.
#==============================================================================
class Sprite_Character
 
  $@ || alias_method(:zoom_update_character, :update)
 
  def update(*args)
    if @old_character_zoom_x
      self.zoom_x = @old_character_zoom_x
      self.zoom_y = @old_character_zoom_y
    end
    zoom_update_character(*args)
    @old_character_zoom_x = self.zoom_x
    @old_character_zoom_y = self.zoom_y
    self.zoom_x *= $game_map.zoom_x
    self.zoom_y *= $game_map.zoom_y
  end
end
Title: Re: [XP] XP Ace Tilemap
Post by: PhoenixFire on November 18, 2014, 10:25:41 am
Added the new tilemap to the XPAce package: http://rmxpace.com/rmxpace/XPAce.zip
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 18, 2014, 10:52:25 am
Drago, did you add fullscreen to it? Last time I tried, the screen just stretched and showed 640x480 but now it goes into proper full screen and retains window size when exiting. I'm asking because that's exactly what I wanted, and I wanted to take a look at the code for full screen, but I don't see it.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on November 19, 2014, 12:21:30 am
done

$resolution.fullscreen  # go to fullscreen 
$resolution.fullscreen? # returns true if fullscreen
$resolution.window      # revert to window
Title: Re: [XP] XP Ace Tilemap
Post by: MetalZelda on November 19, 2014, 09:25:09 am
Quote from: LiTTleDRAgo on November 17, 2014, 10:28:49 pm
try cut this part from the script and place it in a new slot below XAS and above main


It partially fixed the zoom, the player zoom works but not the event, XAS Sprite was the culprit for the player



Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 19, 2014, 01:20:23 pm
He posted the fix earlier, you have to add
    self.zoom_x = $game_map.zoom_x
    self.zoom_y = $game_map.zoom_y

in any scripts that change the zoom of sprite_character. Which isn't just limited to xas
Title: Re: [XP] XP Ace Tilemap
Post by: G_G on November 24, 2014, 07:42:46 pm
Finally got around to testing this on the XP engine alone. I was getting a constant 39-40 FPS on an 800x640 resolution with a 100x100 map and increased weather effects. Priority level also set to 5. Though to be fair, my processor power probably has a lot to do with it.

Spoiler: ShowHide
(http://puu.sh/d4l4T/77f52a59b0.png)


Just to experiment, I changed the resolution to 1792x952 with that 100x100 map and same settings. Still getting max FPS. So I'm pretty positive it's my processor keeping up with it.

Large Image: ShowHide
(http://puu.sh/d4l75/43629b1779.png)


I figured I would have had to switch to the VX Ace implementation in order to get these results considering how much slower Ruby 1.8 is.
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on November 25, 2014, 01:14:46 am
dayum 1792x952 o.o
My computer would explode
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on November 25, 2014, 02:56:04 am
It always seems to me that XP can handle a large amount of graphics better than VXA can. You will probably get worse results trying the XPA method (especially if aiming for 60 FPS).
Title: Re: [XP] XP Ace Tilemap
Post by: G_G on November 25, 2014, 05:34:07 am
Just for shits and giggles I decided to try it out anyways. Still got some very promising results except for the fact that when the screen resizes in Ace's engine, it seems to cut part of the screen off. Could this be because I use Windows Blinds?

Spoiler: ShowHide
(http://puu.sh/d4Ow7/8138749018.png)


1280x720: ShowHide
(http://puu.sh/d4ODz/93931b9f7b.png)


This one had a huge frame drop, but still not terrible. xD
1792x952: ShowHide
(http://puu.sh/d4ONl/d2d71f5196.png)


EDIT: Screen cut off was apparently because of skinning my windows. Changed back and it works fine. It's weird though, I don't get any weird cut offs when using XP's engine.

EDIT 2: Kept it at 1280x720 with a shit load of events and screen flashing every 30 frames. XP Engine was keeping at a steady 39-40 FPS again.

Spoiler: ShowHide
(http://puu.sh/d4PqG/b9d2e568d1.png)
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on November 25, 2014, 07:05:11 am
1792x952 is not divisible by 32x32. :P At least 952 isn't divisible by 32.
Title: Re: [XP] XP Ace Tilemap
Post by: G_G on November 25, 2014, 08:13:12 pm
I know,  but I was trying to keep the 16:9 Aspect Ratio.
Title: Re: [XP] XP Ace Tilemap
Post by: Zangetsu on March 17, 2015, 09:30:04 pm
I am using this script and changed my resolution to 896 x 576... but the problem is my message box floats in an odd place... any idea how to move it down to the bottom of the screen?

I am also using UMS :D

EDIT:
I should describe my problem more I think... I am using XP, and when I playtest I see the messagebox here: http://orig03.deviantart.net/7b07/f/2015/076/6/a/screenshot_2015_03_17_19_54_49_by_espada_kitsuki-d8m4tkc.png
No matter how I edit the UMS, I can't move the message box to the bottom of thes screen, I can't figure it out.

Please help :)
Title: Re: [XP] XP Ace Tilemap
Post by: Zexion on March 17, 2015, 10:17:59 pm
Well, now that the screen is bigger, the coordinates of the message box have to change as well.

Look for this line in the UMS script:
y = 480 - $game_system.window_height - 16

Change the 480 to match your screen height. Just remember that if you decide to change the resolution later you'll have to change this number again xD
Title: Re: [XP] XP Ace Tilemap
Post by: Zangetsu on March 17, 2015, 10:40:18 pm
Hm, for some reason it doesn't work  :???: That's odd... there's a lot of lines where 480 is writtenin the script, would I have to replace them all then?

EDIT:
I replaced all of the 480s in the script, it works now! :D Thanks for your help, it put me on the right path! uwu
Title: Re: [XP] XP Ace Tilemap
Post by: Otávio Rapôso on April 28, 2015, 06:13:33 pm
KK20, Drago Custom Resolution II (http://littledrago.blogspot.com.br/2014/07/rgss-drago-custom-resolution-ii.html) has a lot less graphical glitches than your Tilemap script, but it's slower and it lacks the feature of centering the map on the screen. Could you adapt it (our your script) to make this PROS work togheter?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on April 28, 2015, 06:17:45 pm
What graphical glitches?
Title: Re: [XP] XP Ace Tilemap
Post by: Otávio Rapôso on April 28, 2015, 07:04:05 pm
I just found that some glitches were caused by the Smooth Scrolling script. But now, without the script, there are new problems, like monster's events (I'm using BlizzABS) that become invisible. There is also a problem involving a time gap between entering a new map and centering the map on the screen. I'll be sending you the project that I'm using to test RMXP Ace with big resolutions (1366x768 in fullscreen, more precisely). It's actually a modification on Echoes of Time (http://forum.chaos-project.com/index.php/topic,14885.0.html). Try to test the game with both the Smooth Scrolling script and without it. Try to use also Drago Custom Resolution script (it's already commented in the script editor). You can use my saved game if you want (just go back some maps). Here is the link to the files: http://www.mediafire.com/download/6iaus7gdhvg7dui/Echoes_of_Time.rar

EDIT: I forgot to change the SCREEN_RESOLUTION constant on the demo.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on April 28, 2015, 07:11:57 pm
There's already been a discussion on smooth scrolling scripts in this thread. The solution is also provided but I have not uploaded the fix.

I also didn't test the tilemap with any outside scripts as my main goal was just to get something working and hope enough users would do the testing for me. Rest assured I will get back to updating the code sometime after I graduate from school in a few weeks.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on May 02, 2015, 08:24:27 am
I have weird problem with this script, for some reason map with ID 21 started to make game crash with message "Rgss Player has stopped working", There where only four 'teleport' events... When I deleted those events, games keep crashing at launch with message 'can't find the specified procedure' I have no idea what is going on.

Details in RGSS player has stopped working error ( not english, but there is something about XPATilemap.dll)
http://postimg.org/image/8l5kofecr/

edit,
I just created a new map, and copied all mapping and events, it still don't work.
Deleted all events - still nothing.
Deleted all tileset elemtents from the map - game doesn't crash ;o
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on May 02, 2015, 04:05:44 pm
Then your tileset graphic is probably not of the correct proportions. Can you post the graphic?
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on May 03, 2015, 01:20:10 am
Tileset is in correct proportions, I just checked it. It's 256x9696. And it's not some kind of special map, just another part of forest.

Okay, I replaced for test your rewrite with The King rewrite, and I'm not getting any errors.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on May 03, 2015, 03:01:09 am
It's something that I'm not really capable of checking out at the moment. Send me a demo anyways so that I can see if it really is a bug with the script. I do plan on updating this soon.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 07, 2016, 07:10:23 am
I found a bug. When leaving the screen area and returning to it, it seems that additional blitting occurs over areas that were already blitted so the shadowed part of the graphic gets repeated.

initlal state: ShowHide
(http://imgur.com/geTLNDc.png)


after moving so that part goes offscreen: ShowHide
(http://imgur.com/s9D0TN0.png)


I downloaded this yesterday so I am definitely using the most recent version. I did comment out some pieces of code regarding custom resolution, but that didn't affect this bug at all.

EDIT: You might not be able to reproduce with a tileset that uses 8-bit color and has keyed transparency and semi-transparency colors. You have to use a proper 32-bit PNG for this with actual semi-transparent pixels.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 07, 2016, 11:27:55 am
Blizzard on RMXP? What is this madness??

Zexion pointed this one out to me a while ago. I was planning on updating the script and including that fix along with other new changes, but I slowly kept putting it off until I forgot about it. :T

This should go in the Tilemap#oy= method, close to the bottom of it.

    # If layer is too far up screen, need to move it down
    if @layer_sprites[0].y <= -(MAX_PRIORITY_LAYERS * 32) * @zoom_y
      shift_amt = (($resolution.height/32.0).ceil + MAX_PRIORITY_LAYERS) * 32
      layer = @layer_sprites.shift
      layer.y += shift_amt * @zoom_y
      layer.z += shift_amt
      layer.bitmap.clear
      @layer_sprites.push(layer)
      #KK20
      width = @layer_sprites[0].bitmap.width
      num = @layer_sprites.size
      @layer_sprites[num-5].bitmap.fill_rect(0,128,width,32,Color.new(0,0,0,0))
      @layer_sprites[num-4].bitmap.fill_rect(0,96,width,32,Color.new(0,0,0,0))
      @layer_sprites[num-3].bitmap.fill_rect(0,64,width,32,Color.new(0,0,0,0))
      @layer_sprites[num-2].bitmap.fill_rect(0,32,width,32,Color.new(0,0,0,0))
      @layer_sprites[num-1].bitmap.fill_rect(0,0,width,32,Color.new(0,0,0,0))
    end
    # If layer is too far down screen, need to move it up
    if @layer_sprites[-1].y > (($resolution.height/32.0).ceil * 32) * @zoom_y
      shift_amt = (($resolution.height/32.0).ceil + MAX_PRIORITY_LAYERS) * -32
      layer = @layer_sprites.pop
      layer.y += shift_amt * @zoom_y
      layer.z += shift_amt
      layer.bitmap.clear
      @layer_sprites.unshift(layer)
      #KK20
      width = @layer_sprites[0].bitmap.width
      @layer_sprites[0].bitmap.fill_rect(0,128,width,32,Color.new(0,0,0,0))
      @layer_sprites[1].bitmap.fill_rect(0,96,width,32,Color.new(0,0,0,0))
      @layer_sprites[2].bitmap.fill_rect(0,64,width,32,Color.new(0,0,0,0))
      @layer_sprites[3].bitmap.fill_rect(0,32,width,32,Color.new(0,0,0,0))
      @layer_sprites[4].bitmap.fill_rect(0,0,width,32,Color.new(0,0,0,0))
    end

I probably should get back into fixing up this script again...
Maybe after I'm done with Zexion's camera request.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 07, 2016, 01:12:54 pm
I'm kinda working on Beyond Epic mode in CP. xD
I tried XPA to boost the performance, but I was having problems with the windowskin converter (and found that Window#opacity=0 doesn't hide that waiting arrow in messages, RGSS3 bug probably). When I swithed back to XP, I noticed this bug since I decided to keep this script.

EDIT: Ok, adding that part below #KK20 seemed to fix it. Is there an equivalent for Tilemap#ox= needed? I can see some code that should be doing the same thing, but I'd rather ask.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 07, 2016, 02:30:46 pm
I believe there shouldn't be a need for ox=.

The reason why it occurs in oy= is because of the tiles that have priority. I made these tiles be drawn on SCREN_WIDTH x 160 sized-sprites. The way the DLL works is that it draws all the tiles in a row as it comes into the player's view. Because of that, I forgot to dispose of the row of tiles and it just blts the same tiles over the pre-existing ones.

For ox=, it's mainly just shifting the bitmap bytes left or right and clears the appropriate column before drawing that column with the new tiles. Hopefully that all made sense.

(I'll also have to look at that Window#opacity when I have the time. There is a script that I found and used in Advance Wars Engine that rewrites windows using sprites--could probably try checking that out.)
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 07, 2016, 03:16:33 pm
Yeah, it makes sense, I know what you are talking about. xD

About that window problem, I encountered it in a custom Window class that uses that waiting cursor (similar to Window_Message), but I used only self.opacity and no self.visible to show/hide it. It's visible all the time. And while it's visible, that waiting cursor at the bottom is always visible. It seems that it ignores self.opacity in the Window class in RGSS3 so I'm pretty sure it's an RGSS3 bug.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 07, 2016, 03:26:34 pm
Oh wait a minute, it just occurred to me. I think there's a separate method for that. Did you look in the RMVXA help file? Of course I'm at work so I have no means to look myself.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 07, 2016, 06:13:26 pm
There is? Aw man. ._. Seems kinda pointless to have it separate. No, I didn't look it up.
Regardless, the cursor rendering didn't work well either in a few specific windows with horizontally aligned menu items.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 08, 2016, 02:00:58 am
ayyy, I was right:
arrows_visible (RGSS3)
The visibility of scrolling arrows. If TRUE, the arrows are visible. The default is TRUE.

But le sad face. No more XPA :[

EDIT: Finally found it: http://forum.chaos-project.com/index.php/topic,14219.msg185568.html#msg185568
Not sure if this is what you mentioned about the cursor not aligning. This addresses the issue where, if you wish to view more contents of your window and want to scroll, the cursor would just happen to get stuck where it's at. Then wonky shit happens:
Spoiler: ShowHide

(http://puu.sh/mnP02/40558afba4.gif)

I guess RGSS3 doesn't like the use of self.ox/oy anymore, so those have to be removed.

But the WindowPadding and WindowSkin scripts seem to do their job for me. Are your windows just super unique? xP
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 08, 2016, 03:54:38 am
WindowPadding works fine. WindowSkin required me to remove some code in order to work. I only left the bare minimum.
Yeah, it's possible that ox and oy are causing the problem. It does manifest in a different way in my case, but something's definitely off. I'll try to remove ox and oy and see what happens.

EDIT: Nope, it breaks everything so I put ox and oy back in.
This is what happens usually:

the one instance where it's correct: ShowHide
(http://imgur.com/rDl3e68.png)

when pressing left once: ShowHide
(http://imgur.com/F8Wgrx5.png)

when pressing right once: ShowHide
(http://imgur.com/CiQCuhU.png)


This window is implemented by moving it left right as well as offsetting the cursor coordinate. Here's the code if you wanna check it out.

Spoiler: ShowHide
class Window_Horizontal < Window_Base
 
  attr_reader :commands
 
  def initialize(w, commands)
    super(0, 0, 3 * w + 32, 64)
    @item_max = commands.size
    @commands = commands
    if @item_max > 0
      self.contents = Bitmap.new((@item_max + 4) * w, height - 32)
    else
      self.contents = Bitmap.new(32, height - 32)
    end
    @dir = 0
    self.contents.font.name, self.contents.font.size = 'Brush Script', 26
    self.opacity = self.index = 0
    refresh
  end
 
  def refresh
    self.contents.clear
    (0...@item_max+4).each {|i| draw_item(i, (i + @item_max - 2) % @item_max)}
  end
 
  def get_command
    return @commands[(@index + @item_max) % @item_max]
  end
 
  def draw_item(i, index, color = nil)
    rect = Rect.new((self.width - 32)/3 * i, 0, (self.width - 32)/3, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    if color.is_a?(Color)
      self.contents.font.color = color
    else
      self.contents.font.color = case @commands[index]
      when 'And again!' then text_color(3)
      when 'Warrior' then text_color(6)
      when 'Exerion' then text_color(2)
      when 'Beyond Epic' then text_color(11)
      when 'Controls' then text_color(9)
      when 'Credits' then text_color(10)
      else
        normal_color
      end
    end
    self.contents.draw_text_outline(rect, @commands[index], 1)
  end
 
  def disable_item(index)
    draw_item((index + 2) % @item_max, index, disabled_color)
    draw_item((index + 2) % @item_max + @item_max, index, disabled_color)
    draw_item((index + 2) % @item_max + @item_max*2, index, disabled_color)
  end
 
  def size
    return @commands.size
  end
 
  def update
    super
    if moving?
      case @dir.abs
      when 1 then self.ox -= 5 * @dir.sgn
      when 2 then self.ox -= 10 * @dir.sgn
      when 3 then self.ox -= 20 * @dir.sgn
      when 4 then self.ox -= 45 * @dir.sgn
      when 5 then self.ox -= 45 * @dir.sgn
      when 6 then self.ox -= 20 * @dir.sgn
      when 7 then self.ox -= 10 * @dir.sgn
      when 8 then self.ox -= 5 * @dir.sgn
      end
      @dir -= @dir.sgn
    end
    if !moving? && self.active && @item_max > 0
      if Input.repeat?($controls.right)
        $game_system.se_play($data_system.cursor_se)
        @index = @index % @item_max + 1
        if self.ox == (@item_max + 1)* (self.width - 32)/3
          self.ox -= @item_max * (self.width - 32)/3
          @index = 1
        end
        @dir = -8
      elsif Input.repeat?($controls.left)
        $game_system.se_play($data_system.cursor_se)
        @index = (@index + @item_max - 2) % @item_max + 1
        if self.ox == (self.width - 32)/3
          self.ox += @item_max * (self.width - 32)/3
          @index = @item_max - 1
        end
        @dir = 8
      end
    end
    update_cursor_rect
  end
 
  def moving?
    return (@dir != 0)
  end
     
  def index=(index)
    @index = index
    self.ox = (index + 1) * (self.width - 32)/3
    update_help if self.active && @help_window != nil
    update_cursor_rect
  end
 
  def update_cursor_rect
    self.cursor_rect.set((self.width - 32)/3, 0, (self.width - 32)/3, 32)
  end
 
end
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 09, 2016, 02:05:20 am

  def update_cursor_rect
    self.cursor_rect.set(self.ox + 160, 0, (self.width - 32)/3, 32)
  end

:P

Also, for the whole "opacity = 0 makes the scroll arrows disappear", it doesn't work in vanilla XP. I just tried making a new project, gave player all the items, set Window_Item opacity to zero in initialize, and...arrow:
(http://puu.sh/mp0cn/d07b9f19be.png)
So I think that's something unique to your window modification script only.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 09, 2016, 04:39:03 am
Not scroll arrows. The waiting arrow.

As for that code, does this mean that I have to change all update_cursor_rect implementations?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 09, 2016, 05:01:29 am
Oh, I guess I was under the impression that the scrolling arrows were being used instead or something. In that case, I don't understand why you don't use the Window attribute:
pause
The pause graphic's visibility. This is a symbol that appears in the message window when waiting for the player to press a button. If TRUE, the graphic is visible. The default is FALSE.

The cursor rect does handle much differently now. Rather than being a separate entity, (like another sprite) it's almost like it's being drawn in the window contents itself. If the cursor behaves like a normal window_selectable/command, just do what Drago did in the link I posted earlier (removing self.ox/oy from the equation). If it's more strict, like your horizontal window, you'll have to implement self.ox/oy into the equation.

I've never really looked hard into that problem before, so I'm not sure how feasible a "fix-all" solution is.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 09, 2016, 05:06:29 am
Aha, I understand now what you're trying to tell me. Alright, I'll check it out. I added a $XPA variable in my code so I can easily switch back and forth if XPA causes too many bugs or something.

I also remember that I had some weird freezing when entering certain maps in my game when using XPA, but I have to look into that first.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 09, 2016, 05:34:12 am
Alright, I think I found the window cursor fix. Granted, you need to add Selwyn's Window Rewrite script as well as remove the WindowSkin fix. Also, you'll now get an error for the padding fix. But I took liberty upon myself to just provide a one script fix-all (I think):

#==============================================================================
# ? Window - Hidden RGSS Class - XPA Compatibility Version
#------------------------------------------------------------------------------
# ?by Selwyn
# Edit by KK20
#==============================================================================

#==============================================================================
# ? 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
end

#==============================================================================
# ? SG::Skin
#==============================================================================

class Skin
  #--------------------------------------------------------------------------
  # ? instances settings
  #--------------------------------------------------------------------------
  attr_reader   :margin
  attr_accessor :bitmap
  #--------------------------------------------------------------------------
  # ? initialize
  #--------------------------------------------------------------------------
  def initialize
    @bitmap = nil
    @values = {}
    @values['bg'] = Rect.new(0, 0, 128, 128)
    @values['pause0'] = Rect.new(160, 64, 16, 16)
    @values['pause1'] = Rect.new(176, 64, 16, 16)
    @values['pause2'] = Rect.new(160, 80, 16, 16)
    @values['pause3'] = Rect.new(176, 80, 16, 16)
    @values['arrow_up'] = Rect.new(152, 16, 16, 8)
    @values['arrow_down'] = Rect.new(152, 40, 16, 8)
    @values['arrow_left'] = Rect.new(144, 24, 8, 16)
    @values['arrow_right'] = Rect.new(168, 24, 8, 16)
    self.margin = 16
  end
  #--------------------------------------------------------------------------
  # ? width
  #--------------------------------------------------------------------------
  def margin=(width)
    @margin = width
    set_values
  end
  #--------------------------------------------------------------------------
  # ? set_values
  #--------------------------------------------------------------------------
  def set_values
    w = @margin
    @values['ul_corner'] = Rect.new(128, 0, w, w)
    @values['ur_corner'] = Rect.new(192-w, 0, w, w)
    @values['dl_corner'] = Rect.new(128, 64-w, w, w)
    @values['dr_corner'] = Rect.new(192-w, 64-w, w, w)
    @values['up'] = Rect.new(128+w, 0, 64-2*w, w)
    @values['down'] = Rect.new(128+w, 64-w, 64-2*w, w)
    @values['left'] = Rect.new(128, w, w, 64-2*w)
    @values['right'] = Rect.new(192-w, w, w, 64-2*w)
  end
  #--------------------------------------------------------------------------
  # ? []
  #--------------------------------------------------------------------------
  def [](value)
    return @values[value]
  end
end


#==============================================================================
# ? SG::Cursor_Rect
#==============================================================================

class Cursor_Rect < ::Sprite
  #--------------------------------------------------------------------------
  # ? instances settings
  #--------------------------------------------------------------------------
  attr_reader   :height, :width, :skin, :margin
  #--------------------------------------------------------------------------
  # ? initialize
  #--------------------------------------------------------------------------
  def initialize(viewport, parent_window)
    super(viewport)
    @window = parent_window
    @width = 0
    @height = 0
    @skin = nil
    @margin = 0
    @rect = {}
    @rect['cursor_up'] = Rect.new(129, 64, 30, 1)
    @rect['cursor_down'] = Rect.new(129, 95, 30, 1)
    @rect['cursor_left'] = Rect.new(128, 65, 1, 30)
    @rect['cursor_right'] = Rect.new(159, 65, 1, 30)
    @rect['upleft'] = Rect.new(128, 64, 1, 1)
    @rect['upright'] = Rect.new(159, 64, 1, 1)
    @rect['downleft'] = Rect.new(128, 95, 1, 1)
    @rect['downright'] = Rect.new(159, 95, 1, 1)
    @rect['bg'] = Rect.new(129, 65, 30, 30)
  end
  #--------------------------------------------------------------------------
  # ? margin=
  #--------------------------------------------------------------------------
  def margin=(margin)
    @margin = margin
    set(x, y, width, height)
  end
  #--------------------------------------------------------------------------
  # ? skin=
  #--------------------------------------------------------------------------
  def skin=(skin)
    @skin = skin
    draw_rect
  end
  #--------------------------------------------------------------------------
  # ? 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
  #--------------------------------------------------------------------------
  # ? 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
  #--------------------------------------------------------------------------
  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
  #--------------------------------------------------------------------------
  # ? empty
  #--------------------------------------------------------------------------
  def empty
    self.x = 0
    self.y = 0
    self.width = 0
    self.height = 0
  end
  #--------------------------------------------------------------------------
  # ? draw_rect
  #--------------------------------------------------------------------------
  def draw_rect
    return if @skin == nil
    if @width > 0 and @height > 0
      self.bitmap = Bitmap.new(@width, @height)
      rect = Rect.new(1, 1, @width - 2, @height - 2)
      self.bitmap.stretch_blt(rect, @skin, @rect['bg'])
      self.bitmap.blt(0, 0, @skin, @rect['upleft'])
      self.bitmap.blt(@width-1, 0, @skin, @rect['upright'])
      self.bitmap.blt(0, @height-1, @skin, @rect['downright'])
      self.bitmap.blt(@width-1, @height-1, @skin, @rect['downleft'])
      rect = Rect.new(1, 0, @width - 2, 1)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_up'])
      rect = Rect.new(0, 1, 1, @height - 2)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_left'])
      rect = Rect.new(1, @height-1, @width - 2, 1)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_down'])
      rect = Rect.new(@width - 1, 1, 1, @height - 2)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_right'])
    end
  end
end

#==============================================================================
# ? SG::Window
#------------------------------------------------------------------------------
# ?
#==============================================================================

class Window
  #--------------------------------------------------------------------------
  # ? set instances variables
  #--------------------------------------------------------------------------
  attr_reader(:x, :y, :z, :width, :height, :ox, :oy, :opacity, :back_opacity,
              :stretch, :contents_opacity, :visible, :pause)
  attr_accessor :active
  #--------------------------------------------------------------------------
  # ? initialize
  #--------------------------------------------------------------------------
  def initialize()
    @skin = Skin.new
    @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
    @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[i].bitmap = Bitmap.new(16, 16)
      @arrows[i].visible = false
    end
    @cursor_rect = Cursor_Rect.new(@cr_vport, self)
    @cursor_rect.margin = @skin.margin
    @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
  #--------------------------------------------------------------------------
  # ? contents=
  #--------------------------------------------------------------------------
  def contents=(bmp)
    @window.bitmap = bmp
    if bmp != nil
      if bmp.width > @viewport.rect.width
         bmp.height > @viewport.rect.height
        draw_arrows
      end
    end
  end
  #--------------------------------------------------------------------------
  # ? 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
    @pause_s.src_rect = @skin["pause#{(Graphics.frame_count / 8) % 4}"]
    @pause_s.update
    update_visible
    update_arrows
    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
  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
  #--------------------------------------------------------------------------
  # ? pause=
  #--------------------------------------------------------------------------
  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
  #--------------------------------------------------------------------------
  # ? visible=
  #--------------------------------------------------------------------------
  def visible=(visible)
    @visible = visible
    update_visible
    update_arrows
  end
  #--------------------------------------------------------------------------
  # ? x=
  #--------------------------------------------------------------------------
  def x=(x)
    @x = x
    @bg.x = x + 2
    @frame.x = x
    @viewport.rect.x = x + @skin.margin
    @cr_vport.rect.x = x
    @pause_s.x = x + (@width / 2) - 8
    set_arrows
  end
  #--------------------------------------------------------------------------
  # ? y=
  #--------------------------------------------------------------------------
  def y=(y)
    @y = y
    @bg.y = y + 2
    @frame.y = y
    @viewport.rect.y = y + @skin.margin
    @cr_vport.rect.y = y
    @pause_s.y = y + @height - @skin.margin
    set_arrows
  end
  #--------------------------------------------------------------------------
  # ? z=
  #--------------------------------------------------------------------------
  def z=(z)
    @z = z
    @bg.z = z
    @frame.z = z + 1
    @cr_vport.z = z + 2
    @viewport.z = z + 3
    @pause_s.z = z + 4
  end
  #--------------------------------------------------------------------------
  # ? ox=
  #--------------------------------------------------------------------------
  def ox=(ox)
    return if @ox == ox
    @ox = ox
    @viewport.ox = ox
    update_arrows
  end
  #--------------------------------------------------------------------------
  # ? oy=
  #--------------------------------------------------------------------------
  def oy=(oy)
    return if @oy == oy
    @oy = oy
    @viewport.oy = oy
    update_arrows
  end
  #--------------------------------------------------------------------------
  # ? width=
  #--------------------------------------------------------------------------
  def width=(width)
    @width = width
    @viewport.rect.width = width - @skin.margin * 2
    @cr_vport.rect.width = width
    if @width > 0 and @height > 0
      @frame.bitmap = Bitmap.new(@width, @height)
      @bg.bitmap = Bitmap.new(@width - 4, @height - 4)
      draw_window
    end
    self.x = @x
    self.y = @y
  end
  #--------------------------------------------------------------------------
  # ? height=
  #--------------------------------------------------------------------------
  def height=(height)
    @height = height
    @viewport.rect.height = height - @skin.margin * 2
    @cr_vport.rect.height = height
    if @height > 0 and @width > 0
      @frame.bitmap = Bitmap.new(@width, @height)
      @bg.bitmap = Bitmap.new(@width - 4, @height - 4)
      draw_window
    end
    self.x = @x
    self.y = @y
  end
  #--------------------------------------------------------------------------
  # ? 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
  #--------------------------------------------------------------------------
  # ? back_opacity=
  #--------------------------------------------------------------------------
  def back_opacity=(opacity)
    value = [[opacity, 255].min, 0].max
    @back_opacity = value
    @bg.opacity = value
  end
  #--------------------------------------------------------------------------
  # ? contents_opacity=
  #--------------------------------------------------------------------------
  def contents_opacity=(opacity)
    value = [[opacity, 255].min, 0].max
    @contents_opacity = value
    @window.opacity = value
  end
  #--------------------------------------------------------------------------
  # ? cursor_rect
  #--------------------------------------------------------------------------
  def cursor_rect
    return @cursor_rect
  end
  #--------------------------------------------------------------------------
  # ? 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
  #--------------------------------------------------------------------------
  # ? windowskin
  #--------------------------------------------------------------------------
  def windowskin
    return @skin.bitmap
  end
  #--------------------------------------------------------------------------
  # ? windowskin=
  #--------------------------------------------------------------------------
  def windowskin=(windowskin)
    return if windowskin == nil
    if @skin.bitmap != windowskin
      @pause_s.bitmap = windowskin
      @pause_s.src_rect = @skin['pause0']
      @skin.bitmap = windowskin
      @cursor_rect.skin = windowskin
      draw_window
      draw_arrows
    end
  end
  #--------------------------------------------------------------------------
  # ? padding=
  #--------------------------------------------------------------------------
  alias set_padding padding=
  def padding=(pad)
    return if self.disposed?
    set_padding(pad)
    self.margin = pad
  end
  #--------------------------------------------------------------------------
  # ? margin=
  #--------------------------------------------------------------------------
  def margin=(margin)
    if @skin.margin != margin
      @skin.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
  #--------------------------------------------------------------------------
  # ? stretch=
  #--------------------------------------------------------------------------
  def stretch=(bool)
    if @stretch != bool
      @stretch = bool
      draw_window
    end
  end
  #--------------------------------------------------------------------------
  # ? set_arrows
  #--------------------------------------------------------------------------
  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_arrows
  #--------------------------------------------------------------------------
  def draw_arrows
    return if @skin.bitmap == nil
    @arrows[0].bitmap.blt(0, 0, @skin.bitmap, @skin['arrow_up'])
    @arrows[1].bitmap.blt(0, 0, @skin.bitmap, @skin['arrow_left'])
    @arrows[2].bitmap.blt(0, 0, @skin.bitmap, @skin['arrow_right'])
    @arrows[3].bitmap.blt(0, 0, @skin.bitmap, @skin['arrow_down'])
    update_arrows
  end
  #--------------------------------------------------------------------------
  # ? draw_window
  #--------------------------------------------------------------------------
  def draw_window
    return if @skin.bitmap == nil
    return if @width == 0 or @height == 0
    m = @skin.margin
    if @frame.bitmap.nil?
      @frame.bitmap = Bitmap.new(@width, @height)
      @bg.bitmap = Bitmap.new(@width - 4, @height - 4)
    end
    @frame.bitmap.clear
    @bg.bitmap.clear
    if @stretch
      dest_rect = Rect.new(0, 0, @width-4, @height-4)
      @bg.bitmap.stretch_blt(dest_rect, @skin.bitmap, @skin['bg'])
    else
      bgw = Integer((@width-4) / 128) + 1
      bgh = Integer((@height-4) / 128) + 1
      for x in 0..bgw
        for y in 0..bgh
          @bg.bitmap.blt(x * 128, y * 128, @skin.bitmap, @skin['bg'])
        end
      end
    end
    bx = Integer((@width - m*2) / @skin['up'].width) + 1
    by = Integer((@height - m*2) / @skin['left'].height) + 1
    for x in 0..bx
      w = @skin['up'].width
      @frame.bitmap.blt(x * w + m, 0, @skin.bitmap, @skin['up'])
      @frame.bitmap.blt(x * w + m, @height - m, @skin.bitmap, @skin['down'])
    end
    for y in 0..by
      h = @skin['left'].height
      @frame.bitmap.blt(0, y * h + m, @skin.bitmap, @skin['left'])
      @frame.bitmap.blt(@width - m, y * h + m, @skin.bitmap, @skin['right'])
    end
    @frame.bitmap.erase(@width - m, 0, m, m)
    @frame.bitmap.erase(0, @height - m, m, m)
    @frame.bitmap.erase(@width - m, @height - m, m, m)
    @frame.bitmap.blt(0, 0, @skin.bitmap, @skin['ul_corner'])
    @frame.bitmap.blt(@width - m, 0, @skin.bitmap, @skin['ur_corner'])
    @frame.bitmap.blt(0, @height - m, @skin.bitmap, @skin['dl_corner'])
    @frame.bitmap.blt(@width - m, @height - m, @skin.bitmap, @skin['dr_corner'])
  end
end

Now you can remove the windowskin and window padding script fixes and replace them entirely with this Window's Rewrite. I'll have to make note of this.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 09, 2016, 06:16:30 am
Hm, is replacing the Window class not kinda inefficient?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 09, 2016, 02:46:24 pm
Can't be any more inefficient than replacing the Tilemap class. :P

The rewrite is nice since it modifies the windows to behave like the XP windows rather than VXA windows; less headaches for users making sure if their windows are not buggy. Plus, we now have more access to the windows themselves--change the wait arrows, move things around, make different window cursors, etc.

I could do a stress test and see how many windows start to lag the game, though I would highly doubt the two would be much different, if at all.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 14, 2016, 01:29:21 pm
I tried it any within 15 seconds I came across 3 problems.

1. Some text won't show up.
2. The stretching of the cursor has some serious artifacts. I'm pretty sure it's using nearest neighbor rather linear interpolation. Might be VXA's .exe though.
3. It works on the title screen and save-loading screen, but crashes on @frame being nil as soon as the map should load.

*sigh* I'm seriously thinking about just writing my own Window class. I can probably easily scavenge my C++ implementation from ARC. It would probably be faster that trying to debug this. Not that the code is bad. It's decent. It's just that it doesn't work fully which aggravates me.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 14, 2016, 03:51:04 pm
Your windows must be super unique and perform functions the Window class never really expected. I mean I've been using this script for years in Advance Wars Engine and have never had a single issue with it, both in XP and XPA.

Maybe Zexion and I can research it some more, but there really isn't much promise without knowing what are triggering these unique errors.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 14, 2016, 04:19:19 pm
IDK, but I'm 99% sure that not all of the default Window class' functionality have been implemented in that script. Maybe I'm using an initialize call with a viewport argument, because I don't see it supported in this script.

Also, I just noticed panorama doesn't work in XPA. ._.

EDIT: Ah, fuck, I found it. I'm using a @frame variable myself somewhere in a Window class of my own.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 14, 2016, 04:28:15 pm
I don't think Windows even have viewports. Looking at Window_Base, there's no reference to a viewport in there either.
Stretching of the cursor appears to be using Bitmap#stretch_blt, which I believe is not that great of a method if I can recall. It doesn't look like it's even used in the default scripts either.
I'll have to look at the outline thing when I get the chance--never really played too much with that one.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 14, 2016, 04:31:29 pm
Definitely more naming conflicts. Though, I'm still having trouble with some of the font rendering.

I'm pretty sure myself that Window doesn't support viewport. But it's been so long since the last time I touched XP that I can't remember some things accurately.

I figured the outline thing out. I had to use out_color for it to work. But it's weird. It works in XP and in my new Windows class, but it won't work in XPA when I use that script. ._. Man, so much stuff.

EDIT: stretch_blt should be the right way to go. The problem is that he didn't do it right. He blitted the whole thing at once which is incorrect. The borders of the cursor image are blit separately and in a thinner manner before blitting the center image.

EDIT: These are the correct formulas.

		int w = hmax(this->cursorRect->width - 4, 0);
int h = hmax(this->cursorRect->height - 4, 0);
this->cursorBitmap->_renderToTexture(0, 0, 2, 2, 0, 0, this->windowskinCursor);
this->cursorBitmap->_renderToTexture(30, 0, 2, 2, w + 2, 0, this->windowskinCursor);
this->cursorBitmap->_renderToTexture(0, 30, 2, 2, 0, h + 2, this->windowskinCursor);
this->cursorBitmap->_renderToTexture(30, 30, 2, 2, w + 2, h + 2, this->windowskinCursor);
if (w > 0)
{
this->cursorBitmap->_renderToTexture(2, 0, 28, 2, 2, 0, w, 2, this->windowskinCursor);
this->cursorBitmap->_renderToTexture(2, 30, 28, 2, 2, h + 2, w, 2, this->windowskinCursor);
}
if (h > 0)
{
this->cursorBitmap->_renderToTexture(0, 2, 2, 28, 0, 2, 2, h, this->windowskinCursor);
this->cursorBitmap->_renderToTexture(30, 2, 2, 28, w + 2, 2, 2, h, this->windowskinCursor);
}
if (w > 0 && h > 0)
{
this->cursorBitmap->_renderToTexture(2, 2, 28, 28, 2, 2, w, h, this->windowskinCursor);
}
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 14, 2016, 04:40:34 pm
From the script:

  def draw_rect
    return if @skin == nil
    if @width > 0 and @height > 0
      self.bitmap = Bitmap.new(@width, @height)
      rect = Rect.new(1, 1, @width - 2, @height - 2)
      self.bitmap.stretch_blt(rect, @skin, @rect['bg'])
      self.bitmap.blt(0, 0, @skin, @rect['upleft'])
      self.bitmap.blt(@width-1, 0, @skin, @rect['upright'])
      self.bitmap.blt(0, @height-1, @skin, @rect['downright'])
      self.bitmap.blt(@width-1, @height-1, @skin, @rect['downleft'])
      rect = Rect.new(1, 0, @width - 2, 1)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_up'])
      rect = Rect.new(0, 1, 1, @height - 2)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_left'])
      rect = Rect.new(1, @height-1, @width - 2, 1)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_down'])
      rect = Rect.new(@width - 1, 1, 1, @height - 2)
      self.bitmap.stretch_blt(rect, @skin, @rect['cursor_right'])
    end
  end

Yeah I can see by what you mean. Just blits a 1 pixel border and then stretches the background.

And yeah, the Plane support has been know for a couple years already. Did I not put that in the XPA Tilemap?
Oh I did. And I see the edit :P
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 14, 2016, 04:46:21 pm
Yeah, remember that I disabled some code in the Tilemap? I disabled Plane. It works now after I re-enabled it.

EDIT: About the text: I'm not sure why it doesn't work, but that text won't even display if I just reroute the outline drawing to the normal drawing. But it's not just that. I have a simple window that uses normal text draw calls, but it also doesn't display anything. IDK.

Also, I'm still getting hard crashes in XPA. :/ This simple event caused one:

Spoiler: ShowHide
(http://imgur.com/SRd4dgu.png)


Not sure what's happening. I could assume that my screen transition caused it, but that doesn't explain why it crashed on certain maps that don't have anything to do with it. Also, normal screenshots work just fine so I don't think that the transition that uses a screenshot causes it.

EDIT: I think I'll just keep XP with your Tilemap. I might finish my own Window system for the lulz, but I don't think XPA is an option for me. :/
Title: Re: [XP] XP Ace Tilemap
Post by: syldocaine on January 16, 2016, 10:00:06 am
If you have trouble with XPA I would recommend you this script: http://forum.chaos-project.com/index.php/topic,12291.0.html

together with this line in Main:

Graphics.frame_rate = 60


Just activate the "Reduce Screen Flickering" option and you will get a similar 60 FPS performance even without XPA.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 16, 2016, 01:42:06 pm
I actually wrote my own anti-lag system a long, long time ago, lol! http://forum.chaos-project.com/index.php/topic,104.0.html
I know the thing with the frame rate. I actually use it to speed up the game while debugging.

As I said, I'm getting a hard crash with XPA. I mean the one where the Windows dialog pops up and says "The application has stopped responding." I would just take too long to figure out what's wrong. I'm actually expecting that several things are causing this since it crashes on certain events, but also on map entry on certain maps.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 16, 2016, 06:09:10 pm
@syldocaine
It's not just frame rate that you get from RGSS3. It's really the graphic processing and upgraded Ruby that I get the most out of. Regardless of the FPS on XP, there's way too much screen tearing.
Also, anti-lag just addresses the events on the map. In my Advance Wars Engine, I don't use events so I don't benefit from it. Yet I saw a massive improvement switching to XPA.

@Blizzard
The map entry error sounds like an invalid tile ID. I used this to help someone else out with my Tilemap:

class Game_Map
  alias check_invalid_tiles setup
  def setup(map_id)
    check_invalid_tiles(map_id)
   
    bitmap = RPG::Cache.tileset(@tileset_name)
    maxtileid = (bitmap.width / 32) * (bitmap.height / 32) - 1
   
    for x in 0...@map.data.xsize
      for y in 0...@map.data.ysize
        for z in 0...@map.data.zsize
          if @map.data[x,y,z] - 384 > maxtileid
            msgbox_p("[#{x},#{y},#{z}] = " + @map.data[x,y,z].to_s)
          end
        end
      end
    end
  end
 
end

If a message box pops up, then that's my fault for not writing better code.

The event issue, though, is something I'm not familiar with.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 16, 2016, 06:34:40 pm
I'll try it out at some point and see if it helps. Though, as I said, it works fine in XP and only crashes in XPA.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 31, 2016, 02:03:45 pm
I tried it out, but it didn't help. I'm actually pretty sure it's not your script since the crash also happens if I try somebody else's Tilemap rewrite.
I tried switching the Window class for mine and if I use mine, it crashes right after loading instead of when I try to enter battle.
I also tried not using the screenshot.dll, but that didn't really help either.

I experimented a bit more and I'm pretty sure it's some sort of memory corruption. When I try to enter a battle, the crash can happen at two separate moments. One is somewhere still on top of Scene_Battle#main. And the other is somewhere during my own Bitmap#desaturate method (implemented using get_pixel and set_pixel). The memory corruption scenario makes a lot of sense since Bitmaps methods probably manipulate the most memory and my own Window class implementation has a stretch_blt method that does linear interpolation filtering which means a lot more set_pixel calls. I tried quickly overriding set_pixel and calling fill_rect in its place, but it didn't help so my memory corruption suspicion makes more sense than set_pixel being broken internally. I also tried disabling all rendering methods in Bitmap, but that didn't help either.
Now the big question is what is causing the memory corruption and where. It might not be Bitmap, but it's possible that some internal class has problems with memory management when combined with the garbage collector. I'll probably never figure it out so I think I'll give up on XPA for good. I just have way too much custom shit to be able to find the culprit just like that after some more testing.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 31, 2016, 02:16:55 pm
Do all of these classes/methods exist in the latest game download? I could easily take a look at all of this for you.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 31, 2016, 02:39:12 pm
I can give you CP unencrypted if you want.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 31, 2016, 02:43:04 pm
Probably would be better than sitting here trying to get everything in an editable state.
I'll take that offer. :P
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 31, 2016, 03:12:50 pm
Sent. Have fun. xD
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on February 16, 2016, 02:02:00 pm
Hello!

So, how is the hard crash issue going? I'm here because my game also gives me a hard crash. I'm using XP Ace and this tilemap.

Interestingly enough (?), it only happens in Windows 7/10. In my other PC (it has Windows XP), it doesn't happen. It seems to have something to do with map size or something, because the bigger the map is, the chance of getting a crash is higher.
Also my game has an autosave function every time you change map, so I get the crash, load the autosave, and go through the map with no problems.

The other interesting issue is that games run way faster on that Windows XP machine, even considering it has less RAM and an older CPU. But this is something that happens to me with vanilla VXAce so never mind.

Salut!
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 16, 2016, 02:08:47 pm
I'm pretty sure it's not related to the tilemap if it works on other OS's. I don't have a XP computer to test on unfortunately and I'm not sure if a VM counts.

Can you upload a demo?
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 16, 2016, 02:35:06 pm
Definitely check for the 24-bit PNG thing.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 16, 2016, 02:41:33 pm
If he claims the maps crash when changing maps, but load up from saves just fine, then I suspect disposed Viewports.
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on February 16, 2016, 10:04:54 pm
I have a demo out. It's about 60Mb in size (the host doesn't need any registration to download).
http://gamejolt.com/games/drekiroekr-dusk-of-the-dragon/13780

And here is a savegame. Best-case scenario, just going into the town will crash the game. If that doesn't make it, just go up/north. And if it still has not crashed, well, I'll be amazed.
https://dl.dropboxusercontent.com/u/13006190/Slot1.rxdata

Most of the time are outdoor maps which crash. There is some weather and other sheet going there so there is a difference between out and indoors.

EDIT: Whoops, yeah, in the Slots folder. Part of my game's folder names are inspired in the good old No$GB directory names. Slot for saves, Snap for screens, if there was a need I would have Battery for the other saved stuff xD.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 17, 2016, 02:25:57 am
Stupid me not realizing I had to put the save file in the Slots folder. Anyways, after doing that and loading the game, I was able to reach the "End of the Demo" message which was the map all the way north as you said. Did this on my Windows 7 x64. So...can't reproduce.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 17, 2016, 02:28:30 am
Yup, that sounds like the viewports thing. Different RAM loads should cause different behaviors when deciding which memory address to allocate.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 17, 2016, 02:36:32 am
Added your script Blizz and made this little message box appear to tell us how many sprites failed to be disposed.

class Viewport
 
  alias dispose_xpa_sprite_fix dispose
  def dispose
    if @_sprites != nil
      msgbox_p @_sprites.size
      @_sprites.clone.each {|sprite| sprite.dispose if !sprite.disposed? }
      @_sprites = []
    end
    dispose_xpa_sprite_fix
  end

Loading from the save and going into town, all sizes were 0.
Going to the next map up north revealed one viewport having 25 undisposed sprites.

So it's looking probable.

EDIT: Sprites not being disposed are the Sprite_Bloodsplatter's, which are just the footprints in the snow.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 05, 2016, 03:03:41 pm
Yo, I have a small feature request if you're up for it. It would be nice if there were black borders on the map edges with the highest Z-order, because tile chunks are kinda visible when using the shake screen animation.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 05, 2016, 05:03:12 pm
I know I spent time working on that because I do remember seeing that happen before. Unless you're doing something that I never tested; not sure what you mean by "map edges with the highest Z-order".

Still working on fixing the float-value changes to the Tilemap's ox/oy, which I think I have down, but now the screen shake is screwed up again.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 05, 2016, 05:46:00 pm
Here's a screenshot. Look at the bottom.

Spoiler: ShowHide
(http://imgur.com/BTYNBBv.png)


I meant that adding a additional sprites with a high z-order at the edges would solve this problem.

EDIT: Here's one at the top.

Spoiler: ShowHide
(http://imgur.com/3fs9YHK.png)


BTW, I have a customized shaking script which shakes the map vertically as well. You will probably see the manifestation of this only at the left and right edges with the default scripts.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 05, 2016, 05:56:18 pm
Oh that explains it. I only addressed the horizontal shaking, not vertical. I'll have to think about it a bit more then.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 06, 2016, 03:25:22 am
I found two more things.

1. The first is a hard crash. o.o It seems that I can reproduce it somewhat consistently. All I have to do is go the to right border of the map and then to the upper border. When I get there and start moving down, after 2-3 tiles it crashes. The error does say that XPATilemap.dll caused the crash. You should probably check if your DLL's bitmap boundary clamping works right when you render the layer sprite's bitmap.

2. I wasn't able to reproduce this one after it happened the first time. I don't have a screenshot, but it looked like one column of autotiles was duplicated and shifted to the left by one tile. It was a water autotile and looked something like this:

/===\                  /===\
|###|                  |###|
|###|                  |###|
|###|                  |###|
|###|                  |###|
|###|                  |###|
\===/                  \===/

I came in from the right side of the map after walking a downward corridor in a previous map, but I couldn't make it happen again, no matter how many times I tried reentering the map. This is how the glitch manifested:

/===\              /=/===\
|###|              |#|###|
|###|              |#|###|
|###|              |#|###|
|###|              |#|###|
|###|              |#|###|
\===/              \=\===/

When I walked left so the water got offscreen and back, it obviously fixed itself. This was Giada Castle so shaking was turned on and this is probably related.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 06, 2016, 04:26:55 am
I'll have to take a look at the first one. Haven't heard of that one before. Hopefully it's easy to reproduce as you make it sound.

Second is probably the result of screen shaking. I did notice something though. I tried copying your modified Game_Screen from the project when I had horizontal shaking working. I disabled the vertical shaking (tremble) and ran the game only to find out that my fix suddenly didn't work anymore. I haven't looked into it yet, but it baffles me as to what is the cause.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 06, 2016, 04:44:17 am
If you still have my CP project, load a savegame, press F9, teleport to map 254 and turn on switch 004. Hold CTRL to avoid encounters while walking.

EDIT: Aaaaand I might have another one for you. xD Setting Tilemap#tileset to nil doesn't work the same way as in the original. In the original all tiles simply vanish as if it is an empty bitmap.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 07, 2016, 12:13:02 am
God I have so much work to do now DX I did contemplate about the whole changing the Tilemap graphics thing before, but I don't remember why I never did it. It should be a simple matter of setting @first_update to true again.

I think I understand the whole screen shaking problem, and it's mainly because the default algorithm of handling it is definitely NOT what I would have done. I should also mention that in your tremble you are subtracting @shake_duration by 1 twice; this was making my Tilemap problem more obvious (for some reason).

There happens to be a desync with autotiles updating and the ground layer's X coordinate. If at the left side of the map, the ground layer starts at X = 0. After shaking, it was somehow ending up at X = -32. I need to rethink my Tilemap#ox= method.

EDIT: I can achieve what I want if we change the viewport's x rather than its ox. I think Spriteset_Map and Spriteset_Battle are the only ones to use Viewport#ox= in the default scripts, and specifically only for shaking.

With default RMXP on a 20x15 map, the tilemap wraps around on both sides, which you can clearly see if you put two different tiles along the edges of the map. Same goes for the panorama. If I can draw some high z-value black rectangles when only along the map edges, then I can continue working around Tilemap#ox. Though this will affect some scripts negatively, specifically map wrap scripts.

I can really go a bunch of different ways with this.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 07, 2016, 01:53:07 am
Quote from: KK20 on March 07, 2016, 12:13:02 am
With default RMXP on a 20x15 map, the tilemap wraps around on both sides, which you can clearly see if you put two different tiles along the edges of the map. Same goes for the panorama. If I can draw some high z-value black rectangles when only along the map edges, then I can continue working around Tilemap#ox. Though this will affect some scripts negatively, specifically map wrap scripts.


Yeah, that was the solution I had in mind. You could make it an option so it doesn't mess with other scripts. I don't think the Viewport solution is a good one since it would cause the same problem, but you couldn't really turn it off like the black borders.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 07, 2016, 01:55:48 pm
Well I have an idea how to do it, but it involves reworking my DLL which I haven't looked at for well over a year now.

Main idea is to give Viewport a variable that is assigned to the Tilemap instance. Whenever the Viewport's ox/oy change, I can update the Tilemap accordingly. It'll be a while before I finish it though.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 07, 2016, 02:47:16 pm
I'm coming to San Francisco this weekend so I'm likely not going to work on CP for the next two weeks. You don't have to rush it because of me. xD
Title: Re: [XP] XP Ace Tilemap
Post by: Heretic86 on March 23, 2016, 06:12:00 am
Quote from: Blizzard on March 07, 2016, 02:47:16 pm
I'm coming to San Francisco this weekend so I'm likely not going to work on CP for the next two weeks. You don't have to rush it because of me. xD


You wont be that far from where I live then!  I'll just have to keep my eyes peeled for a black guy thats always nodding their heads (avatar) and is known to be a total Grapist (previous avatar)!  About 4 hours away...
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 23, 2016, 10:17:19 am
Aw, man, we're literally sitting in the rent-a-car, ready to get to the airport. ._.
Title: Re: [XP] XP Ace Tilemap
Post by: Heretic86 on March 23, 2016, 07:02:39 pm
Quote from: Blizzard on March 23, 2016, 10:17:19 am
Aw, man, we're literally sitting in the rent-a-car, ready to get to the airport. ._.


Have fun!  Too damn many people in SF for me...
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 23, 2016, 07:11:43 pm
He means he's going back home ._.
Just read this: http://forum.chaos-project.com/index.php/topic,15331.0.html
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 25, 2016, 03:02:05 pm
I found an inconsistency with the original implementation in RMXP. Fog's ox and oy values are not corrected with the scale. While this is the correct behavior for Sprite classes, it's not the same with the Plane class. You have to change "super(ox % @bitmap.width)" to "super((ox / self.zoom_x) % @bitmap.width)" and the same with oy and self.zoom_y.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on April 27, 2016, 02:53:27 am
Just wanna update that I have fixed the whole wrapping issue. If the map has the word [WRAP] inside its name, the map will behave similar to that of RMXP. Otherwise, a black border will be drawn instead.

It now handles float values properly along with viewport adjustments. Shaking the screen vertically will be fine now. Still seeing an issue with panoramas when the resolution is too big for the map, but that requires an edit to a helper script I'm using in conjunction with this.

All that's left are the easy things like refreshing when a bitmap changes and cleaning up.
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on April 27, 2016, 10:29:03 pm
So it works now with the old wrap/looping map scripts?

Anyway, I think I'll update my game. Howdy-ho!
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on May 03, 2016, 01:16:18 am
Quote from: Blizzard on March 06, 2016, 03:25:22 am
1. The first is a hard crash. o.o It seems that I can reproduce it somewhat consistently. All I have to do is go the to right border of the map and then to the upper border. When I get there and start moving down, after 2-3 tiles it crashes. The error does say that XPATilemap.dll caused the crash. You should probably check if your DLL's bitmap boundary clamping works right when you render the layer sprite's bitmap.

I can't seem to reproduce this in your project. I don't know if it's a specific map or any map in general.

Going to be throwing up the next version sometime this weekend. Still beta phase but closer to what I envisioned.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on May 22, 2016, 09:21:06 pm
So I know I'm like...20 days late on my promise. But it was because I was working on a new Plane rewrite, one that uses a DLL. Turns out that it's actually much better than RMXP's. Not only can it go beyond the 640x480 limit, but zooming works as intended. It's also much more efficient with smaller graphics: using a 9x1 graphic, RMXP frame rate drops to about 30 and drops to single digits when zooming out (no idea why anyone would do this but...for science); the rewrite stays at a crispy 60 (or 59, whatever, it's close enough) regardless.

I still need to test it a bit more before I can give the go ahead and release the Tilemap.

Hopefully Blizz-senpai hasn't given up on me yet :[
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on May 23, 2016, 01:06:02 am
No, I still love you. <3
I'll check this stuff out the next time I work on CP. Though, I'm mostly interested in the black border thingy. xD
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on May 23, 2016, 10:24:16 pm
Quite sweeeeeeeet ma' boy! <3. I love planes *gets run over by an airplane*.
Me wants this new plane thing. <3<3<3

And tilemap update. Oh my. Such delicacies. Life is such a sweet potato sometimes.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 07, 2016, 03:03:17 am
Posting the in-progress build of Version 0.2: DOWNLOAD (https://dl.dropboxusercontent.com/u/58874459/XPA_Tilemap_v2_test.zip)



Give it a shot and report anything weird. I advise not replacing the previous tilemap version you have with this in your main project yet.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on August 17, 2016, 01:15:13 pm
I think v0.2 finally fixed the crashes for me in the maps with screen-shake on.

I still experience a leftover glitch though.

top center: ShowHide
(http://i.imgur.com/svpVt6S.png)


I have 3 hidden events positioned there in the top center of the screen. They are normal visible events and I'm hiding them below priority-5 tiles. So I'd still need that black border I spoke of earlier. xD
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on August 17, 2016, 01:52:24 pm
Fine :P I guess I'll try the easy-way then.
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on August 17, 2016, 03:51:23 pm
With an new project I have an error line 1090.
Maybe I did something wrong ?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on August 17, 2016, 03:54:03 pm
wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ }

This line?
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on August 17, 2016, 04:01:12 pm
Yes, this line.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on August 17, 2016, 04:04:49 pm
Yeah that's only valid syntax for Ruby 1.9.2. The v2 test linked above is for XPA games only. I haven't looked much into the XP compatibility yet, despite the first post.
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on August 17, 2016, 04:08:47 pm
Ow, too bad.=(

I hope you can export the new one into XP.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on August 17, 2016, 04:14:11 pm
Why do you need this for XP anyways? There are plenty of other tilemap rewrites to use.
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on August 17, 2016, 05:02:30 pm
There are interesting things. (Zoom, fullscreen...)
Title: Re: [XP] XP Ace Tilemap
Post by: G_G on August 17, 2016, 05:06:45 pm
Quote from: kreiss on August 17, 2016, 05:02:30 pm
There are interesting things. (Zoom, fullscreen...)


At that point, try and see if the Ace engine works with your project.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on August 17, 2016, 07:22:46 pm
The zooming was done by LiTTleDRAgo in his separate version; it hasn't been put into the official version. I'm not sure if I want to either. VXA's engine allows resizing of the window along with resizing the graphics. Essentially, you can make your game resolution 320x240, make the game window 640x480, and you have a pseudo 200% zoom of your game. Or you can resize the window to the monitor's size, remove the window borders, and *boom* pseudo fullscreen.

XP's engine does not do that, so it would require more work to get it to the same level as it already is in XPA.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on December 03, 2016, 07:36:17 am
Yo, I found a compatibility issue with my encryption system and filenames. You might want to use something like this as additional safeguard.


#===============================================================================
# ** RPG::Cache
#===============================================================================

module RPG::Cache
 
  class << self
    alias :load_bitmap_tilemap_fix :load_bitmap
  end
 
  def self.load_bitmap(folder_name, filename, hue = 0)
    bitmap = self.load_bitmap_tilemap_fix(folder_name, filename, hue)
    if bitmap != nil && filename != ''
      bitmap.filename = filename
    end
    return bitmap
  end
 
  def self.autotile(filename)
    folder_name = 'Graphics/Autotiles/'
    path = folder_name + filename
    if !@cache.include?(path) || @cache[path].disposed?
      bitmap = self.load_bitmap(folder_name, filename)
      if bitmap != nil
        new_bitmap = self.format_autotiles(bitmap, filename)
        if new_bitmap != bitmap
          @cache[path].dispose
          @cache[path] = new_bitmap
          bitmap = new_bitmap
        end
      end
      return bitmap
    end
    return self.load_bitmap(folder_name, filename)
  end
 
end
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on December 03, 2016, 07:29:02 pm
Thanks, I'll take a look at it soon. Been wanting to work on this again.
Need to also change v0.2's way of handling updates to the data_table or bitmaps. Currently using Proc objects assigned to instance variables...which crashes when Marshal.dump is called when saving. Probably resort to an eval or making a ProcController class.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 27, 2017, 04:15:35 am
Version 0.3 is coming along nicely now. Here are the things I plan for it to have:

and maybe others I can't recall at the moment. Might have it done this weekend.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 05, 2017, 02:22:22 am
Version 0.3 Released~
DOWNLOAD HERE (https://dl.dropboxusercontent.com/u/58874459/XPAT_v0.3.zip)

I haven't tested this in vanilla XP yet, so I don't recommend doing that just yet. Over the next week or so I'll look into making it compatible.
But please do test and scope out for any bugs.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 05, 2017, 03:56:13 am
a lot of incompatible syntax

MAX_PRIORITY_LAYERS = 5 unless (1..5).cover?(MAX_PRIORITY_LAYERS)
# should've using include? instead cover? since rmxp didn't have that



  def self.resize_screen(width, height)
    wt, ht = width.divmod(32), height.divmod(32)
    #wt.last + ht.last == 0 || fail('Incorrect width or height')
    wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ } # <<<<
    w, h = wh.(width, height)                   #<<<<
    ww, hh = wh.(width, height, 32)             #<<<<
    www, hhh = wh.(wt.first.succ, ht.first.succ)#<<<<
    base = 0x10000000  # fixed?
    mod = -> adr, val { DL::CPtr.new(base + adr)[0, val.size] = val } #<<<<


quick fix (expired in one week) : http://pastebin.com/pgRdi7Fn
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 05, 2017, 04:18:42 am
I'll wait for the tested version before I update.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 05, 2017, 04:38:43 am
@Drago: Ah, thanks about the cover? bit. Still not sure about the anon scripter part though. That was designed for RGSS3 specifically, so it shouldn't even be doing anything in XP projects, right? I'll need to omit that part entirely.

@Blizz: Should be fine for XPA. Doesn't hurt to just put __END__ at the top of the old tilemap.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 05, 2017, 04:53:50 am
Spoiler: ShowHide
(http://i.imgur.com/AnJGVmp.png)


I kept getting this in previous versions as well, but I hotfixed my copy of the script each time.

EDIT: I get this when I try to open the menu:

Spoiler: ShowHide
(http://i.imgur.com/zFNm0On.png)


EDIT: Would be nice if there was some code to disable all weather-related code since I use a custom weather system.

EDIT: I also had this in the previous version, but I don't know why. xD It's in Game_Screen.


  def shaking?
    return @shake_duration > 0 || @shake != 0
  end


Might be my own code for compatibility.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 05, 2017, 05:20:08 am
What's the fix for invalid byte sequence?
Plane should only create children if there's a viewport being passed in. So a check for if !viewport.nil? will be added.
I can make the WEATHER_ADJUSTMENT encompass Game_Screen and RPG::Weather, so they will only be loaded if WEATHER_ADJUSTMENT is true.
shaking? was removed as I no longer need it for Tilemap#update purposes. Was used to check if I had to move the viewport around and redraw tiles during screen shakes, but I resolved that in a different manner.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 05, 2017, 05:35:52 am
I literally just comment out that line for the byte-sequence. xD
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 05, 2017, 05:51:35 am
Huh, I guess the deletion of null characters isn't necessary. Duly noted.
One fix I did find online would be to do
title = title.encode("UTF-16be", :invalid=>:replace, :replace=>"?").encode('UTF-8')

before the deletion. Haven't tried yet.

How the heck is your title not even UTF-8 :P
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 05, 2017, 06:57:38 am
You misunderstood, Ruby doesn't recognize "\0" as UTF-8 string. It's not the string in "title" that's messed up. I think.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 05, 2017, 12:51:16 pm
But if that's the case, why have I never seen this before? I don't know how to reproduce it. :S
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 05, 2017, 01:20:36 pm
Try my DLL and EXE. https://www.dropbox.com/s/lwfax836rbbyhtx/cp-bin.rar?dl=0

Other than that it could be possible that the string really isn't UTF-8 for some reason. Is it possible that the DLL call messed it up? Or the string full of null-characters actually isn't treated as UTF-8 encoded initially? IDK.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 05, 2017, 01:33:53 pm
Still works for me. Our DLLs are the same. Hoping it's not GetPrivateProfileString at this point.
EDIT:
It's the trademark character (™) in your game title :facepalm:
But yeah, removing delete! or the fix I posted both work strangely enough.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 05, 2017, 05:05:47 pm
Then GetPrivateProfileString() is the one messing things up. It probably supports only ASCII or possibly wide-char if there is a W version of the function. Who knows.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 06, 2017, 04:20:55 am
I think it has to do with the changes in Ruby 1.9. As I found out, 1.9 defaults to UTF-8 encoding whereas 1.8 did not even know about encoding at the time, so all strings are just stored as literal bytes. This was also an issue with Multiple Inputs where we needed to use String#each_byte. Not sure if there's a one-liner thing that can essentially disable string encoding and just revert back to bytes again.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 06, 2017, 04:26:21 am
There was String#scan with (/./m) or something like that. I used it in my input module I think.
Ruby 1.8 did support UTF-8, but it would be implicit. That is, it would regard a string as UTF-8 automatically, because it's backwards compatible with ASCII. Other encodings would not work (such as multi-byte string), but using scan it was still possible to specify the "m" option in a regex (multi-byte) which would kinda make it work. But I'm not sure if it would work with multi-byte or UTF-8 strings, I can't remember.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 07, 2017, 02:31:25 am
I was kinda hoping for a one-liner fix-all, something like

# encoding: ______

that applied to all scripts in the project.

At least for this script, I found out that the Resolution module can be skipped entirely :P Since VXA already has its own resizing, it gets overruled. It's really only needed for XP games.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 08, 2017, 03:41:49 am
Fixed things up as mentioned, so updated to version 0.31
https://dl.dropboxusercontent.com/u/58874459/XPAT_v0.31.zip

Changes:

0.31  ... 08 Feb 2017 ... Bug fixes:
                            - Bad logic with border sprites for non-wrapping map
                            - Problem with Plane objects not initialized with a
                              viewport, causing children-creation to crash
                            - Disable Graphics.resize_screen in Hime's script
                              for XP games as this method does not exist nor is
                              the code necessary to "break" the resolution limit
                            - RGSS does not support Array#cover?
                           Changes:
                            - The Resolution module is disabled for XPA
                            - If WEATHER_ADJUSTMENT is false, it will disable
                              all of the RPG::Weather and Game_Screen classes
                              from loading rather than only some methods
                            - Input module for supporting different game window
                              sizes is disabled for XP as this feature does not
                              work in RGSS
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 08, 2017, 04:56:41 am
(http://i.imgur.com/Id8tk7M.jpg)
http://i.imgur.com/Id8tk7M.jpg

    wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ }
    w, h = wh.(width, height)


rgss can't handle that kind of syntax, it's irrelevant whether you disable it or not
you should change it to more friendly syntax instead

    wh = lambda {|w,h,off| [w + off, h + off].pack('l2').scan(/.{4}/) }
    w, h = wh.call(width, height,0)


edit : ups I forgot, rmxp also didn't have Graphics.snap_to_bitmap method

here to save your time : http://pastebin.com/pgRdi7Fn
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 08, 2017, 02:21:44 pm
Oh right, I had a feeling I was forgetting something. Especially that snap_to_bitmap.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 08, 2017, 06:34:45 pm
another bug detected, the fogs in top left area is thicker than other areas
no other script used, only RTP (pure rmxp) and XPAT

Spoiler: ShowHide
(http://i.imgur.com/gbwMGwO.jpg)
http://i.imgur.com/gbwMGwO.jpg
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 08, 2017, 07:54:47 pm
Does the viewport have some kind of color tint or tone to it? It seems that the children Plane objects aren't getting the same treatment as the parent.

Regarding the whole UTF-8 deal, I found out that if you eval your scripts, it suddenly works? I noticed this while having SUPERCLASS_MISMATCH_HELPER enabled.

start = __FILE__.scan(/\d+/)[0].to_i + 1
for i in start...$RGSS_SCRIPTS.size
  code = $RGSS_SCRIPTS[i][3]
  eval(code, nil, sprintf("{%04d}", i))
end
exit

But it only works if you buffer the string with "\0" * 256, not 0.chr * 256. Just a neat observation.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 09, 2017, 02:34:26 am
Just a normal fog though, not from script call.
Hue is 0 and normal blending, nothing special at all.

(http://i.imgur.com/QbISP8ys.jpg)
http://i.imgur.com/QbISP8y.jpg
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 09, 2017, 02:45:12 am
mmm there's definitely some screen tint involved. I used the same graphic on a tint-less map and noticed nothing.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 09, 2017, 02:50:38 am
Try different opacity values for the fog as well.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 09, 2017, 03:11:27 am
Forgot to tell you, yes there are screen tint involved.
Also, I noticed when using weather, the rain didn't fill the whole screen.

(http://i.imgur.com/QvvcAZU.jpg) (http://i.imgur.com/QvvcAZU.jpg)
http://i.imgur.com/QvvcAZU.jpg
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 09, 2017, 03:46:08 am
I know what the problem is now.
So Spriteset_Map@viewport1 needs to be stretched to the game's resolution in order to display the full Tilemap graphics. Planes can only draw in a 640x480 area regardless of the viewport size. The concept of Plane and Viewport children was born because of this. The problem though is that the parent, viewport1, stretches across the entire screen, so the children will overlap with it. Because the children viewports are created after the parent, they have a higher z-value. Thus, the parent's color "bleeds through" the children, giving off the wrong color (the 640x480 area in the top left is the actual target color).

The only solution I can think of is to not initialize the Plane objects to Spriteset_Map@viewport1; rather, make a child viewport in the top left too. Then somehow link viewport1 changes to apply ONLY to its children and not to itself.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 19, 2017, 05:44:08 am
Found a minor bug.

Spoiler: ShowHide
(http://i.imgur.com/K4z7T20.png)


It's this piece.


  alias flash_parent flash
  def flash(color, duration)
    @children.each{|child| child.flash(color, duration)} if @parent
    flash_parent
  end
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 19, 2017, 04:10:17 pm
Funny how I never noticed that before. Was testing Screen Flash and other map event commands and was convinced it was working. Took me until now to realize that the only time Viewport#flash is ever called is when a battle animation's flash scope is Screen.

Easy fix :P
Haven't looked into revising the script since releasing 0.31--maybe next weekend.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 19, 2017, 04:35:27 pm
Yeah, it happened on my end when I had a flash animation on the entire screen during battle. xD
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 26, 2017, 01:03:40 am
Okay, let's try this again:
Version 0.32: ShowHide

=begin
================================================================================
XPA Tilemap                                                      Version 0.32
by KK20                                                          25 Feb 2017
________________________________________________________________________________

[ Version History ]

Ver.      Date            Notes
-----     -----------     ----------------------------------------------------
0.32  ... 25 Feb 2017 ... Bug fixes:
                            - Child viewports were having display issues when
                              tone changes were involved
                            - Viewport#flash had missing parameters
                            - Added more compatibility for XP games (thanks
                              LiTTleDRAgo!)
0.31  ... 08 Feb 2017 ... Bug fixes:
                            - Bad logic with border sprites for non-wrapping map
                            - Problem with Plane objects not initialized with a
                              viewport, causing children-creation to crash
                            - Disable Graphics.resize_screen in Hime's script
                              for XP games as this method does not exist nor is
                              the code necessary to "break" the resolution limit
                            - RGSS does not support Array#cover?
                           Changes:
                            - The Resolution module is disabled for XPA
                            - If WEATHER_ADJUSTMENT is false, it will disable
                              all of the RPG::Weather and Game_Screen classes
                              from loading rather than only some methods
                            - Input module for supporting different game window
                              sizes is disabled for XP as this feature does not
                              work in RGSS
0.3   ... 04 Feb 2017 ... Bug fixes:
                            - A graphical bug involving priority tiles if the
                              MAX_PRIORITY_LAYERS is set to less than 5
                            - Loading autotiles in RPG::Cache has been revised
                              for better compatibility
                            - CallBackController added to replace the method
                              implemented in v0.2b which prevented saving games
                           Additions:
                            - Commented out a majority of the anonymous scripter
                              code that breaks the resolution limit for RGSS3;
                              its ramifications are unknown at this point
                            - A new Plane rewrite which is merely just creating
                              more Plane objects
                            - Maps that do not wrap have a high z-level black
                              sprite positioned around the map's borders
                            - New fullscreen and other window size options for
                              XPA games (will not work for XP)
                            - Tilesets that are not divisible by 32 will raise
                              an error rather than crash
                            - Maps with invalid tile ID's (caused when a tile
                              was placed with a taller tileset graphic, but then
                              the map uses a shorter tileset) no longer crash
                              the game
0.13b ... 23 Oct 2016 ... Bug fixes:
                            - Resolutions not divisible by 32 would not show the
                              last row/column of tiles entirely
                           ** Fix added on top of v0.12b, not v0.2b, but is
                           ** included in all versions above this one
0.2b  ... 07 Jun 2016 ... Bug fixes:
                            - Shaking still had issues
                           Additions:
                            - Maps can now wrap by putting [WRAP] in the map
                              name, due to a new way of drawing the map
                            - ...which also fixed the shaking above
                            - ...and can also allow vertical shaking
                            - Added Unlimited Resolution, an RMVXA script with
                              some changes
                            - Changing tileset and autotile bitmaps in-game will
                              not crash (assuming you know how to do that)
                            - Overall cleaning of code
0.12b ... 27 Feb 2016 ... Bug fixes:
                            - Tiles with some transparency and priority were
                              being redrawn continuously on each other
                            - Setting the Plane bitmap to nil would crash
0.11b ... 03 Nov 2014 ... Bug fixes:
                            - Table did not take in parameters upon initialize
                            - Centering of maps now shrinks Viewport sizes
                            - Fixed Tilemap#oy= logic
0.1b  ... 02 Nov 2014 ... Initial release
________________________________________________________________________________

[ Introduction ]

In light of recent discoveries regarding the usage of RGSS3 in RPG Maker XP
games, many users were left with a dilemma in choosing which Tilemap rewrite to
use due to the vast differences between RGSS1's and RGSS3's Tilemap classes
that would cause complications in this transition. I aimed to find the best
Tilemap rewrite and decided that I would have to make my own. Like every other
Tilemap rewrite before it, this implementation is in no ways perfect, boasting
PROs and CONs.

This script is intended to be used for RPG Maker XP games using the RGSS3
library (unofficially coined RPG Maker XP Ace); however, it is entirely
compatible with RPG Maker XP games in the RGSS1 library.
________________________________________________________________________________

[ License ]

This work is protected by the following license:
http://creativecommons.org/licenses/by-nc-sa/3.0/

********************************************************************************

You are free:

to Share - to copy, distribute and transmit the work
to Remix - to adapt the work

Under the following conditions:

Attribution:
You must attribute the work in the manner specified by the author or licensor,
but not in any way that suggests that they endorse you or your use of the work.

Noncommercial:
You may not use this work for commercial purposes.

Share alike:
If you alter, transform, or build upon this work, you may distribute the
resulting work only under the same or similar license to this one.

- For any reuse or distribution, you must make clear to others the license terms
  of this work. The best way to do this is with a link to this web page.

- Any of the above conditions can be waived if you get permission from the
  copyright holder.

- Nothing in this license impairs or restricts the author's moral rights.

********************************************************************************

[ Instructions ]

- Place this script below the default scripts but above Main.
- Move 'XPATilemap.dll' into your project folder (same directory as 'Game.exe')
- Configure values at the start of the script
________________________________________________________________________________

[ Features ]

About the script:
- XP and XPA (RGSS1 and RGSS3) compatible, though designed for XPA
- Define your own custom resolution
- Adds new tilemap features
- Maps that are smaller than the game resolution are automatically centered
- Drawing methods written in C-language, which has faster pixel-by-pixel
   operations than Ruby

Add-ons:
- Customize frame rate animation and define unique patterns for your autotiles
- Remove unnecessary priority layers to boost frames-per-second (FPS)
- Extend the default RPG::Weather class to fit larger screens, or not
- Change the way fullscreen works (or disable it), including a double and half-
   size window option (only for XPA)
- more to add later...
________________________________________________________________________________

[ Compatibility ]

- There have been reports of Screen Flash not working for some users, though I
   have yet to receive any valid proof or ways to reproduce this issue
- Your tileset must have dimensions divisible by 32. The game will raise an
   error otherwise.
________________________________________________________________________________

[ Credits ]

KK20 - Author of this script and DLL
Blizzard - Tester and providing bug fixes
LiTTleDRAgo - Reusing code from his edits to Custom Resolution and bug fixes
Zexion - Tester and morale support
ForeverZer0 - Reusing code from his Custom Resolution script, found here:
                http://forum.chaos-project.com/index.php/topic,7814.0.html
________________________________________________________________________________

[ Contact ]

To contact the author of this script, please visit
                http://forum.chaos-project.com/index.php
               
or send an email to
                        tscrane20@gmail.com
                       
================================================================================
=end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                       B E G I N   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#-------------------------------------------------------------------------------
# The game window's screen resolution. RPG Maker XP's default is [640, 480].
# Do note that a larger resolution is prone to sprite lag.
# Anything larger than the default resolution will enable the custom Plane class.
#-------------------------------------------------------------------------------
SCREEN_RESOLUTION = [640, 480]

#-------------------------------------------------------------------------------
# The largest level of priority your game uses. This value should be between
# 1 and 5. If using a large resolution, lowering the number of priority layers
# will help in reducing the lag.
#-------------------------------------------------------------------------------
MAX_PRIORITY_LAYERS = 5

#-------------------------------------------------------------------------------
# If using a larger resolution than 640x480, the default weather effects will
# not cover the entire map. It is recommended that you set this to true to
# compensate for that, unless you are using some custom weather script that can
# address this.
#-------------------------------------------------------------------------------
WEATHER_ADJUSTMENT = false

#-------------------------------------------------------------------------------
# When the map's display_x/y variables extend beyond its borders, the map wraps
# around to fill in the gaps. Setting this to true will prevent that, showing
# black borders instead.
# If you want some maps to wrap around, putting [WRAP] in a map's name will
# allow this.
# Note that the custom Plane class will be enabled in order to create this
# effect regardless of your resolution size.
#-------------------------------------------------------------------------------
DISABLE_WRAP = false

#-------------------------------------------------------------------------------
# Choose a form of fullscreen for your game. The available choices are:
#  0 = Default RPG Maker fullscreen (changes monitor resolution to 640x480)
#  1 = Stetches game window to player's monitor size (only for XPA)
#  2 = Disable the ability to go into fullscreen
# Please note that if you choose anything other than 0, it disables everything
# on the player's computer from being able to use ALT + ENTER.
#-------------------------------------------------------------------------------
FULLSCREEN_METHOD = 0

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 2x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
TWICE_SIZE_BUTTON = Input::F5

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 0.5x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
HALF_SIZE_BUTTON = Input::F6

#-------------------------------------------------------------------------------
# Set the animation frame rate for autotiles. By default, all autotiles will
# update on the 16th frame. You can change that by providing an array of numbers
# that represent how many frames that particular frame of animation will be
# visible for.
# Format:
#   when AUTOTILE_FILENAME then FRAME_DATA
# where FRAME_DATA is an array containing the number of frames that particular
# animation will play for before moving onto the next frame. Be sure to match
# the number of autotile animation frames with the number of elements you put
# into the array.
# Check the examples below.
#-------------------------------------------------------------------------------
def autotile_framerate(filename)
  case filename
  #------------------------------------------------------ START ------
  when '001-G_Water01' then [8, 8, 8, 8]      # Animates twice as fast
  when '009-G2_Water01' then [20, 20, 20, 20] # Animates a bit slower
  when '024-Ocean01' then [32, 16, 32, 16]    # Sine wave effect
  #------------------------------------------------------- END -------
  # Don't touch any of this below
  else
    return nil if filename == ''
    # Generates array of [16, 16, ...] based on autotile width
    # (or nil if not animating autotile)
    w = RPG::Cache.autotile(filename).width
    h = RPG::Cache.autotile(filename).height
    if (h == 32 && w / 32 == 1) || (h == 192 && w / 256 == 1)
      return nil
    else
      return h == 32 ? Array.new(w/32){|i| 16} : Array.new(w/256){|i| 16}
    end
  end
end

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                           E N D   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FULLSCREEN_METHOD = 0 unless FULLSCREEN_METHOD.between?(0,2)
if FULLSCREEN_METHOD != 0
  # Disable ALT+Enter
  reghotkey = Win32API.new('user32', 'RegisterHotKey', 'LIII', 'I')
  reghotkey.call(0, 1, 1, 0x0D)
end

XPACE = RUBY_VERSION == "1.9.2"

MAX_PRIORITY_LAYERS = 5 unless (1..5).include?(MAX_PRIORITY_LAYERS)

if XPACE
#===============================================================================
# ** Input
#===============================================================================
module Input

  GetActiveWindow = Win32API.new('user32', 'GetActiveWindow', '', 'L')
  SetWindowLong = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
  SetWindowPos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
  GetSystemMetrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
  GetAsyncKeyState = Win32API.new('user32', 'GetAsyncKeyState', 'I', 'I')
 
  @fullscreenKeysReleased = true
  @current_state = 0
  NORMAL_STATE     = 0
  FULLSCREEN_STATE = 1
  TWICESIZE_STATE  = 2
  HALFSIZE_STATE   = 3
 
  class << self
    alias get_fullscreen_keys update
   
    # Check for window resize buttons
    def update
      enterkey_state = GetAsyncKeyState.call(0x0D)
      # If ALT+ENTER was pressed, but only for modified fullscreen
      if FULLSCREEN_METHOD == 1 && @fullscreenKeysReleased && Input.press?(Input::ALT) && enterkey_state != 0
        @current_state = @current_state == FULLSCREEN_STATE ? NORMAL_STATE : FULLSCREEN_STATE
        @fullscreenKeysReleased = false
        # Changing game window to fullscreen
        if @current_state == FULLSCREEN_STATE
          full_screen_size
        else
          normal_screen_size
        end
      # If button to double the normal window size was pressed
      elsif TWICE_SIZE_BUTTON && Input.trigger?(TWICE_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to double or normalize the window
        @current_state = @current_state == TWICESIZE_STATE ? NORMAL_STATE : TWICESIZE_STATE
        if @current_state == TWICESIZE_STATE
          double_screen_size
        else
          normal_screen_size
        end
      # If button to halve the normal window size was pressed
      elsif HALF_SIZE_BUTTON && Input.trigger?(HALF_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to halve or normalize the window
        @current_state = @current_state == HALFSIZE_STATE ? NORMAL_STATE : HALFSIZE_STATE
        if @current_state == HALFSIZE_STATE
          half_screen_size
        else
          normal_screen_size
        end
      else
        # Check if ALT or ENTER is released
        @fullscreenKeysReleased = (!Input.press?(Input::ALT) || enterkey_state == 0)
      end
      # Call the alias
      get_fullscreen_keys
    end
   
    # Doubles the window size based on SCREEN_RESOLUTION.
    def double_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] * 2
      nh = SCREEN_RESOLUTION[1] * 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Halves the window size based on SCREEN_RESOLUTION.
    def half_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] / 2
      nh = SCREEN_RESOLUTION[1] / 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Makes game window as large as the monitor's resolution
    def full_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x10000000)
      SetWindowPos.call(GetActiveWindow.call, 0, 0, 0, rw, rh, 0)
    end
   
    # Reverts the game window back to normal size
    def normal_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      x = (rw - SCREEN_RESOLUTION[0]) / 2
      y = (rh - SCREEN_RESOLUTION[1]) / 2
      w = SCREEN_RESOLUTION[0] + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = SCREEN_RESOLUTION[1] + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Simulates the key press of ALT+Enter; called if we need to get in or out
    # of fullscreen even though the player did not press these keys
    def simulate_alt_enter
      keybd = Win32API.new 'user32.dll', 'keybd_event', ['i', 'i', 'l', 'l'], 'v'
      keybd.call(0xA4, 0, 0, 0)
      keybd.call(13, 0, 0, 0)
      keybd.call(13, 0, 2, 0)
      keybd.call(0xA4, 0, 2, 0)
    end
   
    # Check if the game is in default fullscreen
    def fullscreen?
      # We're not using default fullscreen, so this should always be false
      return false if FULLSCREEN_METHOD != 0
      # If current monitor resolution is 640x480, then it is fullscreen
      if GetSystemMetrics.call(0) == 640 && GetSystemMetrics.call(1) == 480
        @current_state = FULLSCREEN_STATE
        return true
      end
    end
   
  end
end

end # if XPACE

if !XPACE
#===============================================================================
# ** Resolution
#===============================================================================
module Resolution
 
  def self.resize_game
    # Set instance variables for calling basic Win32 functions.
    ini = Win32API.new('kernel32', 'GetPrivateProfileStringA','PPPPLP', 'L')
    title = "\0" * 256
    ini.call('Game', 'Title', '', title, 256, '.\\Game.ini')
    title.delete!("\0")
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
    set_window_long = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
    set_window_pos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
    @metrics         = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
    # Set default size, displaying error if size is larger than the hardware.
    default_size = Resolution.size
    # Apply resolution change.
    x = (@metrics.call(0) - SCREEN_RESOLUTION[0]) / 2
    y = (@metrics.call(1) - SCREEN_RESOLUTION[1]) / 2
    set_window_long.call(@window, -16, 0x14CA0000)
    set_window_pos.call(@window, 0, x, y, SCREEN_RESOLUTION[0] + 6, SCREEN_RESOLUTION[1] + 26, 0)
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
  end
  #--------------------------------------------------------------------------
  def self.size
    # Returns the screen size of the machine.
    [@metrics.call(0), @metrics.call(1)]
  end
  #--------------------------------------------------------------------------
end

end # if !XPACE

#===============================================================================
# ** NilClass
#===============================================================================
class NilClass
  unless method_defined?(:dispose)
    def dispose; end
    def disposed?; end
  end
end
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
  attr_accessor :filename
  alias set_filename_of_bitmap initialize
  def initialize(*args)
    # Associate the bitmap with the filename of the graphic; empty string otherwise
    @filename = args.size == 1 ? File.basename(args[0], '.*') : ''
    set_filename_of_bitmap(*args)
  end
end
#===============================================================================
# ** RPG::Cache
#===============================================================================
module RPG::Cache
 
  AUTO_INDEX = [
 
  [27,28,33,34],  [5,28,33,34],  [27,6,33,34],  [5,6,33,34],
  [27,28,33,12],  [5,28,33,12],  [27,6,33,12],  [5,6,33,12],
  [27,28,11,34],  [5,28,11,34],  [27,6,11,34],  [5,6,11,34],
  [27,28,11,12],  [5,28,11,12],  [27,6,11,12],  [5,6,11,12],
  [25,26,31,32],  [25,6,31,32],  [25,26,31,12], [25,6,31,12],
  [15,16,21,22],  [15,16,21,12], [15,16,11,22], [15,16,11,12],
  [29,30,35,36],  [29,30,11,36], [5,30,35,36],  [5,30,11,36],
  [39,40,45,46],  [5,40,45,46],  [39,6,45,46],  [5,6,45,46],
  [25,30,31,36],  [15,16,45,46], [13,14,19,20], [13,14,19,12],
  [17,18,23,24],  [17,18,11,24], [41,42,47,48], [5,42,47,48],
  [37,38,43,44],  [37,6,43,44],  [13,18,19,24], [13,14,43,44],
  [37,42,43,48],  [17,18,47,48], [13,18,43,48], [13,18,43,48]
   
  ]
 
  def self.autotile(filename)
    key = "Graphics/Autotiles/#{filename}"
    if !@cache.include?(key) || @cache[key].disposed?
      # Load the autotile graphic.
      new_bm = self.load_bitmap('Graphics/Autotiles/', filename)
      # Cache each configuration of this autotile.
      new_bm = self.format_autotiles(new_bm, filename)
      @cache[key].dispose
      @cache[key] = new_bm
    end
    @cache[key]
  end

  def self.format_autotiles(bitmap, filename)
    if bitmap.height > 32 && bitmap.height < 256
      frames = bitmap.width / 96
      template = Bitmap.new(256*frames,192)
      template.filename = filename
      # Create a bitmap to use as a template for creation.
      (0..frames-1).each{|frame|
      (0...6).each {|i| (0...8).each {|j| AUTO_INDEX[8*i+j].each {|number|
        number -= 1
        x, y = 16 * (number % 6), 16 * (number / 6)
        rect = Rect.new(x + (frame * 96), y, 16, 16)
        template.blt((32 * j + x % 32) + (frame * 256), 32 * i + y % 32, bitmap, rect)
      }}}}
      return template
    else
      return bitmap
    end
  end
 
end
#===============================================================================
# ** CallBackController
#===============================================================================
module CallBackController
  @@callback = {}
 
  def self.setup_callback(obj, proc)
    @@callback[obj.object_id] = proc
  end
 
  def self.call(obj, *args)
    @@callback[obj.object_id].call(*args) if @@callback[obj.object_id]
    true
  end
 
  def self.delete(obj)
    @@callback.delete(obj.object_id)
  end
 
end

#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :offset_x, :offset_y
 
  alias zer0_viewport_resize_init initialize
  def initialize(x=0, y=0, width=SCREEN_RESOLUTION[0], height=SCREEN_RESOLUTION[1], override=false)
    # Variables needed for Viewport children (for the Plane rewrite); ignore if
    # your game resolution is not larger than 640x480
    @offset_x = @offset_y = 0
    if x.is_a?(Rect)
      # If first argument is a Rectangle, just use it as the argument.
      zer0_viewport_resize_init(x)
    elsif [x, y, width, height] == [0, 0, 640, 480] && !override
      # Resize fullscreen viewport, unless explicitly overridden.
      zer0_viewport_resize_init(Rect.new(0, 0, SCREEN_RESOLUTION[0], SCREEN_RESOLUTION[1]))
    else
      # Call method normally.
      zer0_viewport_resize_init(Rect.new(x, y, width, height))
    end
  end
 
  def resize(*args)
    # Resize the viewport. Can call with (X, Y, WIDTH, HEIGHT) or (RECT).
    if args[0].is_a?(Rect)
      args[0].x += @offset_x
      args[0].y += @offset_y
      self.rect = args[0]
    else
      args[0] += @offset_x
      args[1] += @offset_y
      self.rect = Rect.new(*args)
    end
  end
end

#===============================================================================
# ** Tilemap
#===============================================================================
class Tilemap
 
  attr_accessor :tileset, :autotiles, :map_data, :priorities, :ground_sprite
  attr_reader :wrapping
  #---------------------------------------------------------------------------
  # Initialize
  #---------------------------------------------------------------------------
  def initialize(viewport = nil)
    @viewport = viewport
    @layer_sprites = []
    @autotile_frame = []      #[[ANIMATION_DRAW_INDEX, CURRENT_LOGICAL_FRAME], ... ]
    @autotile_framedata = []  #[[DATA_FROM_CONFIGURATION_ABOVE], ... ]
   
    # Ensures that the bitmap width accounts for an extra tile
    # and is divisible by 32
    bitmap_width = ((SCREEN_RESOLUTION[0] / 32.0).ceil + 1) * 32
    # Create the priority layers
    ((SCREEN_RESOLUTION[1]/32.0).ceil + MAX_PRIORITY_LAYERS).times{ |i|
      s = Sprite.new(@viewport)
      s.bitmap = Bitmap.new(bitmap_width, MAX_PRIORITY_LAYERS * 32)
      @layer_sprites.push(s)
    }
   
    # Same reasons as bitmap_width, but for height
    bitmap_height = ((SCREEN_RESOLUTION[1] / 32.0).ceil + 1) * 32
    # Create the ground layer (priority 0)
    s = Sprite.new(@viewport)
    s.bitmap = Bitmap.new(bitmap_width, bitmap_height)
    @ground_sprite = s
    @ground_sprite.z = 0

    # Initialize remaining variables
    @redraw_tilemap = true
    @tileset = nil
    @autotiles = []
    proc = Proc.new { |x,y| @redraw_tilemap = true; setup_autotile(x) }
    CallBackController.setup_callback(@autotiles, proc)
   
    @map_data = nil
   
    @priorities = nil
    @old_ox = 0
    @old_oy = 0
    @ox = 0
    @oy = 0
    @ox_float = 0.0
    @oy_float = 0.0
    @shift = 0
    @wrapping = (!DISABLE_WRAP || (XPAT_MAP_INFOS[$game_map.map_id].name =~ /.*\[[Ww][Rr][Aa][Pp]\].*/) == 0) ? 1 : 0
    create_border_sprites
   
    # Set up the DLL calls
    @@update = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap2', 'pppp', 'i')
    @@autotile_update = Win32API.new('XPA_Tilemap', 'UpdateAutotiles', 'pppp', 'i')
    @@initial_draw = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap', 'pppp', 'i')
    @empty_tile = Bitmap.new(32,32)
    Win32API.new('XPA_Tilemap','InitEmptyTile','l','i').call(@empty_tile.object_id)
    @black_tile = Bitmap.new(32,32)
    @black_tile.fill_rect(0,0,32,32,Color.new(0,0,0))
    Win32API.new('XPA_Tilemap','InitBlackTile','l','i').call(@black_tile.object_id)
   
  end
  #---------------------------------------------------------------------------
  # Setup autotile animation data
  #---------------------------------------------------------------------------
  def setup_autotile(i)
    # Get animation frame rate of the autotile
    bitmap = @autotiles[i]
    frames = bitmap.nil? ? nil : autotile_framerate(bitmap.filename)
    # If autotile doesn't animate
    if frames.nil?
      @autotile_frame[i] = [0,0]
      @autotile_framedata[i] = nil
    else
      # Save the frame rate data
      @autotile_framedata[i] = frames
      # Determine how long one animation cycle takes and indicate at what time
      # the next frame of animation occurs
      total = 0
      frame_checkpoints = []
     
      frames.each_index{|j| f = frames[j]
        total += f
        frame_checkpoints[j] = total
      }
      # Get animation frame for this autotile based on game time passed
      current_frame = Graphics.frame_count % total
      frame_checkpoints.each_index{|j| c = frame_checkpoints[j]
        next if c.nil?
        if c > current_frame
          @autotile_frame[i] = [j, c - current_frame]
          break
        end
      }
    end
  end
  #---------------------------------------------------------------------------
  # Creates four 32-pixel thick black sprites to surround the map. This is
  # only applied to maps that do not have wrapping enabled. This helps those
  # who have screen shaking in their maps.
  #---------------------------------------------------------------------------
  def create_border_sprites
    @border_sprites = []
    return if @wrapping == 1
    for i in 0..3
      s = Sprite.new(@viewport)
      s.z = 99999
      if i % 2 == 0
        b = Bitmap.new(SCREEN_RESOLUTION[0] + 64,32)
        s.x = -32
        s.y = i == 0 ? -32 : $game_map.height * 32
      else
        b = Bitmap.new(32,SCREEN_RESOLUTION[1] + 64)
        s.x = i == 1 ? -32 : $game_map.width * 32
        s.y = -32
      end
      b.fill_rect(0, 0, b.width, b.height, Color.new(0,0,0))
      s.bitmap = b
      @border_sprites.push(s)
    end
  end
  #---------------------------------------------------------------------------
  # Dispose tilemap
  #---------------------------------------------------------------------------
  def dispose
    @layer_sprites.each{|sprite| sprite.dispose}
    @ground_sprite.dispose
    @border_sprites.each{|sprite| sprite.dispose}
  end
  #---------------------------------------------------------------------------
  # Check if disposed tilemap
  #---------------------------------------------------------------------------
  def disposed?
    @layer_sprites[0].disposed?
  end
  #---------------------------------------------------------------------------
  # Get viewport
  #---------------------------------------------------------------------------
  def viewport
    @viewport
  end
  #---------------------------------------------------------------------------
  # Return if tilemap is visible
  #---------------------------------------------------------------------------
  def visible
    layer_sprites[0].visible
  end
  #---------------------------------------------------------------------------
  # Show or hide tilemap
  #---------------------------------------------------------------------------
  def visible=(bool)
    @layer_sprites.each{|sprite| sprite.visible = bool}
    @ground_sprite.visible = bool
  end
  #---------------------------------------------------------------------------
  # Set tileset
  #---------------------------------------------------------------------------
  def tileset=(bitmap)
    @tileset = bitmap
    if @tileset.width % 32 != 0 || @tileset.height % 32 != 0
      file = bitmap.filename
      raise "Your tileset graphic #{file} needs to be divisible by 32!"
    end
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set autotiles
  #---------------------------------------------------------------------------
  def autotiles=(array)
    CallBackController.delete(@autotiles)
    @autotiles = array
    proc = Proc.new { |i| @redraw_tilemap = true; setup_autotile(i) }
    CallBackController.setup_callback(@autotiles, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map data
  #---------------------------------------------------------------------------
  def map_data=(table)
    CallBackController.delete(@map_data)
    @map_data = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@map_data, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map priorities
  #---------------------------------------------------------------------------
  def priorities=(table)
    CallBackController.delete(@priorities)
    @priorities = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@priorities, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Get horizontal shift
  #---------------------------------------------------------------------------
  def ox
    @ox + @ox_float
  end
  #---------------------------------------------------------------------------
  # Get vertical shift
  #---------------------------------------------------------------------------
  def oy
    @oy + @oy_float
  end
  #---------------------------------------------------------------------------
  # Shift tilemap horizontally
  #---------------------------------------------------------------------------
  def ox=(ox)
    @ox_float = (ox - ox.to_i) % 1
    @ox = ox.floor
    @border_sprites.each{ |s|
      next if s.bitmap.height == 32
      s.ox = @ox
    }
  end
  #---------------------------------------------------------------------------
  # Shift tilemap vertically
  #---------------------------------------------------------------------------
  def oy=(oy)
    @oy_float = (oy - oy.to_i) % 1
    @oy = oy.floor
    @border_sprites.each{ |s|
      next if s.bitmap.width == 32
      s.oy = @oy
    }
  end
  #---------------------------------------------------------------------------
  # Update tilemap graphics
  #---------------------------------------------------------------------------
  def update; end;
  def draw
    # Figure out what the new X and Y coordinates for the ground layer would be
    x = @old_ox - @ox
    @old_ox = @ox
    x += @ground_sprite.x

    y = @old_oy - @oy
    @old_oy = @oy
    y += @ground_sprite.y

    # No reason to do sprite shifting if we're just redrawing everything
    if !@redraw_tilemap
      # If layers would be too far to the left
      if x < @viewport.ox - 31
        # If still too far, then force redraw
        if x + 32 < @viewport.ox - 31
          @redraw_tilemap = true
        else
          # Shift all layers right by 32 and clear out left-most column
          x += 32
          @ground_sprite.bitmap.fill_rect(0, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(0, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 1 # Redraw right column bit-flag (0001)
        end
      # If layers would be too far to the right
      elsif x > @viewport.ox
        # If still too far, then force redraw
        if x - 32 > @viewport.ox
          @redraw_tilemap = true
        else
          # Shift all layers left by 32 and clear out right-most column
          x -= 32
          @ground_sprite.bitmap.fill_rect(@ground_sprite.bitmap.width - 32, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(sprite.bitmap.width - 32, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 2 # Redraw left column bit-flag (0010)
        end
      end
      # Apply the change in X to the layers
      if !@redraw_tilemap
        @ground_sprite.x = x
        @layer_sprites.each{|sprite| sprite.x = x}

        # If layers would be too far up
        if y < @viewport.oy - 31
          # If still too far, then force redraw
          if y + 32 < @viewport.oy - 31
            @redraw_tilemap = true
          else
            y += 32
            layer = @layer_sprites.shift
            layer.bitmap.clear
            @layer_sprites.push(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            num = @layer_sprites.size
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[num-index].bitmap.fill_rect(0, (index - 1) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 4 # Redraw bottom row bit-flag (0100)
          end
        # If layers would be too far down
        elsif y > @viewport.oy
          # If still too far, then force redraw
          if y - 32 > @viewport.oy
            @redraw_tilemap = true
          else
            y -= 32
            layer = @layer_sprites.pop
            layer.bitmap.clear
            @layer_sprites.unshift(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[index].bitmap.fill_rect(0, (MAX_PRIORITY_LAYERS - 1 - index) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 8 # Redraw top row bit-flag (1000)
          end
        end
        # Apply the change to layers' Y and Z values
        if !@redraw_tilemap
          @ground_sprite.y = y
          @layer_sprites.each_index{ |i| sprite = @layer_sprites[i]
            sprite.y = y - 32 * (MAX_PRIORITY_LAYERS - 1 - i)
            sprite.z = sprite.y + (192 - (5 - MAX_PRIORITY_LAYERS) * 32)
          }
        end
      end
    end

    autotile_need_update = []
    # Update autotile animation frames
    for i in 0..6
      autotile_need_update[i] = false
      # If this autotile doesn't animate, skip
      next if @autotile_framedata[i].nil?
      # Reduce frame count
      @autotile_frame[i][1] -= 1
      # Autotile requires update
      if @autotile_frame[i][1] == 0
        @autotile_frame[i][0] = (@autotile_frame[i][0] + 1) % @autotile_framedata[i].size
        @autotile_frame[i][1] = @autotile_framedata[i][@autotile_frame[i][0]]
        autotile_need_update[i] = true
      end
    end
   
   
    # Stop the update unless redrawing, there is shifting, or an autotile needs to update
    return unless @redraw_tilemap || @shift != 0 || !autotile_need_update.index(true).nil?

    # Set up the array for the priority layers
    layers = [@layer_sprites.size + 1]
    # Insert higher priority layers into the array in order (least to most y-value sprite)
    @layer_sprites.each{|sprite| layers.push(sprite.bitmap.object_id) }
    # Insert ground layer last in the array
    layers.push(@ground_sprite.bitmap.object_id)
    # Load autotile bitmap graphics into array
    tile_bms = [self.tileset.object_id]
    self.autotiles.each{|autotile| tile_bms.push(autotile.object_id) }
    # Store autotile animation frame data
    autotiledata = []
    for i in 0..6
      autotiledata.push(@autotile_frame[i][0])
      autotiledata.push(autotile_need_update[i] ? 1 : 0)
    end
    # Fills in remaining information of other tilemaps
    misc_data = [@ox + @viewport.ox, @oy + @viewport.oy,
      self.map_data.object_id, self.priorities.object_id, @shift,
      MAX_PRIORITY_LAYERS, @wrapping]
   
    # If forcing fresh redraw of the map (or drawing for first time)
    if @redraw_tilemap
      # Initialize layer sprite positions and clear them for drawing
      @ground_sprite.bitmap.clear
      @ground_sprite.x = (@viewport.ox - @viewport.ox % 32) - (@ox % 32)
      @ground_sprite.x += 32 if @ground_sprite.x < @viewport.ox - 31
      @ground_sprite.y = (@viewport.oy - @viewport.oy % 32) - (@oy % 32)
      @ground_sprite.y += 32 if @ground_sprite.y < @viewport.oy - 31

      y_buffer = 32 * (MAX_PRIORITY_LAYERS - 1)
      z_buffer = MAX_PRIORITY_LAYERS * 32 + 32
      @layer_sprites.each_index{|i| layer = @layer_sprites[i]
        layer.bitmap.clear
        layer.x = @ground_sprite.x
        layer.y = @ground_sprite.y - y_buffer + 32 * i
        layer.z = layer.y + z_buffer
      }
      # Make DLL call
      @@initial_draw.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    elsif @shift != 0
      # Update for shifting
      @@update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Check for autotile updates (at least one autotile needs an update)
    # No need if redrawn tilemap since it already handled the updated autotiles
    if !@redraw_tilemap && !autotile_need_update.index(true).nil?
      @@autotile_update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Turn off flag
    @redraw_tilemap = false
    # Reset shift flag
    @shift = 0
  end
 
end
#===============================================================================
# ** Game_Player
#===============================================================================
class Game_Player
 
  CENTER_X = ((SCREEN_RESOLUTION[0] / 2) - 16) * 4    # Center screen x-coordinate * 4
  CENTER_Y = ((SCREEN_RESOLUTION[1] / 2) - 16) * 4    # Center screen y-coordinate * 4
 
  def center(x, y)
    # Recalculate the screen center based on the new resolution.
    max_x = (($game_map.width - (SCREEN_RESOLUTION[0]/32.0)) * 128).to_i
    max_y = (($game_map.height - (SCREEN_RESOLUTION[1]/32.0)) * 128).to_i
    $game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
    $game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
  end
end
#===============================================================================
# ** Game_Map
#===============================================================================
class Game_Map
  alias zer0_map_edge_setup setup
  def setup(map_id)
    zer0_map_edge_setup(map_id)
    # Find the displayed area of the map in tiles. No calcualting every step.
    @map_edge = [self.width - (SCREEN_RESOLUTION[0]/32.0), self.height - (SCREEN_RESOLUTION[1]/32.0)]
    @map_edge.collect! {|size| size * 128 }
    # Change the map center if map is smaller than the resolution
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      Game_Player.const_set(:CENTER_X, $game_map.width * 128)
    else
      Game_Player.const_set(:CENTER_X, ((SCREEN_RESOLUTION[0] / 2) - 16) * 4)
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      Game_Player.const_set(:CENTER_Y, $game_map.height * 128)
    else
      Game_Player.const_set(:CENTER_Y, ((SCREEN_RESOLUTION[1] / 2) - 16) * 4)
    end
  end

  def scroll_down(distance)
    # Find point that the map edge meets the screen edge, using custom size.
    @display_y = [@display_y + distance, @map_edge[1]].min
  end

  def scroll_right(distance)
    # Find point that the map edge meets the screen edge, using custom size.
    @display_x = [@display_x + distance, @map_edge[0]].min
  end
end

# Override set-methods to allow callbacks (necessary for Tilemap)
#===============================================================================
# ** Array
#===============================================================================
class Array
  alias flag_changes_to_set []=
  def []=(x, y)
    flag_changes_to_set(x, y)
    CallBackController.call(self, x, y)
  end
end
#===============================================================================
# ** Table
#===============================================================================
class Table
  alias flag_changes_to_set []=
  def []=(*args)
    flag_changes_to_set(*args)
    CallBackController.call(self, *args)
  end
end

if WEATHER_ADJUSTMENT
#===============================================================================
# ** RPG::Weather
#===============================================================================
class RPG::Weather
 
  alias add_more_weather_sprites initialize
  def initialize(vp = nil)
    add_more_weather_sprites(vp)
    total_sprites = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 7680
    if total_sprites > 40
      for i in 1..(total_sprites - 40)
        sprite = Sprite.new(vp)
        sprite.z = 1000
        sprite.visible = false
        sprite.opacity = 0
        @sprites.push(sprite)
      end
    end
  end
 
  def type=(type)
    return if @type == type
    @type = type
    case @type
    when 1
      bitmap = @rain_bitmap
    when 2
      bitmap = @storm_bitmap
    when 3
      bitmap = @snow_bitmap
    else
      bitmap = nil
    end
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
        sprite.bitmap = bitmap
      end
    end
  end
 
  def max=(max)
    return if @max == max;
    @max = [[max, 0].max, @sprites.size].min
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
      end
    end
  end
 
  def update
    return if @type == 0
    for i in 1..@max
      sprite = @sprites[i]
      if sprite == nil
        break
      end
      if @type == 1
        sprite.x -= 2
        sprite.y += 16
        sprite.opacity -= 8
      end
      if @type == 2
        sprite.x -= 8
        sprite.y += 16
        sprite.opacity -= 12
      end
      if @type == 3
        sprite.x -= 2
        sprite.y += 8
        sprite.opacity -= 8
      end
      x = sprite.x - @ox
      y = sprite.y - @oy
      if sprite.opacity < 64
        sprite.x = rand(SCREEN_RESOLUTION[0] + 100) - 100 + @ox
        sprite.y = rand(SCREEN_RESOLUTION[0] + 200) - 200 + @oy
        sprite.opacity = 160 + rand(96)
      end
    end
  end
 
end
#===============================================================================
# ** Game_Screen
#===============================================================================
class Game_Screen
  #--------------------------------------------------------------------------
  # * Set Weather
  #     type : type
  #     power : strength
  #     duration : time
  #--------------------------------------------------------------------------
  def weather(type, power, duration)
    @weather_type_target = type
    if @weather_type_target != 0
      @weather_type = @weather_type_target
    end
    if @weather_type_target == 0
      @weather_max_target = 0.0
    else
      num = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 76800.0
      @weather_max_target = (power + 1) * num
    end
    @weather_duration = duration
    if @weather_duration == 0
      @weather_type = @weather_type_target
      @weather_max = @weather_max_target
    end
  end
 
end

end # if WEATHER_ADJUSTMENT
#===============================================================================
# ** Spriteset_Map
#===============================================================================
class Spriteset_Map

  alias init_for_centered_small_maps initialize
  #---------------------------------------------------------------------------
  # Resize and reposition viewport so that it fits smaller maps
  #---------------------------------------------------------------------------
  def initialize
    @center_offsets = [0,0]
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      x = (SCREEN_RESOLUTION[0] - $game_map.width * 32) / 2
    else
      x = 0
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      y = (SCREEN_RESOLUTION[1] - $game_map.height * 32) / 2
    else
      y = 0
    end
    init_for_centered_small_maps
    w = [$game_map.width  * 32 , SCREEN_RESOLUTION[0]].min
    h = [$game_map.height * 32 , SCREEN_RESOLUTION[1]].min
    @viewport1.resize(x,y,w,h)
  end
  #---------------------------------------------------------------------------
  # Puts the tilemap update method at the end, ensuring that both
  # @tilemap.ox/oy and @viewport1.ox/oy are set.
  #---------------------------------------------------------------------------
  alias update_tilemap_for_real update
  def update
    update_tilemap_for_real
    @tilemap.draw
  end
end

# The following script will only be enabled if the resolution is bigger than the
# default OR if the game does not want certain maps to wrap around.
if DISABLE_WRAP || SCREEN_RESOLUTION[0] > 640 || SCREEN_RESOLUTION[1] > 480
#--------------------------------------------[Unlimited Resolution by Hime]-----
=begin
#===============================================================================
Title: Unlimited Resolution
Date: Oct 24, 2013
Author: Hime ( ** Modified by KK20 ** )
--------------------------------------------------------------------------------   
Terms of Use
Free
--------------------------------------------------------------------------------
Description

This script modifies Graphics.resize_screen to overcome the 640x480 limitation.
It also includes some modifications to module Graphics such as allowing the
default fade transition to cover the entire screen.

Now you can have arbitrarily large game resolutions.
--------------------------------------------------------------------------------
Credits

Unknown author for overcoming the 640x480 limitation
Lantier, from RMW forums for posting the snippet above
Esrever for handling the viewport
Jet, for the custom Graphics code
FenixFyre, for the Plane class fix
Kaelan, for several bug fixes
--------------------------------------------------------------------------------
KK20 Notes:
- Plane class was rewritten from the original script. Certain lines in the
   unknown scripter's code can be omitted entirely to allow this implementation.
- Likewise, the Viewport class needed new methods to handle this Plane rewrite.
- This entire script only applies to games that go beyond the default 640x480
   resolution.

#===============================================================================
=end
#===============================================================================
# ** Graphics
#===============================================================================
module Graphics
 
  @@super_sprite = Sprite.new
  @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
 
  class << self
   
    def freeze(*args, &block)
      ensure_sprite
      @@super_sprite.bitmap = snap_to_bitmap
    end
   
    def transition(time = 10, filename = nil, vague = nil)
      if filename
        @@super_sprite.bitmap = Bitmap.new(filename)
      end
      @@super_sprite.opacity = 255
      incs = 255.0 / time
      time.times do |i|
        @@super_sprite.opacity = 255.0 - incs * i
        Graphics.wait(1)
      end
      @@super_sprite.bitmap.dispose if @@super_sprite.bitmap
      reform_sprite_bitmap
      Graphics.brightness = 255
    end
   
    def reform_sprite_bitmap
      @@super_sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
      @@super_sprite.bitmap.fill_rect(@@super_sprite.bitmap.rect, Color.new(0, 0, 0, 255))
    end
   
    def fadeout(frames)
      incs = 255.0 / frames
      frames.times do |i|
        i += 1
        Graphics.brightness = 255 - incs * i
        Graphics.wait(1)
      end
    end
   
    def fadein(frames)
      incs = 255.0 / frames
      frames.times do |i|
        Graphics.brightness = incs * i
        Graphics.wait(1)
      end
    end

    def brightness=(i)
      @@super_sprite.opacity = 255.0 - i
    end
   
    def brightness
      255 - @@super_sprite.opacity
    end
   
    def ensure_sprite
      if @@super_sprite.disposed?
        @@super_sprite = Sprite.new
        @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
        reform_sprite_bitmap
      end
    end
   
    # XP does not have a snap_to_bitmap method built-in
    unless XPACE
      define_method(:width)  { Resolution.size.at(0) }
      define_method(:height) { Resolution.size.at(1) }
      #--------------------------------------------------------------------------
      # * snap_to_bitmap
      #--------------------------------------------------------------------------
      def snap_to_bitmap
        @window      ||= Win32API.new('user32','GetActiveWindow', '', 'L')
        @getdc       ||= Win32API.new('user32','GetDC','i','i')
        @ccdc        ||= Win32API.new('gdi32','CreateCompatibleDC','i','i')
        @selectobject||= Win32API.new('gdi32','SelectObject','ii','i')
        @deleteobject||= Win32API.new('gdi32','DeleteObject','i','i')
        @setdibits   ||= Win32API.new('gdi32','SetDIBits','iiiiipi','i')
        @getdibits   ||= Win32API.new('gdi32','GetDIBits','iiiiipi','i')
        @bitblt      ||= Win32API.new('gdi32','BitBlt','iiiiiiiii','i')
        @ccbitmap    ||= Win32API.new('gdi32','CreateCompatibleBitmap','iii','i')
       
        bitmap = Bitmap.new(w = Graphics.width,h = Graphics.height)
        @deleteobject.call(@selectobject.call((hDC = @ccdc.call((dc = @getdc.call(@window.call)))),(hBM = @ccbitmap.call(dc,w,h))))
        @setdibits.call(hDC, hBM, 0, h, (a = bitmap.address), (info = [40,w,h,1,32,0,0,0,0,0,0].pack('LllSSLLllLL')), 0)
        @bitblt.call(hDC, 0, 0, w, h, dc, 0, 0, 0xCC0020)
        @getdibits.call(hDC, hBM, 0, h, a, info, 0)
        @deleteobject.call(hBM)
        @deleteobject.call(hDC)
        return bitmap
      end 
   
      def wait(frame=1)
        frame.times {|s| update }
      end
    end
 
# Graphics.resize_screen is only for XPA games
if XPACE
    #-----------------------------------------------------------------------------
    # Unknown Scripter. Copied from http://pastebin.com/sM2MNJZj
    #-----------------------------------------------------------------------------
    alias :th_large_screen_resize_screen :resize_screen
    def resize_screen(width, height)
      wt, ht = width.divmod(32), height.divmod(32)
      #wt.last + ht.last == 0 || fail('Incorrect width or height')
      #wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ }
      wh = lambda {|w,h,off| [w + off, h + off].pack('l2').scan(/.{4}/) }
      w, h     = wh.call(width, height,0)
      ww, hh   = wh.call(width, height, 32)
      www, hhh = wh.call(wt.first.succ, ht.first.succ,0)
      base = 0x10000000  # fixed?
      #mod = -> adr, val { DL::CPtr.new(base + adr)[0, val.size] = val }
      mod = lambda {|adr,val| (DL::CPtr.new(base + adr))[0, val.size] = val}
      # Didn't see anything happen here
  #    mod.(0x195F, "\x90" * 5)  # ???
  #    mod.(0x19A4, h)
  #    mod.(0x19A9, w)
  #    mod.(0x1A56, h)
  #    mod.(0x1A5B, w)
   
      # The following four seem to change the window size. But I dunno why there
      # are two. I commented out a pair of them but they still do the same thing.
      mod.call(0x20F6, w) && mod.call(0x20FF, w)     
      mod.call(0x2106, h) && mod.call(0x210F, h) 
     
      # speed up y?
      #mod.(0x1C5E3, h) ##
      #mod.(0x1C5E8, w) ##
      #zero = [0].pack ?l
      zero = [0].pack(?l)
     
      # Without these, I can use the default Plane class
  #    mod.(0x1C5E3, zero)
  #    mod.(0x1C5E8, zero)
   
      # And not sure what these do
  #    mod.(0x1F477, h)
  #    mod.(0x1F47C, w)
  #    mod.(0x211FF, hh)
  #    mod.(0x21204, ww)
  #    mod.(0x21D7D, hhh[0])
  #    mod.(0x21E01, www[0])
  #    mod.(0x10DEA8, h)
  #    mod.(0x10DEAD, w)
  #    mod.(0x10DEDF, h)
  #    mod.(0x10DEF0, w)
  #    mod.(0x10DF14, h)
  #    mod.(0x10DF18, w)
  #    mod.(0x10DF48, h)
  #    mod.(0x10DF4C, w)
  #    mod.(0x10E6A7, w)
  #    mod.(0x10E6C3, h)
  #    mod.(0x10EEA9, w)
  #    mod.(0x10EEB9, h)
      th_large_screen_resize_screen(width, height)
    end
   
  end # class << self
 
end # if XPACE

end
#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :parent, :children
 
  alias init_children_vps initialize
  def initialize(*args)
    @children = []
    @parent = false
    init_children_vps(*args)
  end
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias flash_parent flash
  def flash(color, duration)
    if @parent
      @children.each{|child| child.flash_parent(color, duration)}
    else
      flash_parent(color, duration)
    end
  end
 
  alias update_parent update
  def update
    @children.each{|child| child.update} if @parent
    update_parent
  end
 
  alias resize_trigger resize
  def resize(*args)
    @children.each{|child| child.resize_trigger(*args)} if @parent
    resize_trigger(*args)
  end
 
  alias set_trigger_vp_ox ox=
  def ox=(nx)
    return if self.ox == nx
    set_trigger_vp_ox(nx)
    @children.each{|child| child.ox = nx}
  end
 
  alias set_trigger_vp_oy oy=
  def oy=(ny)
    return if self.oy == ny
    set_trigger_vp_oy(ny)
    @children.each{|child| child.oy = ny}
  end
 
  alias tone_parent tone=
  def tone=(t)
    if @parent
      @children.each{|child| child.tone_parent(t)}
    else
      tone_parent(t)
    end
  end

end
#===============================================================================
# ** Plane
#===============================================================================
class Plane
  attr_accessor :offset_x, :offset_y
 
  alias parent_initialize initialize
  def initialize(viewport=nil,parent=true)
    @parent = parent
    @children = []
    parent_initialize(viewport)
    @offset_x = 0
    @offset_y = 0
    # If the parent Plane object; but don't make more children if already have
    # some. This occurs in Spriteset_Map when initializing the Panorama and Fog
    if @parent && viewport
      viewport.parent = true
      create_children
    end
  end
 
  def create_children
    gw = [SCREEN_RESOLUTION[0], $game_map.width * 32].min
    gh = [SCREEN_RESOLUTION[1], $game_map.height * 32].min
    w = (gw - 1) / 640
    h = (gh - 1) / 480
    for y in 0..h
      for x in 0..w
        # This is the top-left default/parent Plane, so skip it
        #next if x == 0 && y == 0
        # Create viewport unless it already exists
        width = w > 0 && x == w ? gw - 640 : 640
        height = h > 0 && y == h ? gh - 480 : 480
        vp = Viewport.new(x * 640, y * 480, width, height, true)
        vp.offset_x = x * 640
        vp.offset_y = y * 480
        # Have to do this in order to prevent overlapping with the parent
        # (for Spriteset_Map viewport1 mainly)
        vp.z = self.viewport.z - 1
        self.viewport.children.push(vp)
        # Create the child Plane
        plane = Plane.new(vp,false)
        plane.offset_x = x * 640
        plane.ox = 0
        plane.offset_y = y * 480
        plane.oy = 0
        # Push to array
        @children.push(plane)
      end
    end
  end
 
  # For the remaining Plane properties, if the parent changes, so do its children
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias zoom_x_parent zoom_x=
  def zoom_x=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_x_parent(new_val)} if @parent
    zoom_x_parent(new_val)
  end
 
  alias zoom_y_parent zoom_y=
  def zoom_y=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_y_parent(new_val)} if @parent
    zoom_y_parent(new_val)
  end
 
  alias ox_parent ox=
  def ox=(new_val)
    @children.each{|child| child.ox = new_val} if @parent
    ox_parent(new_val + @offset_x)
  end
 
  alias oy_parent oy=
  def oy=(new_val)
    @children.each{|child| child.oy = new_val} if @parent
    oy_parent(new_val + @offset_y)
  end
 
  alias bitmap_parent bitmap=
  def bitmap=(new_val)
    @children.each{|child| child.bitmap_parent(new_val)} if @parent
    #bitmap_parent(new_val)
  end
 
  alias visible_parent visible=
  def visible=(new_val)
    @children.each{|child| child.visible_parent(new_val)} if @parent
    visible_parent(new_val)
  end
 
  alias z_parent z=
  def z=(new_val)
    # Because the children spawn new Viewports, they have to be lower than the
    # parent's viewport to prevent drawing OVER the parent...unless the Plane's
    # z-value is more than zero, in which case the children viewports NEED to be
    # higher than the parent's. By doing this, we can have panoramas be below
    # the tilemap and fogs be over the tilemap.
    if @parent && @children[0]
      child = @children[0]
      if new_val > 0 && child.viewport.z < self.viewport.z
        @children.each{|child| child.viewport.z += 1}
      elsif new_val <= 0 && child.viewport.z >= self.viewport.z
        @children.each{|child| child.viewport.z -= 1}
      end
    end
   
    @children.each{|child| child.z_parent(new_val)} if @parent
    z_parent(new_val)
  end
 
  alias opacity_parent opacity=
  def opacity=(new_val)
    @children.each{|child| child.opacity_parent(new_val)} if @parent
    opacity_parent(new_val)
  end
 
  alias color_parent color=
  def color=(new_val)
    if @parent
      @children.each{|child| child.color_parent(new_val)}
    else
      color_parent(new_val)
    end
  end
 
  alias blend_type_parent blend_type=
  def blend_type=(new_val)
    @children.each{|child| child.blend_type_parent(new_val)} if @parent
    blend_type_parent(new_val)
  end
 
  alias tone_parent tone=
  def tone=(new_val)
    if @parent
      @children.each{|child| child.tone_parent(new_val)}
    else
      tone_parent(new_val)
    end
  end
 
end
#------------------------------------------[End of Unlimited Resolution]--------
end

# Resize the game window (if using XP) and load the MapInfos file
Resolution.resize_game unless XPACE
XPAT_MAP_INFOS = load_data("Data/MapInfos.rxdata")

Added the Viewport#flash fix.
Child viewport thing I mentioned at the top of this page is implemented. Tone changes look correct now.
Added Drago's XP compatibility methods.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 26, 2017, 02:43:03 am
and the result is...

(http://i.imgur.com/YKtzoWPs.jpg) (http://i.imgur.com/YKtzoWP.jpg)
http://i.imgur.com/YKtzoWP.jpg
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 26, 2017, 03:32:10 am

=begin
================================================================================
XPA Tilemap                                                      Version 0.32
by KK20                                                          25 Feb 2017
________________________________________________________________________________

[ Version History ]

Ver.      Date            Notes
-----     -----------     ----------------------------------------------------
0.32  ... 25 Feb 2017 ... Bug fixes:
                            - Child viewports were having display issues when
                              tone changes were involved
                            - Viewport#flash had missing parameters
                            - Added more compatibility for XP games (thanks
                              LiTTleDRAgo!)
0.31  ... 08 Feb 2017 ... Bug fixes:
                            - Bad logic with border sprites for non-wrapping map
                            - Problem with Plane objects not initialized with a
                              viewport, causing children-creation to crash
                            - Disable Graphics.resize_screen in Hime's script
                              for XP games as this method does not exist nor is
                              the code necessary to "break" the resolution limit
                            - RGSS does not support Array#cover?
                           Changes:
                            - The Resolution module is disabled for XPA
                            - If WEATHER_ADJUSTMENT is false, it will disable
                              all of the RPG::Weather and Game_Screen classes
                              from loading rather than only some methods
                            - Input module for supporting different game window
                              sizes is disabled for XP as this feature does not
                              work in RGSS
0.3   ... 04 Feb 2017 ... Bug fixes:
                            - A graphical bug involving priority tiles if the
                              MAX_PRIORITY_LAYERS is set to less than 5
                            - Loading autotiles in RPG::Cache has been revised
                              for better compatibility
                            - CallBackController added to replace the method
                              implemented in v0.2b which prevented saving games
                           Additions:
                            - Commented out a majority of the anonymous scripter
                              code that breaks the resolution limit for RGSS3;
                              its ramifications are unknown at this point
                            - A new Plane rewrite which is merely just creating
                              more Plane objects
                            - Maps that do not wrap have a high z-level black
                              sprite positioned around the map's borders
                            - New fullscreen and other window size options for
                              XPA games (will not work for XP)
                            - Tilesets that are not divisible by 32 will raise
                              an error rather than crash
                            - Maps with invalid tile ID's (caused when a tile
                              was placed with a taller tileset graphic, but then
                              the map uses a shorter tileset) no longer crash
                              the game
0.13b ... 23 Oct 2016 ... Bug fixes:
                            - Resolutions not divisible by 32 would not show the
                              last row/column of tiles entirely
                           ** Fix added on top of v0.12b, not v0.2b, but is
                           ** included in all versions above this one
0.2b  ... 07 Jun 2016 ... Bug fixes:
                            - Shaking still had issues
                           Additions:
                            - Maps can now wrap by putting [WRAP] in the map
                              name, due to a new way of drawing the map
                            - ...which also fixed the shaking above
                            - ...and can also allow vertical shaking
                            - Added Unlimited Resolution, an RMVXA script with
                              some changes
                            - Changing tileset and autotile bitmaps in-game will
                              not crash (assuming you know how to do that)
                            - Overall cleaning of code
0.12b ... 27 Feb 2016 ... Bug fixes:
                            - Tiles with some transparency and priority were
                              being redrawn continuously on each other
                            - Setting the Plane bitmap to nil would crash
0.11b ... 03 Nov 2014 ... Bug fixes:
                            - Table did not take in parameters upon initialize
                            - Centering of maps now shrinks Viewport sizes
                            - Fixed Tilemap#oy= logic
0.1b  ... 02 Nov 2014 ... Initial release
________________________________________________________________________________

[ Introduction ]

In light of recent discoveries regarding the usage of RGSS3 in RPG Maker XP
games, many users were left with a dilemma in choosing which Tilemap rewrite to
use due to the vast differences between RGSS1's and RGSS3's Tilemap classes
that would cause complications in this transition. I aimed to find the best
Tilemap rewrite and decided that I would have to make my own. Like every other
Tilemap rewrite before it, this implementation is in no ways perfect, boasting
PROs and CONs.

This script is intended to be used for RPG Maker XP games using the RGSS3
library (unofficially coined RPG Maker XP Ace); however, it is entirely
compatible with RPG Maker XP games in the RGSS1 library.
________________________________________________________________________________

[ License ]

This work is protected by the following license:
http://creativecommons.org/licenses/by-nc-sa/3.0/

********************************************************************************

You are free:

to Share - to copy, distribute and transmit the work
to Remix - to adapt the work

Under the following conditions:

Attribution:
You must attribute the work in the manner specified by the author or licensor,
but not in any way that suggests that they endorse you or your use of the work.

Noncommercial:
You may not use this work for commercial purposes.

Share alike:
If you alter, transform, or build upon this work, you may distribute the
resulting work only under the same or similar license to this one.

- For any reuse or distribution, you must make clear to others the license terms
  of this work. The best way to do this is with a link to this web page.

- Any of the above conditions can be waived if you get permission from the
  copyright holder.

- Nothing in this license impairs or restricts the author's moral rights.

********************************************************************************

[ Instructions ]

- Place this script below the default scripts but above Main.
- Move 'XPATilemap.dll' into your project folder (same directory as 'Game.exe')
- Configure values at the start of the script
________________________________________________________________________________

[ Features ]

About the script:
- XP and XPA (RGSS1 and RGSS3) compatible, though designed for XPA
- Define your own custom resolution
- Adds new tilemap features
- Maps that are smaller than the game resolution are automatically centered
- Drawing methods written in C-language, which has faster pixel-by-pixel
   operations than Ruby

Add-ons:
- Customize frame rate animation and define unique patterns for your autotiles
- Remove unnecessary priority layers to boost frames-per-second (FPS)
- Extend the default RPG::Weather class to fit larger screens, or not
- Change the way fullscreen works (or disable it), including a double and half-
   size window option (only for XPA)
- more to add later...
________________________________________________________________________________

[ Compatibility ]

- There have been reports of Screen Flash not working for some users, though I
   have yet to receive any valid proof or ways to reproduce this issue
- Your tileset must have dimensions divisible by 32. The game will raise an
   error otherwise.
________________________________________________________________________________

[ Credits ]

KK20 - Author of this script and DLL
Blizzard - Tester and providing bug fixes
LiTTleDRAgo - Reusing code from his edits to Custom Resolution and bug fixes
Zexion - Tester and morale support
ForeverZer0 - Reusing code from his Custom Resolution script, found here:
                http://forum.chaos-project.com/index.php/topic,7814.0.html
________________________________________________________________________________

[ Contact ]

To contact the author of this script, please visit
                http://forum.chaos-project.com/index.php
               
or send an email to
                        tscrane20@gmail.com
                       
================================================================================
=end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                       B E G I N   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#-------------------------------------------------------------------------------
# The game window's screen resolution. RPG Maker XP's default is [640, 480].
# Do note that a larger resolution is prone to sprite lag.
# Anything larger than the default resolution will enable the custom Plane class.
#-------------------------------------------------------------------------------
SCREEN_RESOLUTION = [1024, 768]

#-------------------------------------------------------------------------------
# The largest level of priority your game uses. This value should be between
# 1 and 5. If using a large resolution, lowering the number of priority layers
# will help in reducing the lag.
#-------------------------------------------------------------------------------
MAX_PRIORITY_LAYERS = 5

#-------------------------------------------------------------------------------
# If using a larger resolution than 640x480, the default weather effects will
# not cover the entire map. It is recommended that you set this to true to
# compensate for that, unless you are using some custom weather script that can
# address this.
#-------------------------------------------------------------------------------
WEATHER_ADJUSTMENT = false

#-------------------------------------------------------------------------------
# When the map's display_x/y variables extend beyond its borders, the map wraps
# around to fill in the gaps. Setting this to true will prevent that, showing
# black borders instead.
# If you want some maps to wrap around, putting [WRAP] in a map's name will
# allow this.
# Note that the custom Plane class will be enabled in order to create this
# effect regardless of your resolution size.
#-------------------------------------------------------------------------------
DISABLE_WRAP = false

#-------------------------------------------------------------------------------
# Choose a form of fullscreen for your game. The available choices are:
#  0 = Default RPG Maker fullscreen (changes monitor resolution to 640x480)
#  1 = Stetches game window to player's monitor size (only for XPA)
#  2 = Disable the ability to go into fullscreen
# Please note that if you choose anything other than 0, it disables everything
# on the player's computer from being able to use ALT + ENTER.
#-------------------------------------------------------------------------------
FULLSCREEN_METHOD = 0

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 2x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
TWICE_SIZE_BUTTON = Input::F5

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 0.5x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
HALF_SIZE_BUTTON = Input::F6

#-------------------------------------------------------------------------------
# Set the animation frame rate for autotiles. By default, all autotiles will
# update on the 16th frame. You can change that by providing an array of numbers
# that represent how many frames that particular frame of animation will be
# visible for.
# Format:
#   when AUTOTILE_FILENAME then FRAME_DATA
# where FRAME_DATA is an array containing the number of frames that particular
# animation will play for before moving onto the next frame. Be sure to match
# the number of autotile animation frames with the number of elements you put
# into the array.
# Check the examples below.
#-------------------------------------------------------------------------------
def autotile_framerate(filename)
  case filename
  #------------------------------------------------------ START ------
  when '001-G_Water01' then [8, 8, 8, 8]      # Animates twice as fast
  when '009-G2_Water01' then [20, 20, 20, 20] # Animates a bit slower
  when '024-Ocean01' then [32, 16, 32, 16]    # Sine wave effect
  #------------------------------------------------------- END -------
  # Don't touch any of this below
  else
    return nil if filename == ''
    # Generates array of [16, 16, ...] based on autotile width
    # (or nil if not animating autotile)
    w = RPG::Cache.autotile(filename).width
    h = RPG::Cache.autotile(filename).height
    if (h == 32 && w / 32 == 1) || (h == 192 && w / 256 == 1)
      return nil
    else
      return h == 32 ? Array.new(w/32){|i| 16} : Array.new(w/256){|i| 16}
    end
  end
end

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                           E N D   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FULLSCREEN_METHOD = 0 unless FULLSCREEN_METHOD.between?(0,2)
if FULLSCREEN_METHOD != 0
  # Disable ALT+Enter
  reghotkey = Win32API.new('user32', 'RegisterHotKey', 'LIII', 'I')
  reghotkey.call(0, 1, 1, 0x0D)
end

XPACE = RUBY_VERSION == "1.9.2"

MAX_PRIORITY_LAYERS = 5 unless (1..5).include?(MAX_PRIORITY_LAYERS)

if XPACE
#===============================================================================
# ** Input
#===============================================================================
module Input

  GetActiveWindow = Win32API.new('user32', 'GetActiveWindow', '', 'L')
  SetWindowLong = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
  SetWindowPos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
  GetSystemMetrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
  GetAsyncKeyState = Win32API.new('user32', 'GetAsyncKeyState', 'I', 'I')
 
  @fullscreenKeysReleased = true
  @current_state = 0
  NORMAL_STATE     = 0
  FULLSCREEN_STATE = 1
  TWICESIZE_STATE  = 2
  HALFSIZE_STATE   = 3
 
  class << self
    alias get_fullscreen_keys update
   
    # Check for window resize buttons
    def update
      enterkey_state = GetAsyncKeyState.call(0x0D)
      # If ALT+ENTER was pressed, but only for modified fullscreen
      if FULLSCREEN_METHOD == 1 && @fullscreenKeysReleased && Input.press?(Input::ALT) && enterkey_state != 0
        @current_state = @current_state == FULLSCREEN_STATE ? NORMAL_STATE : FULLSCREEN_STATE
        @fullscreenKeysReleased = false
        # Changing game window to fullscreen
        if @current_state == FULLSCREEN_STATE
          full_screen_size
        else
          normal_screen_size
        end
      # If button to double the normal window size was pressed
      elsif TWICE_SIZE_BUTTON && Input.trigger?(TWICE_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to double or normalize the window
        @current_state = @current_state == TWICESIZE_STATE ? NORMAL_STATE : TWICESIZE_STATE
        if @current_state == TWICESIZE_STATE
          double_screen_size
        else
          normal_screen_size
        end
      # If button to halve the normal window size was pressed
      elsif HALF_SIZE_BUTTON && Input.trigger?(HALF_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to halve or normalize the window
        @current_state = @current_state == HALFSIZE_STATE ? NORMAL_STATE : HALFSIZE_STATE
        if @current_state == HALFSIZE_STATE
          half_screen_size
        else
          normal_screen_size
        end
      else
        # Check if ALT or ENTER is released
        @fullscreenKeysReleased = (!Input.press?(Input::ALT) || enterkey_state == 0)
      end
      # Call the alias
      get_fullscreen_keys
    end
   
    # Doubles the window size based on SCREEN_RESOLUTION.
    def double_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] * 2
      nh = SCREEN_RESOLUTION[1] * 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Halves the window size based on SCREEN_RESOLUTION.
    def half_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] / 2
      nh = SCREEN_RESOLUTION[1] / 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Makes game window as large as the monitor's resolution
    def full_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x10000000)
      SetWindowPos.call(GetActiveWindow.call, 0, 0, 0, rw, rh, 0)
    end
   
    # Reverts the game window back to normal size
    def normal_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      x = (rw - SCREEN_RESOLUTION[0]) / 2
      y = (rh - SCREEN_RESOLUTION[1]) / 2
      w = SCREEN_RESOLUTION[0] + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = SCREEN_RESOLUTION[1] + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Simulates the key press of ALT+Enter; called if we need to get in or out
    # of fullscreen even though the player did not press these keys
    def simulate_alt_enter
      keybd = Win32API.new 'user32.dll', 'keybd_event', ['i', 'i', 'l', 'l'], 'v'
      keybd.call(0xA4, 0, 0, 0)
      keybd.call(13, 0, 0, 0)
      keybd.call(13, 0, 2, 0)
      keybd.call(0xA4, 0, 2, 0)
    end
   
    # Check if the game is in default fullscreen
    def fullscreen?
      # We're not using default fullscreen, so this should always be false
      return false if FULLSCREEN_METHOD != 0
      # If current monitor resolution is 640x480, then it is fullscreen
      if GetSystemMetrics.call(0) == 640 && GetSystemMetrics.call(1) == 480
        @current_state = FULLSCREEN_STATE
        return true
      end
    end
   
  end
end

end # if XPACE

if !XPACE
#===============================================================================
# ** Resolution
#===============================================================================
module Resolution
 
  def self.resize_game
    # Set instance variables for calling basic Win32 functions.
    ini = Win32API.new('kernel32', 'GetPrivateProfileStringA','PPPPLP', 'L')
    title = "\0" * 256
    ini.call('Game', 'Title', '', title, 256, '.\\Game.ini')
    title.delete!("\0")
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
    set_window_long = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
    set_window_pos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
    @metrics         = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
    # Set default size, displaying error if size is larger than the hardware.
    default_size = Resolution.size
    # Apply resolution change.
    x = (@metrics.call(0) - SCREEN_RESOLUTION[0]) / 2
    y = (@metrics.call(1) - SCREEN_RESOLUTION[1]) / 2
    set_window_long.call(@window, -16, 0x14CA0000)
    set_window_pos.call(@window, 0, x, y, SCREEN_RESOLUTION[0] + 6, SCREEN_RESOLUTION[1] + 26, 0)
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
  end
  #--------------------------------------------------------------------------
  def self.size
    # Returns the screen size of the machine.
    [@metrics.call(0), @metrics.call(1)]
  end
  #--------------------------------------------------------------------------
end

end # if !XPACE

#===============================================================================
# ** NilClass
#===============================================================================
class NilClass
  unless method_defined?(:dispose)
    def dispose; end
    def disposed?; end
  end
end
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
  attr_accessor :filename
  alias set_filename_of_bitmap initialize
  def initialize(*args)
    # Associate the bitmap with the filename of the graphic; empty string otherwise
    @filename = args.size == 1 ? File.basename(args[0], '.*') : ''
    set_filename_of_bitmap(*args)
  end
end
#===============================================================================
# ** RPG::Cache
#===============================================================================
module RPG::Cache
 
  AUTO_INDEX = [
 
  [27,28,33,34],  [5,28,33,34],  [27,6,33,34],  [5,6,33,34],
  [27,28,33,12],  [5,28,33,12],  [27,6,33,12],  [5,6,33,12],
  [27,28,11,34],  [5,28,11,34],  [27,6,11,34],  [5,6,11,34],
  [27,28,11,12],  [5,28,11,12],  [27,6,11,12],  [5,6,11,12],
  [25,26,31,32],  [25,6,31,32],  [25,26,31,12], [25,6,31,12],
  [15,16,21,22],  [15,16,21,12], [15,16,11,22], [15,16,11,12],
  [29,30,35,36],  [29,30,11,36], [5,30,35,36],  [5,30,11,36],
  [39,40,45,46],  [5,40,45,46],  [39,6,45,46],  [5,6,45,46],
  [25,30,31,36],  [15,16,45,46], [13,14,19,20], [13,14,19,12],
  [17,18,23,24],  [17,18,11,24], [41,42,47,48], [5,42,47,48],
  [37,38,43,44],  [37,6,43,44],  [13,18,19,24], [13,14,43,44],
  [37,42,43,48],  [17,18,47,48], [13,18,43,48], [13,18,43,48]
   
  ]
 
  def self.autotile(filename)
    key = "Graphics/Autotiles/#{filename}"
    if !@cache.include?(key) || @cache[key].disposed?
      # Load the autotile graphic.
      new_bm = self.load_bitmap('Graphics/Autotiles/', filename)
      # Cache each configuration of this autotile.
      new_bm = self.format_autotiles(new_bm, filename)
      @cache[key].dispose
      @cache[key] = new_bm
    end
    @cache[key]
  end

  def self.format_autotiles(bitmap, filename)
    if bitmap.height > 32 && bitmap.height < 256
      frames = bitmap.width / 96
      template = Bitmap.new(256*frames,192)
      template.filename = filename
      # Create a bitmap to use as a template for creation.
      (0..frames-1).each{|frame|
      (0...6).each {|i| (0...8).each {|j| AUTO_INDEX[8*i+j].each {|number|
        number -= 1
        x, y = 16 * (number % 6), 16 * (number / 6)
        rect = Rect.new(x + (frame * 96), y, 16, 16)
        template.blt((32 * j + x % 32) + (frame * 256), 32 * i + y % 32, bitmap, rect)
      }}}}
      return template
    else
      return bitmap
    end
  end
 
end
#===============================================================================
# ** CallBackController
#===============================================================================
module CallBackController
  @@callback = {}
 
  def self.setup_callback(obj, proc)
    @@callback[obj.object_id] = proc
  end
 
  def self.call(obj, *args)
    @@callback[obj.object_id].call(*args) if @@callback[obj.object_id]
    true
  end
 
  def self.delete(obj)
    @@callback.delete(obj.object_id)
  end
 
end

#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :offset_x, :offset_y
 
  alias zer0_viewport_resize_init initialize
  def initialize(x=0, y=0, width=SCREEN_RESOLUTION[0], height=SCREEN_RESOLUTION[1], override=false)
    # Variables needed for Viewport children (for the Plane rewrite); ignore if
    # your game resolution is not larger than 640x480
    @offset_x = @offset_y = 0
    if x.is_a?(Rect)
      # If first argument is a Rectangle, just use it as the argument.
      zer0_viewport_resize_init(x)
    elsif [x, y, width, height] == [0, 0, 640, 480] && !override
      # Resize fullscreen viewport, unless explicitly overridden.
      zer0_viewport_resize_init(Rect.new(0, 0, SCREEN_RESOLUTION[0], SCREEN_RESOLUTION[1]))
    else
      # Call method normally.
      zer0_viewport_resize_init(Rect.new(x, y, width, height))
    end
  end
 
  def resize(*args)
    # Resize the viewport. Can call with (X, Y, WIDTH, HEIGHT) or (RECT).
    if args[0].is_a?(Rect)
      args[0].x += @offset_x
      args[0].y += @offset_y
      self.rect = args[0]
    else
      args[0] += @offset_x
      args[1] += @offset_y
      self.rect = Rect.new(*args)
    end
  end
end

#===============================================================================
# ** Tilemap
#===============================================================================
class Tilemap
 
  attr_accessor :tileset, :autotiles, :map_data, :priorities, :ground_sprite
  attr_reader :wrapping
  #---------------------------------------------------------------------------
  # Initialize
  #---------------------------------------------------------------------------
  def initialize(viewport = nil)
    @viewport = viewport
    @layer_sprites = []
    @autotile_frame = []      #[[ANIMATION_DRAW_INDEX, CURRENT_LOGICAL_FRAME], ... ]
    @autotile_framedata = []  #[[DATA_FROM_CONFIGURATION_ABOVE], ... ]
   
    # Ensures that the bitmap width accounts for an extra tile
    # and is divisible by 32
    bitmap_width = ((SCREEN_RESOLUTION[0] / 32.0).ceil + 1) * 32
    # Create the priority layers
    ((SCREEN_RESOLUTION[1]/32.0).ceil + MAX_PRIORITY_LAYERS).times{ |i|
      s = Sprite.new(@viewport)
      s.bitmap = Bitmap.new(bitmap_width, MAX_PRIORITY_LAYERS * 32)
      @layer_sprites.push(s)
    }
   
    # Same reasons as bitmap_width, but for height
    bitmap_height = ((SCREEN_RESOLUTION[1] / 32.0).ceil + 1) * 32
    # Create the ground layer (priority 0)
    s = Sprite.new(@viewport)
    s.bitmap = Bitmap.new(bitmap_width, bitmap_height)
    @ground_sprite = s
    @ground_sprite.z = 0

    # Initialize remaining variables
    @redraw_tilemap = true
    @tileset = nil
    @autotiles = []
    proc = Proc.new { |x,y| @redraw_tilemap = true; setup_autotile(x) }
    CallBackController.setup_callback(@autotiles, proc)
   
    @map_data = nil
   
    @priorities = nil
    @old_ox = 0
    @old_oy = 0
    @ox = 0
    @oy = 0
    @ox_float = 0.0
    @oy_float = 0.0
    @shift = 0
    @wrapping = (!DISABLE_WRAP || (XPAT_MAP_INFOS[$game_map.map_id].name =~ /.*\[[Ww][Rr][Aa][Pp]\].*/) == 0) ? 1 : 0
    create_border_sprites
   
    # Set up the DLL calls
    @@update = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap2', 'pppp', 'i')
    @@autotile_update = Win32API.new('XPA_Tilemap', 'UpdateAutotiles', 'pppp', 'i')
    @@initial_draw = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap', 'pppp', 'i')
    @empty_tile = Bitmap.new(32,32)
    Win32API.new('XPA_Tilemap','InitEmptyTile','l','i').call(@empty_tile.object_id)
    @black_tile = Bitmap.new(32,32)
    @black_tile.fill_rect(0,0,32,32,Color.new(0,0,0))
    Win32API.new('XPA_Tilemap','InitBlackTile','l','i').call(@black_tile.object_id)
   
  end
  #---------------------------------------------------------------------------
  # Setup autotile animation data
  #---------------------------------------------------------------------------
  def setup_autotile(i)
    # Get animation frame rate of the autotile
    bitmap = @autotiles[i]
    frames = bitmap.nil? ? nil : autotile_framerate(bitmap.filename)
    # If autotile doesn't animate
    if frames.nil?
      @autotile_frame[i] = [0,0]
      @autotile_framedata[i] = nil
    else
      # Save the frame rate data
      @autotile_framedata[i] = frames
      # Determine how long one animation cycle takes and indicate at what time
      # the next frame of animation occurs
      total = 0
      frame_checkpoints = []
     
      frames.each_index{|j| f = frames[j]
        total += f
        frame_checkpoints[j] = total
      }
      # Get animation frame for this autotile based on game time passed
      current_frame = Graphics.frame_count % total
      frame_checkpoints.each_index{|j| c = frame_checkpoints[j]
        next if c.nil?
        if c > current_frame
          @autotile_frame[i] = [j, c - current_frame]
          break
        end
      }
    end
  end
  #---------------------------------------------------------------------------
  # Creates four 32-pixel thick black sprites to surround the map. This is
  # only applied to maps that do not have wrapping enabled. This helps those
  # who have screen shaking in their maps.
  #---------------------------------------------------------------------------
  def create_border_sprites
    @border_sprites = []
    return if @wrapping == 1
    for i in 0..3
      s = Sprite.new(@viewport)
      s.z = 99999
      if i % 2 == 0
        b = Bitmap.new(SCREEN_RESOLUTION[0] + 64,32)
        s.x = -32
        s.y = i == 0 ? -32 : $game_map.height * 32
      else
        b = Bitmap.new(32,SCREEN_RESOLUTION[1] + 64)
        s.x = i == 1 ? -32 : $game_map.width * 32
        s.y = -32
      end
      b.fill_rect(0, 0, b.width, b.height, Color.new(0,0,0))
      s.bitmap = b
      @border_sprites.push(s)
    end
  end
  #---------------------------------------------------------------------------
  # Dispose tilemap
  #---------------------------------------------------------------------------
  def dispose
    @layer_sprites.each{|sprite| sprite.dispose}
    @ground_sprite.dispose
    @border_sprites.each{|sprite| sprite.dispose}
  end
  #---------------------------------------------------------------------------
  # Check if disposed tilemap
  #---------------------------------------------------------------------------
  def disposed?
    @layer_sprites[0].disposed?
  end
  #---------------------------------------------------------------------------
  # Get viewport
  #---------------------------------------------------------------------------
  def viewport
    @viewport
  end
  #---------------------------------------------------------------------------
  # Return if tilemap is visible
  #---------------------------------------------------------------------------
  def visible
    layer_sprites[0].visible
  end
  #---------------------------------------------------------------------------
  # Show or hide tilemap
  #---------------------------------------------------------------------------
  def visible=(bool)
    @layer_sprites.each{|sprite| sprite.visible = bool}
    @ground_sprite.visible = bool
  end
  #---------------------------------------------------------------------------
  # Set tileset
  #---------------------------------------------------------------------------
  def tileset=(bitmap)
    @tileset = bitmap
    if @tileset.width % 32 != 0 || @tileset.height % 32 != 0
      file = bitmap.filename
      raise "Your tileset graphic #{file} needs to be divisible by 32!"
    end
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set autotiles
  #---------------------------------------------------------------------------
  def autotiles=(array)
    CallBackController.delete(@autotiles)
    @autotiles = array
    proc = Proc.new { |i| @redraw_tilemap = true; setup_autotile(i) }
    CallBackController.setup_callback(@autotiles, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map data
  #---------------------------------------------------------------------------
  def map_data=(table)
    CallBackController.delete(@map_data)
    @map_data = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@map_data, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map priorities
  #---------------------------------------------------------------------------
  def priorities=(table)
    CallBackController.delete(@priorities)
    @priorities = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@priorities, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Get horizontal shift
  #---------------------------------------------------------------------------
  def ox
    @ox + @ox_float
  end
  #---------------------------------------------------------------------------
  # Get vertical shift
  #---------------------------------------------------------------------------
  def oy
    @oy + @oy_float
  end
  #---------------------------------------------------------------------------
  # Shift tilemap horizontally
  #---------------------------------------------------------------------------
  def ox=(ox)
    @ox_float = (ox - ox.to_i) % 1
    @ox = ox.floor
    @border_sprites.each{ |s|
      next if s.bitmap.height == 32
      s.ox = @ox
    }
  end
  #---------------------------------------------------------------------------
  # Shift tilemap vertically
  #---------------------------------------------------------------------------
  def oy=(oy)
    @oy_float = (oy - oy.to_i) % 1
    @oy = oy.floor
    @border_sprites.each{ |s|
      next if s.bitmap.width == 32
      s.oy = @oy
    }
  end
  #---------------------------------------------------------------------------
  # Update tilemap graphics
  #---------------------------------------------------------------------------
  def update; end;
  def draw
    # Figure out what the new X and Y coordinates for the ground layer would be
    x = @old_ox - @ox
    @old_ox = @ox
    x += @ground_sprite.x

    y = @old_oy - @oy
    @old_oy = @oy
    y += @ground_sprite.y

    # No reason to do sprite shifting if we're just redrawing everything
    if !@redraw_tilemap
      # If layers would be too far to the left
      if x < @viewport.ox - 31
        # If still too far, then force redraw
        if x + 32 < @viewport.ox - 31
          @redraw_tilemap = true
        else
          # Shift all layers right by 32 and clear out left-most column
          x += 32
          @ground_sprite.bitmap.fill_rect(0, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(0, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 1 # Redraw right column bit-flag (0001)
        end
      # If layers would be too far to the right
      elsif x > @viewport.ox
        # If still too far, then force redraw
        if x - 32 > @viewport.ox
          @redraw_tilemap = true
        else
          # Shift all layers left by 32 and clear out right-most column
          x -= 32
          @ground_sprite.bitmap.fill_rect(@ground_sprite.bitmap.width - 32, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(sprite.bitmap.width - 32, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 2 # Redraw left column bit-flag (0010)
        end
      end
      # Apply the change in X to the layers
      if !@redraw_tilemap
        @ground_sprite.x = x
        @layer_sprites.each{|sprite| sprite.x = x}

        # If layers would be too far up
        if y < @viewport.oy - 31
          # If still too far, then force redraw
          if y + 32 < @viewport.oy - 31
            @redraw_tilemap = true
          else
            y += 32
            layer = @layer_sprites.shift
            layer.bitmap.clear
            @layer_sprites.push(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            num = @layer_sprites.size
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[num-index].bitmap.fill_rect(0, (index - 1) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 4 # Redraw bottom row bit-flag (0100)
          end
        # If layers would be too far down
        elsif y > @viewport.oy
          # If still too far, then force redraw
          if y - 32 > @viewport.oy
            @redraw_tilemap = true
          else
            y -= 32
            layer = @layer_sprites.pop
            layer.bitmap.clear
            @layer_sprites.unshift(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[index].bitmap.fill_rect(0, (MAX_PRIORITY_LAYERS - 1 - index) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 8 # Redraw top row bit-flag (1000)
          end
        end
        # Apply the change to layers' Y and Z values
        if !@redraw_tilemap
          @ground_sprite.y = y
          @layer_sprites.each_index{ |i| sprite = @layer_sprites[i]
            sprite.y = y - 32 * (MAX_PRIORITY_LAYERS - 1 - i)
            sprite.z = sprite.y + (192 - (5 - MAX_PRIORITY_LAYERS) * 32)
          }
        end
      end
    end

    autotile_need_update = []
    # Update autotile animation frames
    for i in 0..6
      autotile_need_update[i] = false
      # If this autotile doesn't animate, skip
      next if @autotile_framedata[i].nil?
      # Reduce frame count
      @autotile_frame[i][1] -= 1
      # Autotile requires update
      if @autotile_frame[i][1] == 0
        @autotile_frame[i][0] = (@autotile_frame[i][0] + 1) % @autotile_framedata[i].size
        @autotile_frame[i][1] = @autotile_framedata[i][@autotile_frame[i][0]]
        autotile_need_update[i] = true
      end
    end
   
   
    # Stop the update unless redrawing, there is shifting, or an autotile needs to update
    return unless @redraw_tilemap || @shift != 0 || !autotile_need_update.index(true).nil?

    # Set up the array for the priority layers
    layers = [@layer_sprites.size + 1]
    # Insert higher priority layers into the array in order (least to most y-value sprite)
    @layer_sprites.each{|sprite| layers.push(sprite.bitmap.object_id) }
    # Insert ground layer last in the array
    layers.push(@ground_sprite.bitmap.object_id)
    # Load autotile bitmap graphics into array
    tile_bms = [self.tileset.object_id]
    self.autotiles.each{|autotile| tile_bms.push(autotile.object_id) }
    # Store autotile animation frame data
    autotiledata = []
    for i in 0..6
      autotiledata.push(@autotile_frame[i][0])
      autotiledata.push(autotile_need_update[i] ? 1 : 0)
    end
    # Fills in remaining information of other tilemaps
    misc_data = [@ox + @viewport.ox, @oy + @viewport.oy,
      self.map_data.object_id, self.priorities.object_id, @shift,
      MAX_PRIORITY_LAYERS, @wrapping]
   
    # If forcing fresh redraw of the map (or drawing for first time)
    if @redraw_tilemap
      # Initialize layer sprite positions and clear them for drawing
      @ground_sprite.bitmap.clear
      @ground_sprite.x = (@viewport.ox - @viewport.ox % 32) - (@ox % 32)
      @ground_sprite.x += 32 if @ground_sprite.x < @viewport.ox - 31
      @ground_sprite.y = (@viewport.oy - @viewport.oy % 32) - (@oy % 32)
      @ground_sprite.y += 32 if @ground_sprite.y < @viewport.oy - 31

      y_buffer = 32 * (MAX_PRIORITY_LAYERS - 1)
      z_buffer = MAX_PRIORITY_LAYERS * 32 + 32
      @layer_sprites.each_index{|i| layer = @layer_sprites[i]
        layer.bitmap.clear
        layer.x = @ground_sprite.x
        layer.y = @ground_sprite.y - y_buffer + 32 * i
        layer.z = layer.y + z_buffer
      }
      # Make DLL call
      @@initial_draw.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    elsif @shift != 0
      # Update for shifting
      @@update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Check for autotile updates (at least one autotile needs an update)
    # No need if redrawn tilemap since it already handled the updated autotiles
    if !@redraw_tilemap && !autotile_need_update.index(true).nil?
      @@autotile_update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Turn off flag
    @redraw_tilemap = false
    # Reset shift flag
    @shift = 0
  end
 
end
#===============================================================================
# ** Game_Player
#===============================================================================
class Game_Player
 
  CENTER_X = ((SCREEN_RESOLUTION[0] / 2) - 16) * 4    # Center screen x-coordinate * 4
  CENTER_Y = ((SCREEN_RESOLUTION[1] / 2) - 16) * 4    # Center screen y-coordinate * 4
 
  def center(x, y)
    # Recalculate the screen center based on the new resolution.
    max_x = (($game_map.width - (SCREEN_RESOLUTION[0]/32.0)) * 128).to_i
    max_y = (($game_map.height - (SCREEN_RESOLUTION[1]/32.0)) * 128).to_i
    $game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
    $game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
  end
end
#===============================================================================
# ** Game_Map
#===============================================================================
class Game_Map
  alias zer0_map_edge_setup setup
  def setup(map_id)
    zer0_map_edge_setup(map_id)
    # Find the displayed area of the map in tiles. No calcualting every step.
    @map_edge = [self.width - (SCREEN_RESOLUTION[0]/32.0), self.height - (SCREEN_RESOLUTION[1]/32.0)]
    @map_edge.collect! {|size| size * 128 }
    # Change the map center if map is smaller than the resolution
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      Game_Player.const_set(:CENTER_X, $game_map.width * 128)
    else
      Game_Player.const_set(:CENTER_X, ((SCREEN_RESOLUTION[0] / 2) - 16) * 4)
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      Game_Player.const_set(:CENTER_Y, $game_map.height * 128)
    else
      Game_Player.const_set(:CENTER_Y, ((SCREEN_RESOLUTION[1] / 2) - 16) * 4)
    end
  end

  def scroll_down(distance)
    # Find point that the map edge meets the screen edge, using custom size.
    @display_y = [@display_y + distance, @map_edge[1]].min
  end

  def scroll_right(distance)
    # Find point that the map edge meets the screen edge, using custom size.
    @display_x = [@display_x + distance, @map_edge[0]].min
  end
end

# Override set-methods to allow callbacks (necessary for Tilemap)
#===============================================================================
# ** Array
#===============================================================================
class Array
  alias flag_changes_to_set []=
  def []=(x, y)
    flag_changes_to_set(x, y)
    CallBackController.call(self, x, y)
  end
end
#===============================================================================
# ** Table
#===============================================================================
class Table
  alias flag_changes_to_set []=
  def []=(*args)
    flag_changes_to_set(*args)
    CallBackController.call(self, *args)
  end
end

if WEATHER_ADJUSTMENT
#===============================================================================
# ** RPG::Weather
#===============================================================================
class RPG::Weather
 
  alias add_more_weather_sprites initialize
  def initialize(vp = nil)
    add_more_weather_sprites(vp)
    total_sprites = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 7680
    if total_sprites > 40
      for i in 1..(total_sprites - 40)
        sprite = Sprite.new(vp)
        sprite.z = 1000
        sprite.visible = false
        sprite.opacity = 0
        @sprites.push(sprite)
      end
    end
  end
 
  def type=(type)
    return if @type == type
    @type = type
    case @type
    when 1
      bitmap = @rain_bitmap
    when 2
      bitmap = @storm_bitmap
    when 3
      bitmap = @snow_bitmap
    else
      bitmap = nil
    end
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
        sprite.bitmap = bitmap
      end
    end
  end
 
  def max=(max)
    return if @max == max;
    @max = [[max, 0].max, @sprites.size].min
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
      end
    end
  end
 
  def update
    return if @type == 0
    for i in 1..@max
      sprite = @sprites[i]
      if sprite == nil
        break
      end
      if @type == 1
        sprite.x -= 2
        sprite.y += 16
        sprite.opacity -= 8
      end
      if @type == 2
        sprite.x -= 8
        sprite.y += 16
        sprite.opacity -= 12
      end
      if @type == 3
        sprite.x -= 2
        sprite.y += 8
        sprite.opacity -= 8
      end
      x = sprite.x - @ox
      y = sprite.y - @oy
      if sprite.opacity < 64
        sprite.x = rand(SCREEN_RESOLUTION[0] + 100) - 100 + @ox
        sprite.y = rand(SCREEN_RESOLUTION[0] + 200) - 200 + @oy
        sprite.opacity = 160 + rand(96)
      end
    end
  end
 
end
#===============================================================================
# ** Game_Screen
#===============================================================================
class Game_Screen
  #--------------------------------------------------------------------------
  # * Set Weather
  #     type : type
  #     power : strength
  #     duration : time
  #--------------------------------------------------------------------------
  def weather(type, power, duration)
    @weather_type_target = type
    if @weather_type_target != 0
      @weather_type = @weather_type_target
    end
    if @weather_type_target == 0
      @weather_max_target = 0.0
    else
      num = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 76800.0
      @weather_max_target = (power + 1) * num
    end
    @weather_duration = duration
    if @weather_duration == 0
      @weather_type = @weather_type_target
      @weather_max = @weather_max_target
    end
  end
 
end

end # if WEATHER_ADJUSTMENT
#===============================================================================
# ** Spriteset_Map
#===============================================================================
class Spriteset_Map

  alias init_for_centered_small_maps initialize
  #---------------------------------------------------------------------------
  # Resize and reposition viewport so that it fits smaller maps
  #---------------------------------------------------------------------------
  def initialize
    @center_offsets = [0,0]
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      x = (SCREEN_RESOLUTION[0] - $game_map.width * 32) / 2
    else
      x = 0
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      y = (SCREEN_RESOLUTION[1] - $game_map.height * 32) / 2
    else
      y = 0
    end
    init_for_centered_small_maps
    w = [$game_map.width  * 32 , SCREEN_RESOLUTION[0]].min
    h = [$game_map.height * 32 , SCREEN_RESOLUTION[1]].min
    @viewport1.resize(x,y,w,h)
  end
  #---------------------------------------------------------------------------
  # Puts the tilemap update method at the end, ensuring that both
  # @tilemap.ox/oy and @viewport1.ox/oy are set.
  #---------------------------------------------------------------------------
  alias update_tilemap_for_real update
  def update
    update_tilemap_for_real
    @tilemap.draw
  end
end

# The following script will only be enabled if the resolution is bigger than the
# default OR if the game does not want certain maps to wrap around.
if DISABLE_WRAP || SCREEN_RESOLUTION[0] > 640 || SCREEN_RESOLUTION[1] > 480
#--------------------------------------------[Unlimited Resolution by Hime]-----
=begin
#===============================================================================
Title: Unlimited Resolution
Date: Oct 24, 2013
Author: Hime ( ** Modified by KK20 ** )
--------------------------------------------------------------------------------   
Terms of Use
Free
--------------------------------------------------------------------------------
Description

This script modifies Graphics.resize_screen to overcome the 640x480 limitation.
It also includes some modifications to module Graphics such as allowing the
default fade transition to cover the entire screen.

Now you can have arbitrarily large game resolutions.
--------------------------------------------------------------------------------
Credits

Unknown author for overcoming the 640x480 limitation
Lantier, from RMW forums for posting the snippet above
Esrever for handling the viewport
Jet, for the custom Graphics code
FenixFyre, for the Plane class fix
Kaelan, for several bug fixes
--------------------------------------------------------------------------------
KK20 Notes:
- Plane class was rewritten from the original script. Certain lines in the
   unknown scripter's code can be omitted entirely to allow this implementation.
- Likewise, the Viewport class needed new methods to handle this Plane rewrite.
- This entire script only applies to games that go beyond the default 640x480
   resolution.

#===============================================================================
=end
unless XPACE
class Bitmap
  #----------------------------------------------------------------------------
  # ● New method: address
  #----------------------------------------------------------------------------
  def address
    @rtlmemory_pi ||= Win32API.new('kernel32','RtlMoveMemory','pii','i')
    @address ||= (  @rtlmemory_pi.call(a="\0"*4, __id__*2+16, 4)
                      @rtlmemory_pi.call(a, a.unpack('L')[0]+8, 4)
                      @rtlmemory_pi.call(a, a.unpack('L')[0]+16, 4)
                      a.unpack('L')[0]    )
  end
end
end
#===============================================================================
# ** Graphics
#===============================================================================
module Graphics
 
  @@super_sprite = Sprite.new
  @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
 
  class << self
   
    def freeze(*args, &block)
      ensure_sprite
      @@super_sprite.bitmap = snap_to_bitmap
    end
   
    def transition(time = 10, filename = nil, vague = nil)
      if filename
        @@super_sprite.bitmap = Bitmap.new(filename)
      end
      @@super_sprite.opacity = 255
      incs = 255.0 / time
      time.times do |i|
        @@super_sprite.opacity = 255.0 - incs * i
        Graphics.wait(1)
      end
      @@super_sprite.bitmap.dispose if @@super_sprite.bitmap
      reform_sprite_bitmap
      Graphics.brightness = 255
    end
   
    def reform_sprite_bitmap
      @@super_sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
      @@super_sprite.bitmap.fill_rect(@@super_sprite.bitmap.rect, Color.new(0, 0, 0, 255))
    end
   
    def fadeout(frames)
      incs = 255.0 / frames
      frames.times do |i|
        i += 1
        Graphics.brightness = 255 - incs * i
        Graphics.wait(1)
      end
    end
   
    def fadein(frames)
      incs = 255.0 / frames
      frames.times do |i|
        Graphics.brightness = incs * i
        Graphics.wait(1)
      end
    end

    def brightness=(i)
      @@super_sprite.opacity = 255.0 - i
    end
   
    def brightness
      255 - @@super_sprite.opacity
    end
   
    def ensure_sprite
      if @@super_sprite.disposed?
        @@super_sprite = Sprite.new
        @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
        reform_sprite_bitmap
      end
    end
   
    # XP does not have a snap_to_bitmap method built-in
    unless XPACE
      define_method(:width)  { Resolution.size.at(0) }
      define_method(:height) { Resolution.size.at(1) }
      #--------------------------------------------------------------------------
      # * snap_to_bitmap
      #--------------------------------------------------------------------------
      def snap_to_bitmap
        @window      ||= Win32API.new('user32','GetActiveWindow', '', 'L')
        @getdc       ||= Win32API.new('user32','GetDC','i','i')
        @ccdc        ||= Win32API.new('gdi32','CreateCompatibleDC','i','i')
        @selectobject||= Win32API.new('gdi32','SelectObject','ii','i')
        @deleteobject||= Win32API.new('gdi32','DeleteObject','i','i')
        @setdibits   ||= Win32API.new('gdi32','SetDIBits','iiiiipi','i')
        @getdibits   ||= Win32API.new('gdi32','GetDIBits','iiiiipi','i')
        @bitblt      ||= Win32API.new('gdi32','BitBlt','iiiiiiiii','i')
        @ccbitmap    ||= Win32API.new('gdi32','CreateCompatibleBitmap','iii','i')
       
        bitmap = Bitmap.new(w = Graphics.width,h = Graphics.height)
        @deleteobject.call(@selectobject.call((hDC = @ccdc.call((dc = @getdc.call(@window.call)))),(hBM = @ccbitmap.call(dc,w,h))))
        @setdibits.call(hDC, hBM, 0, h, (a = bitmap.address), (info = [40,w,h,1,32,0,0,0,0,0,0].pack('LllSSLLllLL')), 0)
        @bitblt.call(hDC, 0, 0, w, h, dc, 0, 0, 0xCC0020)
        @getdibits.call(hDC, hBM, 0, h, a, info, 0)
        @deleteobject.call(hBM)
        @deleteobject.call(hDC)
        return bitmap
      end 
   
      def wait(frame=1)
        frame.times {|s| update }
      end
    end
 
# Graphics.resize_screen is only for XPA games
if XPACE
    #-----------------------------------------------------------------------------
    # Unknown Scripter. Copied from http://pastebin.com/sM2MNJZj
    #-----------------------------------------------------------------------------
    alias :th_large_screen_resize_screen :resize_screen
    def resize_screen(width, height)
      wt, ht = width.divmod(32), height.divmod(32)
      #wt.last + ht.last == 0 || fail('Incorrect width or height')
      #wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ }
      wh = lambda {|w,h,off| [w + off, h + off].pack('l2').scan(/.{4}/) }
      w, h     = wh.call(width, height,0)
      ww, hh   = wh.call(width, height, 32)
      www, hhh = wh.call(wt.first.succ, ht.first.succ,0)
      base = 0x10000000  # fixed?
      #mod = -> adr, val { DL::CPtr.new(base + adr)[0, val.size] = val }
      mod = lambda {|adr,val| (DL::CPtr.new(base + adr))[0, val.size] = val}
      # Didn't see anything happen here
  #    mod.(0x195F, "\x90" * 5)  # ???
  #    mod.(0x19A4, h)
  #    mod.(0x19A9, w)
  #    mod.(0x1A56, h)
  #    mod.(0x1A5B, w)
   
      # The following four seem to change the window size. But I dunno why there
      # are two. I commented out a pair of them but they still do the same thing.
      mod.call(0x20F6, w) && mod.call(0x20FF, w)     
      mod.call(0x2106, h) && mod.call(0x210F, h) 
     
      # speed up y?
      #mod.(0x1C5E3, h) ##
      #mod.(0x1C5E8, w) ##
      #zero = [0].pack ?l
      zero = [0].pack(?l)
     
      # Without these, I can use the default Plane class
  #    mod.(0x1C5E3, zero)
  #    mod.(0x1C5E8, zero)
   
      # And not sure what these do
  #    mod.(0x1F477, h)
  #    mod.(0x1F47C, w)
  #    mod.(0x211FF, hh)
  #    mod.(0x21204, ww)
  #    mod.(0x21D7D, hhh[0])
  #    mod.(0x21E01, www[0])
  #    mod.(0x10DEA8, h)
  #    mod.(0x10DEAD, w)
  #    mod.(0x10DEDF, h)
  #    mod.(0x10DEF0, w)
  #    mod.(0x10DF14, h)
  #    mod.(0x10DF18, w)
  #    mod.(0x10DF48, h)
  #    mod.(0x10DF4C, w)
  #    mod.(0x10E6A7, w)
  #    mod.(0x10E6C3, h)
  #    mod.(0x10EEA9, w)
  #    mod.(0x10EEB9, h)
      th_large_screen_resize_screen(width, height)
    end
   
  end # class << self
 
end # if XPACE

end
#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :parent, :children
 
  alias init_children_vps initialize
  def initialize(*args)
    @children = []
    @parent = false
    init_children_vps(*args)
  end
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias flash_parent flash
  def flash(color, duration)
    if @parent
      @children.each{|child| child.flash_parent(color, duration)}
    else
      flash_parent(color, duration)
    end
  end
 
  alias update_parent update
  def update
    @children.each{|child| child.update} if @parent
    update_parent
  end
 
  alias resize_trigger resize
  def resize(*args)
    @children.each{ |child|
      if args[0].is_a?(Rect)
        rect = args[0]
        new_args = Rect.new(rect.x,rect.y,child.rect.width,child.rect.height)
      else
        new_args = [args[0],args[1]]
        new_args[2] = child.rect.width
        new_args[3] = child.rect.height
      end
      child.resize_trigger(*new_args)
    } if @parent
    resize_trigger(*args)
  end
 
  alias set_trigger_vp_ox ox=
  def ox=(nx)
    return if self.ox == nx
    set_trigger_vp_ox(nx)
    @children.each{|child| child.ox = nx}
  end
 
  alias set_trigger_vp_oy oy=
  def oy=(ny)
    return if self.oy == ny
    set_trigger_vp_oy(ny)
    @children.each{|child| child.oy = ny}
  end
 
  alias tone_parent tone=
  def tone=(t)
    if @parent
      @children.each{|child| child.tone_parent(t)}
    else
      tone_parent(t)
    end
  end

end
#===============================================================================
# ** Plane
#===============================================================================
class Plane
  attr_accessor :offset_x, :offset_y
 
  alias parent_initialize initialize
  def initialize(viewport=nil,parent=true)
    @parent = parent
    @children = []
    parent_initialize(viewport)
    @offset_x = 0
    @offset_y = 0
    # If the parent Plane object; but don't make more children if already have
    # some. This occurs in Spriteset_Map when initializing the Panorama and Fog
    if @parent && viewport
      viewport.parent = true
      create_children
    end
  end
 
  def create_children
    gw = [SCREEN_RESOLUTION[0], $game_map.width * 32].min
    gh = [SCREEN_RESOLUTION[1], $game_map.height * 32].min
    w = (gw - 1) / 640
    h = (gh - 1) / 480
    for y in 0..h
      for x in 0..w
        # This is the top-left default/parent Plane, so skip it
        #next if x == 0 && y == 0
        # Create viewport unless it already exists
        width = w > 0 && x == w ? gw - 640 : 640
        height = h > 0 && y == h ? gh - 480 : 480
        vp = Viewport.new(x * 640, y * 480, width, height, true)
        vp.offset_x = x * 640
        vp.offset_y = y * 480
        # Have to do this in order to prevent overlapping with the parent
        # (for Spriteset_Map viewport1 mainly)
        vp.z = self.viewport.z - 1
        self.viewport.children.push(vp)
        # Create the child Plane
        plane = Plane.new(vp,false)
        plane.offset_x = x * 640
        plane.ox = 0
        plane.offset_y = y * 480
        plane.oy = 0
        # Push to array
        @children.push(plane)
      end
    end
  end
 
  # For the remaining Plane properties, if the parent changes, so do its children
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias zoom_x_parent zoom_x=
  def zoom_x=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_x_parent(new_val)} if @parent
    zoom_x_parent(new_val)
  end
 
  alias zoom_y_parent zoom_y=
  def zoom_y=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_y_parent(new_val)} if @parent
    zoom_y_parent(new_val)
  end
 
  alias ox_parent ox=
  def ox=(new_val)
    @children.each{|child| child.ox = new_val} if @parent
    ox_parent(new_val + @offset_x)
  end
 
  alias oy_parent oy=
  def oy=(new_val)
    @children.each{|child| child.oy = new_val} if @parent
    oy_parent(new_val + @offset_y)
  end
 
  alias bitmap_parent bitmap=
  def bitmap=(new_val)
    @children.each{|child| child.bitmap_parent(new_val)} if @parent
    #bitmap_parent(new_val)
  end
 
  alias visible_parent visible=
  def visible=(new_val)
    @children.each{|child| child.visible_parent(new_val)} if @parent
    visible_parent(new_val)
  end
 
  alias z_parent z=
  def z=(new_val)
    # Because the children spawn new Viewports, they have to be lower than the
    # parent's viewport to prevent drawing OVER the parent...unless the Plane's
    # z-value is more than zero, in which case the children viewports NEED to be
    # higher than the parent's. By doing this, we can have panoramas be below
    # the tilemap and fogs be over the tilemap.
    if @parent && @children[0]
      child = @children[0]
      if new_val > 0 && child.viewport.z < self.viewport.z
        @children.each{|child| child.viewport.z += 1}
      elsif new_val <= 0 && child.viewport.z >= self.viewport.z
        @children.each{|child| child.viewport.z -= 1}
      end
    end
   
    @children.each{|child| child.z_parent(new_val)} if @parent
    z_parent(new_val)
  end
 
  alias opacity_parent opacity=
  def opacity=(new_val)
    @children.each{|child| child.opacity_parent(new_val)} if @parent
    opacity_parent(new_val)
  end
 
  alias color_parent color=
  def color=(new_val)
    if @parent
      @children.each{|child| child.color_parent(new_val)}
    else
      color_parent(new_val)
    end
  end
 
  alias blend_type_parent blend_type=
  def blend_type=(new_val)
    @children.each{|child| child.blend_type_parent(new_val)} if @parent
    blend_type_parent(new_val)
  end
 
  alias tone_parent tone=
  def tone=(new_val)
    if @parent
      @children.each{|child| child.tone_parent(new_val)}
    else
      tone_parent(new_val)
    end
  end
 
end
#------------------------------------------[End of Unlimited Resolution]--------
end

# Resize the game window (if using XP) and load the MapInfos file
Resolution.resize_game unless XPACE
XPAT_MAP_INFOS = load_data("Data/MapInfos.rxdata")

Forgot to check the tone changing when I was fixing the Viewport#resize
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on February 26, 2017, 09:46:24 am
Perfect. :D
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 26, 2017, 04:20:04 pm
Cool, I'll update the download then. Next step is to make a project that tests all these features. Will be a pain.

Would like to look into how Graphics.transition works, particularly what vague does. Google searches didn't show any results--no one figured it out or has shared it publicly.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on February 26, 2017, 04:54:08 pm
I did implement it in ARC so you can figure it out actually. It's how much the alpha will transition. IIRC a vague of 255 would do a long transition while a vague of 0 would jump from 0 to 255 opacity during just one frame.

EDIT:

Check out the implementation:
https://github.com/borisblizzard/arcreator/blob/master/engine/lib/legacy/src/Graphics.cpp

And here is insertAlphaMap():
https://github.com/AprilAndFriends/april/blob/master/src/images/Image.cpp
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 27, 2017, 12:59:43 am
I actually did look at the source before but it seemed over my head at that time. I was able to copy most of it over, and it almost seems to work. The transition doesn't actually finish all the way and sort of "skips" to the end. I'll need to play with the code more. Thanks ;)

Red -> Blue = RMXP Transition
Blue -> Red = DLL method
Spoiler: ShowHide
(http://i.imgur.com/fU0Rx7s.gif)
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on February 28, 2017, 04:30:40 pm
Hey, would it be possible to implement in the next version proper, not stretched fullscreen? something similiar to Fullscreen++ on VX.

I'm not sure if it's the right place to ask, but I noticed, that Lambchop's Super Simple Mouse Script doesn't change it's cursor on events with XP Ace. There's mouse script demo - http://rmrk.net/index.php?action=dlattach;topic=39691.0;attach=30495
Any ideas how to fix it? If you're going to test it, don't forget to copy couple lines of code from Main. :)

Thank you :)
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 28, 2017, 11:42:25 pm
I'll see what I can do about that.

The mouse issue appears to be caused by Array#to_s. They changed how it works in version 1.8 to 1.9.
You can add this to XPA's Ruby 1.8 Methods:

class Array
  def to_s
    self.join('')
  end
end

I'll be sure to add this when I update the XPA package.

For compatibility issues in XPA, it's best that you post them in the official XPA topic (http://forum.chaos-project.com/index.php/topic,12899.0.html).
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on March 01, 2017, 02:48:16 am
Thank you! works perfectly now. :)
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on March 09, 2017, 03:47:19 pm
Just updated my game to this, and it works like a charm (I even think it goes 1-2 frames better). Anyway anything I find I'll be sure to pester notify you.

So yeah thanks for your great work KK20 and all people involved in this.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on April 26, 2017, 02:46:36 pm
I just got this:

Spoiler: ShowHide
(http://i.imgur.com/j4AsnBa.png)



class Bitmap
  attr_accessor :filename
  alias set_filename_of_bitmap initialize
  def initialize(*args)
    # Associate the bitmap with the filename of the graphic; empty string otherwise
    @filename = args.size == 1 ? File.basename(args[0], '.*') : ''
    set_filename_of_bitmap(*args) # <---------- this line
  end
end


I've done easily over a 100-150 map switches before this happened so I'm not sure how you could reproduce it. In any case, I definitely think it's some sort of edge case.

EDIT: I found another issue. I have a map about 40x40-50x50 and it's filled with autotiles. When I'm in the upper half, it's all fine, but while I'm in the lower half of the map, it lags a lot. The FPS probably drops to 10 or so.

EDIT: I also just found a crash, but at least I have a 100% reproduction rate. I don't really know why it happens, but it happens basically as soon as the carpet autotile gets out of focus. I'll PM you my build so you can investigate.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on April 26, 2017, 08:43:19 pm
Think you can add a catch there to print the args in case it happens again? Hopefully the cause of the error can be pin-pointed that way.

Do you have a map you can provide me with to test myself? Doesn't seem like bucket filling all three layers with autotiles can reproduce it.

Discord PM'd you about the crash. Has to do with null autotiles being used. Will need to bug fix that one.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on April 27, 2017, 01:36:17 am
I can add some protection there. I've mostly been using F8 for reload data and then J + "Yes" to reset puzzle on the 2nd Fortress of Nighmares map (it's in the Para-Universe part) with all the switches and bridges and at one point it just crashed with that error message.

For the lag, just teleport with the F9 menu to the lava map in Grand Crossing (also within Para-Universe).
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on April 27, 2017, 02:01:48 am
Regarding the lag, it's the panorama. That 1 width pixel graphic is back to haunt us again lol

I notice the lag spike right when the graphic wraps around. Definitely plane rewrite being the problem here, but will need to investigate that more.
Simply removing it brings the frame rate back to 60.
EDIT: Alternatively, you can stretch the graphic to a larger size (say 640x640).

Strangely enough, there's no problems with the original graphic in XP or VXA. XPA Tilemap in a XP game has no issues either. Problem occurs even without the Plane rewrite in XPA. Hard to say what's the real issue.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on April 27, 2017, 04:14:01 am
I made that 1-pixel panorama graphic exactly for that reason: To reduce lag. xD
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on April 30, 2017, 11:42:11 pm
Due to Blizzard holding me hostage, I have released v0.33

Download v0.33 (https://www.dropbox.com/s/vbrxdg8qv0ev96u/XPAT_v0.33.zip?dl=0)
Please send help, I cannot take anymore German Dungeon Porn : (
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on May 01, 2017, 02:19:40 am
I'm probably gonna try it out today.

Quote from: KK20 on April 30, 2017, 11:42:11 pm
Please send help, I cannot take anymore German Dungeon Porn : (


xD

EDIT: No more hard crashes. :3 I still have the lag issue in map 852 though. It's in Para-Universe -> Grand Crossing -> Grand Crossing, the one with lava.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on May 01, 2017, 03:18:39 am
Quote from: KK20 on April 27, 2017, 02:01:48 am
Regarding the lag, it's the panorama. That 1 width pixel graphic is back to haunt us again lol

I notice the lag spike right when the graphic wraps around. Definitely plane rewrite being the problem here, but will need to investigate that more.
Simply removing it brings the frame rate back to 60.
EDIT: Alternatively, you can stretch the graphic to a larger size (say 640x640).

Strangely enough, there's no problems with the original graphic in XP or VXA. XPA Tilemap in a XP game has no issues either. Problem occurs even without the Plane rewrite in XPA. Hard to say what's the real issue.

That's really all I can help you with on that one.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on May 01, 2017, 03:35:04 am
Yup, it seems to be the only solution. Oh well, it's not that big of an issue for me.
*extends graphics*
*optimization OCD goes haywire* #_#
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on May 03, 2017, 12:48:00 pm
So, we've been hunting a memory leak for the past 2 hours and it turned out to be this script. Your C code seemed fine so I started digging in Ruby to see what could be causing the issue. And I found it. xD You're missing this in Tilemap#dispose:


    CallBackController.delete(@autotiles)
    CallBackController.delete(@map_data)
    CallBackController.delete(@priorities)


But it's is somewhat unsafe to use code like this. If the Tilemap isn't disposed explicitly, the memory will remain allocated and not collected by the GC. IDK if you maybe should change this implementation entirely and just throw out that CallBackController class. Your call.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on May 04, 2017, 03:58:35 am
Thanks to Blizzard's discovery, I have created a fix in version 0.34. It was only a couple lines added, so you only need to replace the script.
Spoiler: ShowHide

=begin
================================================================================
XPA Tilemap                                                      Version 0.34
by KK20                                                          4 May 2017
________________________________________________________________________________

[ Version History ]

Ver.      Date            Notes
-----     -----------     ----------------------------------------------------
0.34  ... 04 May 2017 ... Bug fixes:
                            - CallBackController was not disposing its contents,
                              causing a memory leak whenever a new Tilemap was
                              created (and eventually crashing the game)
0.33  ... 30 Apr 2017 ... Bug fixes:
                            - Maps with empty autotiles would crash the game
                            - Tilesets without a graphic would crash the game
                            - The creation of empty autotiles would continually
                              spawn disposed Bitmap objects (related to above)
                            - 32x32 autotiles that animated would crash the game
0.32  ... 25 Feb 2017 ... Bug fixes:
                            - Child viewports were having display issues when
                              tone changes were involved
                            - Viewport#flash had missing parameters
                            - Added more compatibility for XP games (thanks
                              LiTTleDRAgo!)
0.31  ... 08 Feb 2017 ... Bug fixes:
                            - Bad logic with border sprites for non-wrapping map
                            - Problem with Plane objects not initialized with a
                              viewport, causing children-creation to crash
                            - Disable Graphics.resize_screen in Hime's script
                              for XP games as this method does not exist nor is
                              the code necessary to "break" the resolution limit
                            - RGSS does not support Array#cover?
                           Changes:
                            - The Resolution module is disabled for XPA
                            - If WEATHER_ADJUSTMENT is false, it will disable
                              all of the RPG::Weather and Game_Screen classes
                              from loading rather than only some methods
                            - Input module for supporting different game window
                              sizes is disabled for XP as this feature does not
                              work in RGSS
0.3   ... 04 Feb 2017 ... Bug fixes:
                            - A graphical bug involving priority tiles if the
                              MAX_PRIORITY_LAYERS is set to less than 5
                            - Loading autotiles in RPG::Cache has been revised
                              for better compatibility
                            - CallBackController added to replace the method
                              implemented in v0.2b which prevented saving games
                           Additions:
                            - Commented out a majority of the anonymous scripter
                              code that breaks the resolution limit for RGSS3;
                              its ramifications are unknown at this point
                            - A new Plane rewrite which is merely just creating
                              more Plane objects
                            - Maps that do not wrap have a high z-level black
                              sprite positioned around the map's borders
                            - New fullscreen and other window size options for
                              XPA games (will not work for XP)
                            - Tilesets that are not divisible by 32 will raise
                              an error rather than crash
                            - Maps with invalid tile ID's (caused when a tile
                              was placed with a taller tileset graphic, but then
                              the map uses a shorter tileset) no longer crash
                              the game
0.13b ... 23 Oct 2016 ... Bug fixes:
                            - Resolutions not divisible by 32 would not show the
                              last row/column of tiles entirely
                           ** Fix added on top of v0.12b, not v0.2b, but is
                           ** included in all versions above this one
0.2b  ... 07 Jun 2016 ... Bug fixes:
                            - Shaking still had issues
                           Additions:
                            - Maps can now wrap by putting [WRAP] in the map
                              name, due to a new way of drawing the map
                            - ...which also fixed the shaking above
                            - ...and can also allow vertical shaking
                            - Added Unlimited Resolution, an RMVXA script with
                              some changes
                            - Changing tileset and autotile bitmaps in-game will
                              not crash (assuming you know how to do that)
                            - Overall cleaning of code
0.12b ... 27 Feb 2016 ... Bug fixes:
                            - Tiles with some transparency and priority were
                              being redrawn continuously on each other
                            - Setting the Plane bitmap to nil would crash
0.11b ... 03 Nov 2014 ... Bug fixes:
                            - Table did not take in parameters upon initialize
                            - Centering of maps now shrinks Viewport sizes
                            - Fixed Tilemap#oy= logic
0.1b  ... 02 Nov 2014 ... Initial release
________________________________________________________________________________

[ Introduction ]

In light of recent discoveries regarding the usage of RGSS3 in RPG Maker XP
games, many users were left with a dilemma in choosing which Tilemap rewrite to
use due to the vast differences between RGSS1's and RGSS3's Tilemap classes
that would cause complications in this transition. I aimed to find the best
Tilemap rewrite and decided that I would have to make my own. Like every other
Tilemap rewrite before it, this implementation is in no ways perfect, boasting
PROs and CONs.

This script is intended to be used for RPG Maker XP games using the RGSS3
library (unofficially coined RPG Maker XP Ace); however, it is entirely
compatible with RPG Maker XP games in the RGSS1 library.
________________________________________________________________________________

[ License ]

This work is protected by the following license:
http://creativecommons.org/licenses/by-nc-sa/3.0/

********************************************************************************

You are free:

to Share - to copy, distribute and transmit the work
to Remix - to adapt the work

Under the following conditions:

Attribution:
You must attribute the work in the manner specified by the author or licensor,
but not in any way that suggests that they endorse you or your use of the work.

Noncommercial:
You may not use this work for commercial purposes.

Share alike:
If you alter, transform, or build upon this work, you may distribute the
resulting work only under the same or similar license to this one.

- For any reuse or distribution, you must make clear to others the license terms
  of this work. The best way to do this is with a link to this web page.

- Any of the above conditions can be waived if you get permission from the
  copyright holder.

- Nothing in this license impairs or restricts the author's moral rights.

********************************************************************************

[ Instructions ]

- Place this script below the default scripts but above Main.
- Move 'XPATilemap.dll' into your project folder (same directory as 'Game.exe')
- Configure values at the start of the script
________________________________________________________________________________

[ Features ]

About the script:
- XP and XPA (RGSS1 and RGSS3) compatible, though designed for XPA
- Define your own custom resolution
- Adds new tilemap features
- Maps that are smaller than the game resolution are automatically centered
- Drawing methods written in C-language, which has faster pixel-by-pixel
   operations than Ruby

Add-ons:
- Customize frame rate animation and define unique patterns for your autotiles
- Remove unnecessary priority layers to boost frames-per-second (FPS)
- Extend the default RPG::Weather class to fit larger screens, or not
- Change the way fullscreen works (or disable it), including a double and half-
   size window option (only for XPA)
- more to add later...
________________________________________________________________________________

[ Compatibility ]

- There have been reports of Screen Flash not working for some users, though I
   have yet to receive any valid proof or ways to reproduce this issue
- Your tileset must have dimensions divisible by 32. The game will raise an
   error otherwise.
________________________________________________________________________________

[ Credits ]

KK20 - Author of this script and DLL
Blizzard - Tester and providing bug fixes
LiTTleDRAgo - Reusing code from his edits to Custom Resolution and bug fixes
Zexion - Tester and morale support
ForeverZer0 - Reusing code from his Custom Resolution script, found here:
                http://forum.chaos-project.com/index.php/topic,7814.0.html
________________________________________________________________________________

[ Contact ]

To contact the author of this script, please visit
                http://forum.chaos-project.com/index.php
               
or send an email to
                        tscrane20@gmail.com
                       
================================================================================
=end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                       B E G I N   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#-------------------------------------------------------------------------------
# The game window's screen resolution. RPG Maker XP's default is [640, 480].
# Do note that a larger resolution is prone to sprite lag.
# Anything larger than the default resolution will enable the custom Plane class.
#-------------------------------------------------------------------------------
SCREEN_RESOLUTION = [640,480]

#-------------------------------------------------------------------------------
# The largest level of priority your game uses. This value should be between
# 1 and 5. If using a large resolution, lowering the number of priority layers
# will help in reducing the lag.
#-------------------------------------------------------------------------------
MAX_PRIORITY_LAYERS = 5

#-------------------------------------------------------------------------------
# If using a larger resolution than 640x480, the default weather effects will
# not cover the entire map. It is recommended that you set this to true to
# compensate for that, unless you are using some custom weather script that can
# address this.
#-------------------------------------------------------------------------------
WEATHER_ADJUSTMENT = false

#-------------------------------------------------------------------------------
# When the map's display_x/y variables extend beyond its borders, the map wraps
# around to fill in the gaps. Setting this to true will prevent that, showing
# black borders instead.
# If you want some maps to wrap around, putting [WRAP] in a map's name will
# allow this.
# Note that the custom Plane class will be enabled in order to create this
# effect regardless of your resolution size.
#-------------------------------------------------------------------------------
DISABLE_WRAP = false

#-------------------------------------------------------------------------------
# Choose a form of fullscreen for your game. The available choices are:
#  0 = Default RPG Maker fullscreen (changes monitor resolution to 640x480)
#  1 = Stetches game window to player's monitor size (only for XPA)
#  2 = Disable the ability to go into fullscreen
# Please note that if you choose anything other than 0, it disables everything
# on the player's computer from being able to use ALT + ENTER.
#-------------------------------------------------------------------------------
FULLSCREEN_METHOD = 0

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 2x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
TWICE_SIZE_BUTTON = Input::F5

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 0.5x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
HALF_SIZE_BUTTON = Input::F6

#-------------------------------------------------------------------------------
# Set the animation frame rate for autotiles. By default, all autotiles will
# update on the 16th frame. You can change that by providing an array of numbers
# that represent how many frames that particular frame of animation will be
# visible for.
# Format:
#   when AUTOTILE_FILENAME then FRAME_DATA
# where FRAME_DATA is an array containing the number of frames that particular
# animation will play for before moving onto the next frame. Be sure to match
# the number of autotile animation frames with the number of elements you put
# into the array.
# Check the examples below.
#-------------------------------------------------------------------------------
def autotile_framerate(filename)
  case filename
  #------------------------------------------------------ START ------
  when '001-G_Water01' then [8, 8, 8, 8]      # Animates twice as fast
  when '009-G2_Water01' then [20, 20, 20, 20] # Animates a bit slower
  when '024-Ocean01' then [32, 16, 32, 16]    # Sine wave effect
  #------------------------------------------------------- END -------
  # Don't touch any of this below
  else
    return nil if filename == ''
    # Generates array of [16, 16, ...] based on autotile width
    # (or nil if not animating autotile)
    w = RPG::Cache.autotile(filename).width
    h = RPG::Cache.autotile(filename).height
    if (h == 32 && w / 32 == 1) || (h == 192 && w / 256 == 1)
      return nil
    else
      return h == 32 ? Array.new(w/32){|i| 16} : Array.new(w/256){|i| 16}
    end
  end
end

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                           E N D   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FULLSCREEN_METHOD = 0 unless FULLSCREEN_METHOD.between?(0,2)
if FULLSCREEN_METHOD != 0
  # Disable ALT+Enter
  reghotkey = Win32API.new('user32', 'RegisterHotKey', 'LIII', 'I')
  reghotkey.call(0, 1, 1, 0x0D)
end

XPACE = RUBY_VERSION == "1.9.2"

MAX_PRIORITY_LAYERS = 5 unless (1..5).include?(MAX_PRIORITY_LAYERS)

if XPACE
#===============================================================================
# ** Input
#===============================================================================
module Input

  GetActiveWindow = Win32API.new('user32', 'GetActiveWindow', '', 'L')
  SetWindowLong = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
  SetWindowPos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
  GetSystemMetrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
  GetAsyncKeyState = Win32API.new('user32', 'GetAsyncKeyState', 'I', 'I')
 
  @fullscreenKeysReleased = true
  @current_state = 0
  NORMAL_STATE     = 0
  FULLSCREEN_STATE = 1
  TWICESIZE_STATE  = 2
  HALFSIZE_STATE   = 3
 
  class << self
    alias get_fullscreen_keys update
   
    # Check for window resize buttons
    def update
      enterkey_state = GetAsyncKeyState.call(0x0D)
      # If ALT+ENTER was pressed, but only for modified fullscreen
      if FULLSCREEN_METHOD == 1 && @fullscreenKeysReleased && Input.press?(Input::ALT) && enterkey_state != 0
        @current_state = @current_state == FULLSCREEN_STATE ? NORMAL_STATE : FULLSCREEN_STATE
        @fullscreenKeysReleased = false
        # Changing game window to fullscreen
        if @current_state == FULLSCREEN_STATE
          full_screen_size
        else
          normal_screen_size
        end
      # If button to double the normal window size was pressed
      elsif TWICE_SIZE_BUTTON && Input.trigger?(TWICE_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to double or normalize the window
        @current_state = @current_state == TWICESIZE_STATE ? NORMAL_STATE : TWICESIZE_STATE
        if @current_state == TWICESIZE_STATE
          double_screen_size
        else
          normal_screen_size
        end
      # If button to halve the normal window size was pressed
      elsif HALF_SIZE_BUTTON && Input.trigger?(HALF_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to halve or normalize the window
        @current_state = @current_state == HALFSIZE_STATE ? NORMAL_STATE : HALFSIZE_STATE
        if @current_state == HALFSIZE_STATE
          half_screen_size
        else
          normal_screen_size
        end
      else
        # Check if ALT or ENTER is released
        @fullscreenKeysReleased = (!Input.press?(Input::ALT) || enterkey_state == 0)
      end
      # Call the alias
      get_fullscreen_keys
    end
   
    # Doubles the window size based on SCREEN_RESOLUTION.
    def double_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] * 2
      nh = SCREEN_RESOLUTION[1] * 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Halves the window size based on SCREEN_RESOLUTION.
    def half_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] / 2
      nh = SCREEN_RESOLUTION[1] / 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Makes game window as large as the monitor's resolution
    def full_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x10000000)
      SetWindowPos.call(GetActiveWindow.call, 0, 0, 0, rw, rh, 0)
    end
   
    # Reverts the game window back to normal size
    def normal_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      x = (rw - SCREEN_RESOLUTION[0]) / 2
      y = (rh - SCREEN_RESOLUTION[1]) / 2
      w = SCREEN_RESOLUTION[0] + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = SCREEN_RESOLUTION[1] + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Simulates the key press of ALT+Enter; called if we need to get in or out
    # of fullscreen even though the player did not press these keys
    def simulate_alt_enter
      keybd = Win32API.new 'user32.dll', 'keybd_event', ['i', 'i', 'l', 'l'], 'v'
      keybd.call(0xA4, 0, 0, 0)
      keybd.call(13, 0, 0, 0)
      keybd.call(13, 0, 2, 0)
      keybd.call(0xA4, 0, 2, 0)
    end
   
    # Check if the game is in default fullscreen
    def fullscreen?
      # We're not using default fullscreen, so this should always be false
      return false if FULLSCREEN_METHOD != 0
      # If current monitor resolution is 640x480, then it is fullscreen
      if GetSystemMetrics.call(0) == 640 && GetSystemMetrics.call(1) == 480
        @current_state = FULLSCREEN_STATE
        return true
      end
    end
   
  end
end

end # if XPACE

if !XPACE
#===============================================================================
# ** Resolution
#===============================================================================
module Resolution
 
  def self.resize_game
    # Set instance variables for calling basic Win32 functions.
    ini = Win32API.new('kernel32', 'GetPrivateProfileStringA','PPPPLP', 'L')
    title = "\0" * 256
    ini.call('Game', 'Title', '', title, 256, '.\\Game.ini')
    title.delete!("\0")
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
    set_window_long = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
    set_window_pos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
    @metrics         = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
    # Set default size, displaying error if size is larger than the hardware.
    default_size = Resolution.size
    # Apply resolution change.
    x = (@metrics.call(0) - SCREEN_RESOLUTION[0]) / 2
    y = (@metrics.call(1) - SCREEN_RESOLUTION[1]) / 2
    set_window_long.call(@window, -16, 0x14CA0000)
    set_window_pos.call(@window, 0, x, y, SCREEN_RESOLUTION[0] + 6, SCREEN_RESOLUTION[1] + 26, 0)
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
  end
  #--------------------------------------------------------------------------
  def self.size
    # Returns the screen size of the machine.
    [@metrics.call(0), @metrics.call(1)]
  end
  #--------------------------------------------------------------------------
end

end # if !XPACE

#===============================================================================
# ** NilClass
#===============================================================================
class NilClass
  unless method_defined?(:dispose)
    def dispose; end
    def disposed?; end
  end
end
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
  attr_accessor :filename
  alias set_filename_of_bitmap initialize
  def initialize(*args)
    # Associate the bitmap with the filename of the graphic; empty string otherwise
    @filename = args.size == 1 ? File.basename(args[0], '.*') : ''
    set_filename_of_bitmap(*args)
  end
end
#===============================================================================
# ** RPG::Cache
#===============================================================================
module RPG::Cache
 
  AUTO_INDEX = [
 
  [27,28,33,34],  [5,28,33,34],  [27,6,33,34],  [5,6,33,34],
  [27,28,33,12],  [5,28,33,12],  [27,6,33,12],  [5,6,33,12],
  [27,28,11,34],  [5,28,11,34],  [27,6,11,34],  [5,6,11,34],
  [27,28,11,12],  [5,28,11,12],  [27,6,11,12],  [5,6,11,12],
  [25,26,31,32],  [25,6,31,32],  [25,26,31,12], [25,6,31,12],
  [15,16,21,22],  [15,16,21,12], [15,16,11,22], [15,16,11,12],
  [29,30,35,36],  [29,30,11,36], [5,30,35,36],  [5,30,11,36],
  [39,40,45,46],  [5,40,45,46],  [39,6,45,46],  [5,6,45,46],
  [25,30,31,36],  [15,16,45,46], [13,14,19,20], [13,14,19,12],
  [17,18,23,24],  [17,18,11,24], [41,42,47,48], [5,42,47,48],
  [37,38,43,44],  [37,6,43,44],  [13,18,19,24], [13,14,43,44],
  [37,42,43,48],  [17,18,47,48], [13,18,43,48], [13,18,43,48]
   
  ]
 
  def self.autotile(filename)
    key = "Graphics/Autotiles/#{filename}"
    if !@cache.include?(key) || @cache[key].disposed?
      # Load the autotile graphic.
      orig_bm = self.load_bitmap('Graphics/Autotiles/', filename)
      # Cache each configuration of this autotile.
      new_bm = self.format_autotiles(orig_bm, filename)
      if new_bm != orig_bm
        @cache[key].dispose
        @cache[key] = new_bm
      end
    end
    @cache[key]
  end

  def self.format_autotiles(bitmap, filename)
    if bitmap.height > 32 && bitmap.height < 256
      frames = bitmap.width / 96
      template = Bitmap.new(256*frames,192)
      template.filename = filename
      # Create a bitmap to use as a template for creation.
      (0..frames-1).each{|frame|
      (0...6).each {|i| (0...8).each {|j| AUTO_INDEX[8*i+j].each {|number|
        number -= 1
        x, y = 16 * (number % 6), 16 * (number / 6)
        rect = Rect.new(x + (frame * 96), y, 16, 16)
        template.blt((32 * j + x % 32) + (frame * 256), 32 * i + y % 32, bitmap, rect)
      }}}}
      return template
    else
      return bitmap
    end
  end
 
end
#===============================================================================
# ** CallBackController
#===============================================================================
module CallBackController
  @@callback = {}
 
  def self.clear
    @@callback.clear
  end
 
  def self.setup_callback(obj, proc)
    @@callback[obj.object_id] = proc
  end
 
  def self.call(obj, *args)
    @@callback[obj.object_id].call(*args) if @@callback[obj.object_id]
    true
  end
 
  def self.delete(obj)
    @@callback.delete(obj.object_id)
  end
 
end

#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :offset_x, :offset_y
 
  alias zer0_viewport_resize_init initialize
  def initialize(x=0, y=0, width=SCREEN_RESOLUTION[0], height=SCREEN_RESOLUTION[1], override=false)
    # Variables needed for Viewport children (for the Plane rewrite); ignore if
    # your game resolution is not larger than 640x480
    @offset_x = @offset_y = 0
    if x.is_a?(Rect)
      # If first argument is a Rectangle, just use it as the argument.
      zer0_viewport_resize_init(x)
    elsif [x, y, width, height] == [0, 0, 640, 480] && !override
      # Resize fullscreen viewport, unless explicitly overridden.
      zer0_viewport_resize_init(Rect.new(0, 0, SCREEN_RESOLUTION[0], SCREEN_RESOLUTION[1]))
    else
      # Call method normally.
      zer0_viewport_resize_init(Rect.new(x, y, width, height))
    end
  end
 
  def resize(*args)
    # Resize the viewport. Can call with (X, Y, WIDTH, HEIGHT) or (RECT).
    if args[0].is_a?(Rect)
      args[0].x += @offset_x
      args[0].y += @offset_y
      self.rect = args[0]
    else
      args[0] += @offset_x
      args[1] += @offset_y
      self.rect = Rect.new(*args)
    end
  end
end

#===============================================================================
# ** Tilemap
#===============================================================================
class Tilemap
 
  attr_accessor :tileset, :autotiles, :map_data, :priorities, :ground_sprite
  attr_reader :wrapping
  #---------------------------------------------------------------------------
  # Initialize
  #---------------------------------------------------------------------------
  def initialize(viewport = nil)
    # Ensure that all callbacks are removed to prevent memory leaks
    CallBackController.clear
   
    @viewport = viewport
    @layer_sprites = []
    @autotile_frame = []      #[[ANIMATION_DRAW_INDEX, CURRENT_LOGICAL_FRAME], ... ]
    @autotile_framedata = []  #[[DATA_FROM_CONFIGURATION_ABOVE], ... ]
   
    # Ensures that the bitmap width accounts for an extra tile
    # and is divisible by 32
    bitmap_width = ((SCREEN_RESOLUTION[0] / 32.0).ceil + 1) * 32
    # Create the priority layers
    ((SCREEN_RESOLUTION[1]/32.0).ceil + MAX_PRIORITY_LAYERS).times{ |i|
      s = Sprite.new(@viewport)
      s.bitmap = Bitmap.new(bitmap_width, MAX_PRIORITY_LAYERS * 32)
      @layer_sprites.push(s)
    }
   
    # Same reasons as bitmap_width, but for height
    bitmap_height = ((SCREEN_RESOLUTION[1] / 32.0).ceil + 1) * 32
    # Create the ground layer (priority 0)
    s = Sprite.new(@viewport)
    s.bitmap = Bitmap.new(bitmap_width, bitmap_height)
    @ground_sprite = s
    @ground_sprite.z = 0

    # Initialize remaining variables
    @redraw_tilemap = true
    @tileset = nil
    @autotiles = []
    proc = Proc.new { |x,y| @redraw_tilemap = true; setup_autotile(x) }
    CallBackController.setup_callback(@autotiles, proc)
   
    @map_data = nil
   
    @priorities = nil
    @old_ox = 0
    @old_oy = 0
    @ox = 0
    @oy = 0
    @ox_float = 0.0
    @oy_float = 0.0
    @shift = 0
    @wrapping = (!DISABLE_WRAP || (XPAT_MAP_INFOS[$game_map.map_id].name =~ /.*\[[Ww][Rr][Aa][Pp]\].*/) == 0) ? 1 : 0
    create_border_sprites
   
    # Set up the DLL calls
    @@update = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap2', 'pppp', 'i')
    @@autotile_update = Win32API.new('XPA_Tilemap', 'UpdateAutotiles', 'pppp', 'i')
    @@initial_draw = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap', 'pppp', 'i')
    @empty_tile = Bitmap.new(32,32)
    Win32API.new('XPA_Tilemap','InitEmptyTile','l','i').call(@empty_tile.object_id)
    @black_tile = Bitmap.new(32,32)
    @black_tile.fill_rect(0,0,32,32,Color.new(0,0,0))
    Win32API.new('XPA_Tilemap','InitBlackTile','l','i').call(@black_tile.object_id)
   
  end
  #---------------------------------------------------------------------------
  # Setup autotile animation data
  #---------------------------------------------------------------------------
  def setup_autotile(i)
    # Get animation frame rate of the autotile
    bitmap = @autotiles[i]
    frames = bitmap.nil? ? nil : autotile_framerate(bitmap.filename)
    # If autotile doesn't animate
    if frames.nil?
      @autotile_frame[i] = [0,0]
      @autotile_framedata[i] = nil
    else
      # Save the frame rate data
      @autotile_framedata[i] = frames
      # Determine how long one animation cycle takes and indicate at what time
      # the next frame of animation occurs
      total = 0
      frame_checkpoints = []
     
      frames.each_index{|j| f = frames[j]
        total += f
        frame_checkpoints[j] = total
      }
      # Get animation frame for this autotile based on game time passed
      current_frame = Graphics.frame_count % total
      frame_checkpoints.each_index{|j| c = frame_checkpoints[j]
        next if c.nil?
        if c > current_frame
          @autotile_frame[i] = [j, c - current_frame]
          break
        end
      }
    end
  end
  #---------------------------------------------------------------------------
  # Creates four 32-pixel thick black sprites to surround the map. This is
  # only applied to maps that do not have wrapping enabled. This helps those
  # who have screen shaking in their maps.
  #---------------------------------------------------------------------------
  def create_border_sprites
    @border_sprites = []
    return if @wrapping == 1
    for i in 0..3
      s = Sprite.new(@viewport)
      s.z = 99999
      if i % 2 == 0
        b = Bitmap.new(SCREEN_RESOLUTION[0] + 64,32)
        s.x = -32
        s.y = i == 0 ? -32 : $game_map.height * 32
      else
        b = Bitmap.new(32,SCREEN_RESOLUTION[1] + 64)
        s.x = i == 1 ? -32 : $game_map.width * 32
        s.y = -32
      end
      b.fill_rect(0, 0, b.width, b.height, Color.new(0,0,0))
      s.bitmap = b
      @border_sprites.push(s)
    end
  end
  #---------------------------------------------------------------------------
  # Dispose tilemap
  #---------------------------------------------------------------------------
  def dispose
    @layer_sprites.each{|sprite| sprite.dispose}
    @ground_sprite.dispose
    @border_sprites.each{|sprite| sprite.dispose}
    CallBackController.clear
  end
  #---------------------------------------------------------------------------
  # Check if disposed tilemap
  #---------------------------------------------------------------------------
  def disposed?
    @layer_sprites[0].disposed?
  end
  #---------------------------------------------------------------------------
  # Get viewport
  #---------------------------------------------------------------------------
  def viewport
    @viewport
  end
  #---------------------------------------------------------------------------
  # Return if tilemap is visible
  #---------------------------------------------------------------------------
  def visible
    layer_sprites[0].visible
  end
  #---------------------------------------------------------------------------
  # Show or hide tilemap
  #---------------------------------------------------------------------------
  def visible=(bool)
    @layer_sprites.each{|sprite| sprite.visible = bool}
    @ground_sprite.visible = bool
  end
  #---------------------------------------------------------------------------
  # Set tileset
  #---------------------------------------------------------------------------
  def tileset=(bitmap)
    @tileset = bitmap
    if @tileset.width % 32 != 0 || @tileset.height % 32 != 0
      file = bitmap.filename
      raise "Your tileset graphic #{file} needs to be divisible by 32!"
    end
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set autotiles
  #---------------------------------------------------------------------------
  def autotiles=(array)
    CallBackController.delete(@autotiles)
    @autotiles = array
    proc = Proc.new { |i| @redraw_tilemap = true; setup_autotile(i) }
    CallBackController.setup_callback(@autotiles, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map data
  #---------------------------------------------------------------------------
  def map_data=(table)
    CallBackController.delete(@map_data)
    @map_data = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@map_data, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map priorities
  #---------------------------------------------------------------------------
  def priorities=(table)
    CallBackController.delete(@priorities)
    @priorities = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@priorities, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Get horizontal shift
  #---------------------------------------------------------------------------
  def ox
    @ox + @ox_float
  end
  #---------------------------------------------------------------------------
  # Get vertical shift
  #---------------------------------------------------------------------------
  def oy
    @oy + @oy_float
  end
  #---------------------------------------------------------------------------
  # Shift tilemap horizontally
  #---------------------------------------------------------------------------
  def ox=(ox)
    @ox_float = (ox - ox.to_i) % 1
    @ox = ox.floor
    @border_sprites.each{ |s|
      next if s.bitmap.height == 32
      s.ox = @ox
    }
  end
  #---------------------------------------------------------------------------
  # Shift tilemap vertically
  #---------------------------------------------------------------------------
  def oy=(oy)
    @oy_float = (oy - oy.to_i) % 1
    @oy = oy.floor
    @border_sprites.each{ |s|
      next if s.bitmap.width == 32
      s.oy = @oy
    }
  end
  #---------------------------------------------------------------------------
  # Update tilemap graphics
  #---------------------------------------------------------------------------
  def update; end;
  def draw
    # Figure out what the new X and Y coordinates for the ground layer would be
    x = @old_ox - @ox
    @old_ox = @ox
    x += @ground_sprite.x

    y = @old_oy - @oy
    @old_oy = @oy
    y += @ground_sprite.y

    # No reason to do sprite shifting if we're just redrawing everything
    if !@redraw_tilemap
      # If layers would be too far to the left
      if x < @viewport.ox - 31
        # If still too far, then force redraw
        if x + 32 < @viewport.ox - 31
          @redraw_tilemap = true
        else
          # Shift all layers right by 32 and clear out left-most column
          x += 32
          @ground_sprite.bitmap.fill_rect(0, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(0, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 1 # Redraw right column bit-flag (0001)
        end
      # If layers would be too far to the right
      elsif x > @viewport.ox
        # If still too far, then force redraw
        if x - 32 > @viewport.ox
          @redraw_tilemap = true
        else
          # Shift all layers left by 32 and clear out right-most column
          x -= 32
          @ground_sprite.bitmap.fill_rect(@ground_sprite.bitmap.width - 32, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(sprite.bitmap.width - 32, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 2 # Redraw left column bit-flag (0010)
        end
      end
      # Apply the change in X to the layers
      if !@redraw_tilemap
        @ground_sprite.x = x
        @layer_sprites.each{|sprite| sprite.x = x}

        # If layers would be too far up
        if y < @viewport.oy - 31
          # If still too far, then force redraw
          if y + 32 < @viewport.oy - 31
            @redraw_tilemap = true
          else
            y += 32
            layer = @layer_sprites.shift
            layer.bitmap.clear
            @layer_sprites.push(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            num = @layer_sprites.size
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[num-index].bitmap.fill_rect(0, (index - 1) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 4 # Redraw bottom row bit-flag (0100)
          end
        # If layers would be too far down
        elsif y > @viewport.oy
          # If still too far, then force redraw
          if y - 32 > @viewport.oy
            @redraw_tilemap = true
          else
            y -= 32
            layer = @layer_sprites.pop
            layer.bitmap.clear
            @layer_sprites.unshift(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[index].bitmap.fill_rect(0, (MAX_PRIORITY_LAYERS - 1 - index) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 8 # Redraw top row bit-flag (1000)
          end
        end
        # Apply the change to layers' Y and Z values
        if !@redraw_tilemap
          @ground_sprite.y = y
          @layer_sprites.each_index{ |i| sprite = @layer_sprites[i]
            sprite.y = y - 32 * (MAX_PRIORITY_LAYERS - 1 - i)
            sprite.z = sprite.y + (192 - (5 - MAX_PRIORITY_LAYERS) * 32)
          }
        end
      end
    end

    autotile_need_update = []
    # Update autotile animation frames
    for i in 0..6
      autotile_need_update[i] = false
      # If this autotile doesn't animate, skip
      next if @autotile_framedata[i].nil?
      # Reduce frame count
      @autotile_frame[i][1] -= 1
      # Autotile requires update
      if @autotile_frame[i][1] == 0
        @autotile_frame[i][0] = (@autotile_frame[i][0] + 1) % @autotile_framedata[i].size
        @autotile_frame[i][1] = @autotile_framedata[i][@autotile_frame[i][0]]
        autotile_need_update[i] = true
      end
    end
   
   
    # Stop the update unless redrawing, there is shifting, or an autotile needs to update
    return unless @redraw_tilemap || @shift != 0 || !autotile_need_update.index(true).nil?

    # Set up the array for the priority layers
    layers = [@layer_sprites.size + 1]
    # Insert higher priority layers into the array in order (least to most y-value sprite)
    @layer_sprites.each{|sprite| layers.push(sprite.bitmap.object_id) }
    # Insert ground layer last in the array
    layers.push(@ground_sprite.bitmap.object_id)
    # Load autotile bitmap graphics into array
    tile_bms = [self.tileset.object_id]
    self.autotiles.each{|autotile| tile_bms.push(autotile.object_id) }
    # Store autotile animation frame data
    autotiledata = []
    for i in 0..6
      autotiledata.push(@autotile_frame[i][0])
      autotiledata.push(autotile_need_update[i] ? 1 : 0)
    end
    # Fills in remaining information of other tilemaps
    misc_data = [@ox + @viewport.ox, @oy + @viewport.oy,
      self.map_data.object_id, self.priorities.object_id, @shift,
      MAX_PRIORITY_LAYERS, @wrapping]
   
    # If forcing fresh redraw of the map (or drawing for first time)
    if @redraw_tilemap
      # Initialize layer sprite positions and clear them for drawing
      @ground_sprite.bitmap.clear
      @ground_sprite.x = (@viewport.ox - @viewport.ox % 32) - (@ox % 32)
      @ground_sprite.x += 32 if @ground_sprite.x < @viewport.ox - 31
      @ground_sprite.y = (@viewport.oy - @viewport.oy % 32) - (@oy % 32)
      @ground_sprite.y += 32 if @ground_sprite.y < @viewport.oy - 31

      y_buffer = 32 * (MAX_PRIORITY_LAYERS - 1)
      z_buffer = MAX_PRIORITY_LAYERS * 32 + 32
      @layer_sprites.each_index{|i| layer = @layer_sprites[i]
        layer.bitmap.clear
        layer.x = @ground_sprite.x
        layer.y = @ground_sprite.y - y_buffer + 32 * i
        layer.z = layer.y + z_buffer
      }
      # Make DLL call
      @@initial_draw.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    elsif @shift != 0
      # Update for shifting
      @@update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Check for autotile updates (at least one autotile needs an update)
    # No need if redrawn tilemap since it already handled the updated autotiles
    if !@redraw_tilemap && !autotile_need_update.index(true).nil?
      @@autotile_update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Turn off flag
    @redraw_tilemap = false
    # Reset shift flag
    @shift = 0
  end
 
end
#===============================================================================
# ** Game_Player
#===============================================================================
class Game_Player
 
  CENTER_X = ((SCREEN_RESOLUTION[0] / 2) - 16) * 4    # Center screen x-coordinate * 4
  CENTER_Y = ((SCREEN_RESOLUTION[1] / 2) - 16) * 4    # Center screen y-coordinate * 4
 
  def center(x, y)
    # Recalculate the screen center based on the new resolution.
    max_x = (($game_map.width - (SCREEN_RESOLUTION[0]/32.0)) * 128).to_i
    max_y = (($game_map.height - (SCREEN_RESOLUTION[1]/32.0)) * 128).to_i
    $game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
    $game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
  end
end
#===============================================================================
# ** Game_Map
#===============================================================================
class Game_Map
  alias zer0_map_edge_setup setup
  def setup(map_id)
    zer0_map_edge_setup(map_id)
    # Find the displayed area of the map in tiles. No calcualting every step.
    @map_edge = [self.width - (SCREEN_RESOLUTION[0]/32.0), self.height - (SCREEN_RESOLUTION[1]/32.0)]
    @map_edge.collect! {|size| size * 128 }
    # Change the map center if map is smaller than the resolution
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      Game_Player.const_set(:CENTER_X, $game_map.width * 128)
    else
      Game_Player.const_set(:CENTER_X, ((SCREEN_RESOLUTION[0] / 2) - 16) * 4)
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      Game_Player.const_set(:CENTER_Y, $game_map.height * 128)
    else
      Game_Player.const_set(:CENTER_Y, ((SCREEN_RESOLUTION[1] / 2) - 16) * 4)
    end
  end

  def scroll_down(distance)
    # Find point that the map edge meets the screen edge, using custom size.
    @display_y = [@display_y + distance, @map_edge[1]].min
  end

  def scroll_right(distance)
    # Find point that the map edge meets the screen edge, using custom size.
    @display_x = [@display_x + distance, @map_edge[0]].min
  end
end

# Override set-methods to allow callbacks (necessary for Tilemap)
#===============================================================================
# ** Array
#===============================================================================
class Array
  alias flag_changes_to_set []=
  def []=(x, y)
    flag_changes_to_set(x, y)
    CallBackController.call(self, x, y)
  end
end
#===============================================================================
# ** Table
#===============================================================================
class Table
  alias flag_changes_to_set []=
  def []=(*args)
    flag_changes_to_set(*args)
    CallBackController.call(self, *args)
  end
end

if WEATHER_ADJUSTMENT
#===============================================================================
# ** RPG::Weather
#===============================================================================
class RPG::Weather
 
  alias add_more_weather_sprites initialize
  def initialize(vp = nil)
    add_more_weather_sprites(vp)
    total_sprites = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 7680
    if total_sprites > 40
      for i in 1..(total_sprites - 40)
        sprite = Sprite.new(vp)
        sprite.z = 1000
        sprite.visible = false
        sprite.opacity = 0
        @sprites.push(sprite)
      end
    end
  end
 
  def type=(type)
    return if @type == type
    @type = type
    case @type
    when 1
      bitmap = @rain_bitmap
    when 2
      bitmap = @storm_bitmap
    when 3
      bitmap = @snow_bitmap
    else
      bitmap = nil
    end
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
        sprite.bitmap = bitmap
      end
    end
  end
 
  def max=(max)
    return if @max == max;
    @max = [[max, 0].max, @sprites.size].min
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
      end
    end
  end
 
  def update
    return if @type == 0
    for i in 1..@max
      sprite = @sprites[i]
      if sprite == nil
        break
      end
      if @type == 1
        sprite.x -= 2
        sprite.y += 16
        sprite.opacity -= 8
      end
      if @type == 2
        sprite.x -= 8
        sprite.y += 16
        sprite.opacity -= 12
      end
      if @type == 3
        sprite.x -= 2
        sprite.y += 8
        sprite.opacity -= 8
      end
      x = sprite.x - @ox
      y = sprite.y - @oy
      if sprite.opacity < 64
        sprite.x = rand(SCREEN_RESOLUTION[0] + 100) - 100 + @ox
        sprite.y = rand(SCREEN_RESOLUTION[0] + 200) - 200 + @oy
        sprite.opacity = 160 + rand(96)
      end
    end
  end
 
end
#===============================================================================
# ** Game_Screen
#===============================================================================
class Game_Screen
  #--------------------------------------------------------------------------
  # * Set Weather
  #     type : type
  #     power : strength
  #     duration : time
  #--------------------------------------------------------------------------
  def weather(type, power, duration)
    @weather_type_target = type
    if @weather_type_target != 0
      @weather_type = @weather_type_target
    end
    if @weather_type_target == 0
      @weather_max_target = 0.0
    else
      num = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 76800.0
      @weather_max_target = (power + 1) * num
    end
    @weather_duration = duration
    if @weather_duration == 0
      @weather_type = @weather_type_target
      @weather_max = @weather_max_target
    end
  end
 
end

end # if WEATHER_ADJUSTMENT
#===============================================================================
# ** Spriteset_Map
#===============================================================================
class Spriteset_Map

  alias init_for_centered_small_maps initialize
  #---------------------------------------------------------------------------
  # Resize and reposition viewport so that it fits smaller maps
  #---------------------------------------------------------------------------
  def initialize
    @center_offsets = [0,0]
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      x = (SCREEN_RESOLUTION[0] - $game_map.width * 32) / 2
    else
      x = 0
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      y = (SCREEN_RESOLUTION[1] - $game_map.height * 32) / 2
    else
      y = 0
    end
    init_for_centered_small_maps
    w = [$game_map.width  * 32 , SCREEN_RESOLUTION[0]].min
    h = [$game_map.height * 32 , SCREEN_RESOLUTION[1]].min
    @viewport1.resize(x,y,w,h)
  end
  #---------------------------------------------------------------------------
  # Puts the tilemap update method at the end, ensuring that both
  # @tilemap.ox/oy and @viewport1.ox/oy are set.
  #---------------------------------------------------------------------------
  alias update_tilemap_for_real update
  def update
    update_tilemap_for_real
    @tilemap.draw
  end
end

# The following script will only be enabled if the resolution is bigger than the
# default OR if the game does not want certain maps to wrap around.
if DISABLE_WRAP || SCREEN_RESOLUTION[0] > 640 || SCREEN_RESOLUTION[1] > 480
#--------------------------------------------[Unlimited Resolution by Hime]-----
=begin
#===============================================================================
Title: Unlimited Resolution
Date: Oct 24, 2013
Author: Hime ( ** Modified by KK20 ** )
--------------------------------------------------------------------------------   
Terms of Use
Free
--------------------------------------------------------------------------------
Description

This script modifies Graphics.resize_screen to overcome the 640x480 limitation.
It also includes some modifications to module Graphics such as allowing the
default fade transition to cover the entire screen.

Now you can have arbitrarily large game resolutions.
--------------------------------------------------------------------------------
Credits

Unknown author for overcoming the 640x480 limitation
Lantier, from RMW forums for posting the snippet above
Esrever for handling the viewport
Jet, for the custom Graphics code
FenixFyre, for the Plane class fix
Kaelan, for several bug fixes
--------------------------------------------------------------------------------
KK20 Notes:
- Plane class was rewritten from the original script. Certain lines in the
   unknown scripter's code can be omitted entirely to allow this implementation.
- Likewise, the Viewport class needed new methods to handle this Plane rewrite.
- This entire script only applies to games that go beyond the default 640x480
   resolution.

#===============================================================================
=end
unless XPACE
class Bitmap
  #----------------------------------------------------------------------------
  # ● New method: address
  #----------------------------------------------------------------------------
  def address
    @rtlmemory_pi ||= Win32API.new('kernel32','RtlMoveMemory','pii','i')
    @address ||= (  @rtlmemory_pi.call(a="\0"*4, __id__*2+16, 4)
                      @rtlmemory_pi.call(a, a.unpack('L')[0]+8, 4)
                      @rtlmemory_pi.call(a, a.unpack('L')[0]+16, 4)
                      a.unpack('L')[0]    )
  end
end
end
#===============================================================================
# ** Graphics
#===============================================================================
module Graphics
 
  @@super_sprite = Sprite.new
  @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
 
  class << self
   
    def freeze(*args, &block)
      ensure_sprite
      @@super_sprite.bitmap = snap_to_bitmap
    end
   
    def transition(time = 10, filename = nil, vague = nil)
      if filename
        @@super_sprite.bitmap = Bitmap.new(filename)
      end
      @@super_sprite.opacity = 255
      incs = 255.0 / time
      time.times do |i|
        @@super_sprite.opacity = 255.0 - incs * i
        Graphics.wait(1)
      end
      @@super_sprite.bitmap.dispose if @@super_sprite.bitmap
      reform_sprite_bitmap
      Graphics.brightness = 255
    end
   
    def reform_sprite_bitmap
      @@super_sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
      @@super_sprite.bitmap.fill_rect(@@super_sprite.bitmap.rect, Color.new(0, 0, 0, 255))
    end
   
    def fadeout(frames)
      incs = 255.0 / frames
      frames.times do |i|
        i += 1
        Graphics.brightness = 255 - incs * i
        Graphics.wait(1)
      end
    end
   
    def fadein(frames)
      incs = 255.0 / frames
      frames.times do |i|
        Graphics.brightness = incs * i
        Graphics.wait(1)
      end
    end

    def brightness=(i)
      @@super_sprite.opacity = 255.0 - i
    end
   
    def brightness
      255 - @@super_sprite.opacity
    end
   
    def ensure_sprite
      if @@super_sprite.disposed?
        @@super_sprite = Sprite.new
        @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
        reform_sprite_bitmap
      end
    end
   
    # XP does not have a snap_to_bitmap method built-in
    unless XPACE
      define_method(:width)  { Resolution.size.at(0) }
      define_method(:height) { Resolution.size.at(1) }
      #--------------------------------------------------------------------------
      # * snap_to_bitmap
      #--------------------------------------------------------------------------
      def snap_to_bitmap
        @window      ||= Win32API.new('user32','GetActiveWindow', '', 'L')
        @getdc       ||= Win32API.new('user32','GetDC','i','i')
        @ccdc        ||= Win32API.new('gdi32','CreateCompatibleDC','i','i')
        @selectobject||= Win32API.new('gdi32','SelectObject','ii','i')
        @deleteobject||= Win32API.new('gdi32','DeleteObject','i','i')
        @setdibits   ||= Win32API.new('gdi32','SetDIBits','iiiiipi','i')
        @getdibits   ||= Win32API.new('gdi32','GetDIBits','iiiiipi','i')
        @bitblt      ||= Win32API.new('gdi32','BitBlt','iiiiiiiii','i')
        @ccbitmap    ||= Win32API.new('gdi32','CreateCompatibleBitmap','iii','i')
       
        bitmap = Bitmap.new(w = Graphics.width,h = Graphics.height)
        @deleteobject.call(@selectobject.call((hDC = @ccdc.call((dc = @getdc.call(@window.call)))),(hBM = @ccbitmap.call(dc,w,h))))
        @setdibits.call(hDC, hBM, 0, h, (a = bitmap.address), (info = [40,w,h,1,32,0,0,0,0,0,0].pack('LllSSLLllLL')), 0)
        @bitblt.call(hDC, 0, 0, w, h, dc, 0, 0, 0xCC0020)
        @getdibits.call(hDC, hBM, 0, h, a, info, 0)
        @deleteobject.call(hBM)
        @deleteobject.call(hDC)
        return bitmap
      end 
   
      def wait(frame=1)
        frame.times {|s| update }
      end
    end
 
# Graphics.resize_screen is only for XPA games
if XPACE
    #-----------------------------------------------------------------------------
    # Unknown Scripter. Copied from http://pastebin.com/sM2MNJZj
    #-----------------------------------------------------------------------------
    alias :th_large_screen_resize_screen :resize_screen
    def resize_screen(width, height)
      wt, ht = width.divmod(32), height.divmod(32)
      #wt.last + ht.last == 0 || fail('Incorrect width or height')
      #wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ }
      wh = lambda {|w,h,off| [w + off, h + off].pack('l2').scan(/.{4}/) }
      w, h     = wh.call(width, height,0)
      ww, hh   = wh.call(width, height, 32)
      www, hhh = wh.call(wt.first.succ, ht.first.succ,0)
      base = 0x10000000  # fixed?
      #mod = -> adr, val { DL::CPtr.new(base + adr)[0, val.size] = val }
      mod = lambda {|adr,val| (DL::CPtr.new(base + adr))[0, val.size] = val}
      # Didn't see anything happen here
  #    mod.(0x195F, "\x90" * 5)  # ???
  #    mod.(0x19A4, h)
  #    mod.(0x19A9, w)
  #    mod.(0x1A56, h)
  #    mod.(0x1A5B, w)
   
      # The following four seem to change the window size. But I dunno why there
      # are two. I commented out a pair of them but they still do the same thing.
      mod.call(0x20F6, w) && mod.call(0x20FF, w)     
      mod.call(0x2106, h) && mod.call(0x210F, h) 
     
      # speed up y?
      #mod.(0x1C5E3, h) ##
      #mod.(0x1C5E8, w) ##
      #zero = [0].pack ?l
      zero = [0].pack(?l)
     
      # Without these, I can use the default Plane class
  #    mod.(0x1C5E3, zero)
  #    mod.(0x1C5E8, zero)
   
      # And not sure what these do
  #    mod.(0x1F477, h)
  #    mod.(0x1F47C, w)
  #    mod.(0x211FF, hh)
  #    mod.(0x21204, ww)
  #    mod.(0x21D7D, hhh[0])
  #    mod.(0x21E01, www[0])
  #    mod.(0x10DEA8, h)
  #    mod.(0x10DEAD, w)
  #    mod.(0x10DEDF, h)
  #    mod.(0x10DEF0, w)
  #    mod.(0x10DF14, h)
  #    mod.(0x10DF18, w)
  #    mod.(0x10DF48, h)
  #    mod.(0x10DF4C, w)
  #    mod.(0x10E6A7, w)
  #    mod.(0x10E6C3, h)
  #    mod.(0x10EEA9, w)
  #    mod.(0x10EEB9, h)
      th_large_screen_resize_screen(width, height)
    end
   
  end # class << self
 
end # if XPACE

end
#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :parent, :children
 
  alias init_children_vps initialize
  def initialize(*args)
    @children = []
    @parent = false
    init_children_vps(*args)
  end
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias flash_parent flash
  def flash(color, duration)
    if @parent
      @children.each{|child| child.flash_parent(color, duration)}
    else
      flash_parent(color, duration)
    end
  end
 
  alias update_parent update
  def update
    @children.each{|child| child.update} if @parent
    update_parent
  end
 
  alias resize_trigger resize
  def resize(*args)
    @children.each{ |child|
      if args[0].is_a?(Rect)
        rect = args[0]
        new_args = Rect.new(rect.x,rect.y,child.rect.width,child.rect.height)
      else
        new_args = [args[0],args[1]]
        new_args[2] = child.rect.width
        new_args[3] = child.rect.height
      end
      child.resize_trigger(*new_args)
    } if @parent
    resize_trigger(*args)
  end
 
  alias set_trigger_vp_ox ox=
  def ox=(nx)
    return if self.ox == nx
    set_trigger_vp_ox(nx)
    @children.each{|child| child.ox = nx}
  end
 
  alias set_trigger_vp_oy oy=
  def oy=(ny)
    return if self.oy == ny
    set_trigger_vp_oy(ny)
    @children.each{|child| child.oy = ny}
  end
 
  alias tone_parent tone=
  def tone=(t)
    if @parent
      @children.each{|child| child.tone_parent(t)}
    else
      tone_parent(t)
    end
  end

end
#===============================================================================
# ** Plane
#===============================================================================
class Plane
  attr_accessor :offset_x, :offset_y
 
  alias parent_initialize initialize
  def initialize(viewport=nil,parent=true)
    @parent = parent
    @children = []
    parent_initialize(viewport)
    @offset_x = 0
    @offset_y = 0
    # If the parent Plane object; but don't make more children if already have
    # some. This occurs in Spriteset_Map when initializing the Panorama and Fog
    if @parent && viewport
      viewport.parent = true
      create_children
    end
  end
 
  def create_children
    gw = [SCREEN_RESOLUTION[0], $game_map.width * 32].min
    gh = [SCREEN_RESOLUTION[1], $game_map.height * 32].min
    w = (gw - 1) / 640
    h = (gh - 1) / 480
    for y in 0..h
      for x in 0..w
        # This is the top-left default/parent Plane, so skip it
        #next if x == 0 && y == 0
        # Create viewport unless it already exists
        width = w > 0 && x == w ? gw - 640 : 640
        height = h > 0 && y == h ? gh - 480 : 480
        vp = Viewport.new(x * 640, y * 480, width, height, true)
        vp.offset_x = x * 640
        vp.offset_y = y * 480
        # Have to do this in order to prevent overlapping with the parent
        # (for Spriteset_Map viewport1 mainly)
        vp.z = self.viewport.z - 1
        self.viewport.children.push(vp)
        # Create the child Plane
        plane = Plane.new(vp,false)
        plane.offset_x = x * 640
        plane.ox = 0
        plane.offset_y = y * 480
        plane.oy = 0
        # Push to array
        @children.push(plane)
      end
    end
  end
 
  # For the remaining Plane properties, if the parent changes, so do its children
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias zoom_x_parent zoom_x=
  def zoom_x=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_x_parent(new_val)} if @parent
    zoom_x_parent(new_val)
  end
 
  alias zoom_y_parent zoom_y=
  def zoom_y=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_y_parent(new_val)} if @parent
    zoom_y_parent(new_val)
  end
 
  alias ox_parent ox=
  def ox=(new_val)
    @children.each{|child| child.ox = new_val} if @parent
    ox_parent(new_val + @offset_x)
  end
 
  alias oy_parent oy=
  def oy=(new_val)
    @children.each{|child| child.oy = new_val} if @parent
    oy_parent(new_val + @offset_y)
  end
 
  alias bitmap_parent bitmap=
  def bitmap=(new_val)
    @children.each{|child| child.bitmap_parent(new_val)} if @parent
    #bitmap_parent(new_val)
  end
 
  alias visible_parent visible=
  def visible=(new_val)
    @children.each{|child| child.visible_parent(new_val)} if @parent
    visible_parent(new_val)
  end
 
  alias z_parent z=
  def z=(new_val)
    # Because the children spawn new Viewports, they have to be lower than the
    # parent's viewport to prevent drawing OVER the parent...unless the Plane's
    # z-value is more than zero, in which case the children viewports NEED to be
    # higher than the parent's. By doing this, we can have panoramas be below
    # the tilemap and fogs be over the tilemap.
    if @parent && @children[0]
      child = @children[0]
      if new_val > 0 && child.viewport.z < self.viewport.z
        @children.each{|child| child.viewport.z += 1}
      elsif new_val <= 0 && child.viewport.z >= self.viewport.z
        @children.each{|child| child.viewport.z -= 1}
      end
    end
   
    @children.each{|child| child.z_parent(new_val)} if @parent
    z_parent(new_val)
  end
 
  alias opacity_parent opacity=
  def opacity=(new_val)
    @children.each{|child| child.opacity_parent(new_val)} if @parent
    opacity_parent(new_val)
  end
 
  alias color_parent color=
  def color=(new_val)
    if @parent
      @children.each{|child| child.color_parent(new_val)}
    else
      color_parent(new_val)
    end
  end
 
  alias blend_type_parent blend_type=
  def blend_type=(new_val)
    @children.each{|child| child.blend_type_parent(new_val)} if @parent
    blend_type_parent(new_val)
  end
 
  alias tone_parent tone=
  def tone=(new_val)
    if @parent
      @children.each{|child| child.tone_parent(new_val)}
    else
      tone_parent(new_val)
    end
  end
 
end
#------------------------------------------[End of Unlimited Resolution]--------
end

# Resize the game window (if using XP) and load the MapInfos file
Resolution.resize_game unless XPACE
XPAT_MAP_INFOS = load_data("Data/MapInfos.rxdata")


CallBackController is only used by the Tilemap class to ensure that, whenever a few of its variables are modified, the map can redraw to show those changes (e.g. doing a script call like $game_map.data[x, y, z] = tile_id will update the map to show the new tile). I wasn't properly disposing the references in the controller; hence every time a new Tilemap was drawn, it would accumulate more and more references and eat up the players' alloted memory until the game runs out of space and crashes. The easy fix was just to clear out the controller before the creation of a new Tilemap.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on June 18, 2017, 04:38:29 am
Hey, it's me again. I found two issues, that hopefully might improve compatibility if fixed.
I tried using Emotions Script, but I can't change the target of emotion, it's always stuck to the player.
And Heretics Circular Sprite Motion just doesn't work. Without throwing any error.
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>SCRIPT<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
#                                                               #
#                        Emotions Script                        #
#                by Ánemus (www.arcadiumrpg.net)                #
#                                                               #
#  This script shows emotions over the player or over the other #
#                     characters of the map.                    #
#                                                               #
#                  $scene.emotion(id,ev,image)                  #
#                                                               #
#           For any comments: anemus@arcadiumrpg.net            #
#                                                               #
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>SETTINGS<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
#                                                               #
# Number of Repetitions or LOOP:                                #
# That's the number of times the animation of the emotion will  #
# repeat. I recomend 1, because bigger numbers are just way to  #
# repetitive.                                                   #
LOOP = 1
#                                                               #
# Delay:                                                        #
# That's the slowness of the animation. I recomend 3 or 4,      #
# smaller numbers are like flashes, so they aren't really       #
# useful.                                                       #
DELAY = 4
#                                                               #
# Deafult file for emotions:                                    #
# This is a tool to make it easier to use, this way you just    #
# write the id of the animation and the event where you want to #
# show it.
DEFAULTFILE = "Balloon"
#                                                               #
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>INSTRUCTIONS<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
#                                                               #
# Whenever you want to use it just use Call Script command      #
# then write:                                                   #
# $scene.emotion(id, ev, image)                                 #
# Being id the number of the emotion in the file (the top one is#
# the 0 and the lowest one the 9), ev the event over which you  #
# are showing the emotion (being -1 for the player and any      #
# other number for events, and image, that is the image file    #
# that you are using for the emotions. This file is to be placed#
# on Pictures folder and should be 256x320 px.                  #
#                                                               #
# Some tips:                                                    #
# If you are using the emotion file specified in DEFAULTFILE    #
# you dont need to include it in the sentence.                  #
# $scene.emotion(id, ev)                                        #
# Now if you are using the default file and also placing the    #
# emotion on the main character, the sentence is reduced to:    #
# $scene.emotion(id)                                            #
#                                                               #
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>END<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#

#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>CODE<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
class Sprite_Character < RPG::Sprite
  alias :old_updateEmo :update
  def update
    old_updateEmo
    if @frames != nil
      @pic.x = (@character.screen_x + 5)
      @pic.y = (@character.screen_y - @ph - @ch.to_i+2)
      if @frames > (1 + LOOP*7)*DELAY
        @pic.zoom_x = 0.6
        @pic.zoom_y = 0.6
        @pic.opacity = 100
        @frames -= 1
        return
      elsif @frames > (LOOP*7)*DELAY
        @pic.zoom_x = 1
        @pic.zoom_y = 1
        @pic.opacity = 255
        @frames -= 1
        @iframe = 1
        @gota = 0
        return
      elsif @frames == 0
        @frames = nil
        @pic.bitmap.dispose
        @pic.dispose
        @picid = nil
        return
      else
        @pic.bitmap.clear
        @pic.bitmap.blt(0,0,RPG::Cache.picture(@picig),Rect.new(@iframe*32, @picid*32, 32, 32))
        @pic.zoom_x = 1
        @pic.zoom_y = 1
        @pic.opacity = 255
        @frames -= 1
        if @gota == DELAY
          @iframe += 1
          if @iframe > 7
            @iframe = 1
          end
          @gota = 0
        end
        @gota +=1
      end
    end
  end
  def emotion (id,ig="Balloon",wt=false)
    if !FileTest.exist?("Graphics/Pictures/"+ig+".png")
      return 0
    end
    @frames = (2 + LOOP*7)*DELAY
    @picid = id > 9 ? 9 : id
    @picig = ig
    @pic = Sprite.new
    @pic.bitmap = Bitmap.new(32,32)
    @pic.bitmap.blt(0, 0, RPG::Cache.picture(@picig), Rect.new(0,32*@picid,32,32))
    @pic.ox = @pic.bitmap.width / 2
    @pic.oy = @ph = @pic.bitmap.height / 2
    @pic.z = 100
    if wt
      return @frames
    else
      return 0
    end
  end
  def dispose
    super
    if @pic != nil
      @pic.bitmap.dispose
      @pic.dispose
    end
  end
end
class Spriteset_Map
  def emotion (id,ev=-1,ig=DEFAULTFILE,wt=false)
    if ev.to_i > -1
      @frames = @character_sprites[ev].emotion(id,ig,wt)
    else
      @frames = @character_sprites[@character_sprites.size - 1].emotion(id,ig,wt)
    end
    return @frames
  end
end
class Scene_Map
  def emotion(id,ev=-1,ig=DEFAULTFILE,wt=false)
    $game_system.map_interpreter.wait_count = @spriteset.emotion(id,ev,ig,wt)
  end
end
class Interpreter
  def wait_count=(frames)
    @wait_count = frames.to_i
  end
end

Thanks for keeping this script alive. I appreciate it.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 18, 2017, 04:50:20 pm
Emotions Script:
Let me guess...you tried to play an emotion over the LAST EVENT ID on the map. If your map had only one event, obviously its ID would be 1. So your script call would look like
$scene.emotion(ID, 1)

But this would play over the player.
The author clearly did not test their code at all. If you were to create a second event on the map, you will actually see the emotion effect play over this new event instead. In short, the event ID you want the emotion to play over is actually one less than the event's actual ID.

Here's the fix. Find and replace this class in the Emotions script

class Spriteset_Map
  def emotion (id,ev=-1,ig=DEFAULTFILE,wt=false)
    if ev.to_i > 0
      @frames = @character_sprites[ev - 1].emotion(id,ig,wt)
    else
      @frames = @character_sprites[@character_sprites.size - 1].emotion(id,ig,wt)
    end
    return @frames
  end
end


Circular Motion:
First off, the script mentions you need Modular Passable (http://forum.chaos-project.com/index.php/topic,14986.0.html) placed above Circular Sprite Motion.
Secondly, your event page should look something like this:

Comment: \spin
Comment: \spin_radius[N]
Comment: \spin_speed[N]

Note the BACKSLASH. It's not FORWARD SLASH as the instructions make it out to be. Also, these have to be three separate comment commands, not one comment with all three lines in it.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on June 19, 2017, 02:12:18 am
Thanks for fixing the emotions script, I would've never figure it out.
When it comes to Circular Motion, I noticed that XPA installed into demo works alright. But when I copy everything - events too - correctly into new project, it just doesn't work. I've read instructions.
Sorry for spamming your thread with not related problems, next time I'll make sure if it's tied to XPA.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 19, 2017, 02:24:01 am
Want to give me a demo then? I got it working fine on my end.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on June 19, 2017, 02:46:17 am
Alright, here's demo. - http://www96.zippyshare.com/v/JgrzbsIx/file.html
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 19, 2017, 03:14:48 am
__END__

This was at the very top of your Circular Motion script. What it does is effectively ignore everything below it. The game didn't even load the script.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on June 20, 2017, 02:08:27 pm
^ I didn't add this line, it's straight out of demo. :O.o:

Now I'm sure, I've found bug connected to XPA, take a look what happens when translucent shadows have priority set to 1 - https://youtu.be/Iv3bn3mhpwI
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 20, 2017, 02:39:27 pm
That's been fixed in an update to the Tilemap. The current XPA package still uses an older version.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on June 20, 2017, 03:01:17 pm
I'm using version 0.34 and this bug still occures.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 20, 2017, 03:27:25 pm
Well shit you're right. How this escaped me for this long, I do not know.
Find this in the script (around line 920)

            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[num-index].bitmap.fill_rect(0, (index - 1) * 32, width, 32, Color.new(0,0,0,0))
            }

Just remove a period in the 1...MAX_PRIORITY_LAYERS bit.

Thanks for finding this :P
Title: Re: [XP] XP Ace Tilemap
Post by: Heretic86 on June 22, 2017, 10:59:18 pm
Quote from: Kise on June 18, 2017, 04:38:29 am
Hey, it's me again. I found two issues, that hopefully might improve compatibility if fixed.
I tried using Emotions Script, but I can't change the target of emotion, it's always stuck to the player.
And Heretics Circular Sprite Motion just doesn't work. Without throwing any error.
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>SCRIPT<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
#                                                               #
#                        Emotions Script                        #
#                by Ánemus (www.arcadiumrpg.net)                #
#                                                               #
#  This script shows emotions over the player or over the other #
#                     characters of the map.                    #
#                                                               #
#                  $scene.emotion(id,ev,image)                  #
#                                                               #
#           For any comments: anemus@arcadiumrpg.net            #
#                                                               #
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>SETTINGS<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
#                                                               #
# Number of Repetitions or LOOP:                                #
# That's the number of times the animation of the emotion will  #
# repeat. I recomend 1, because bigger numbers are just way to  #
# repetitive.                                                   #
LOOP = 1
#                                                               #
# Delay:                                                        #
# That's the slowness of the animation. I recomend 3 or 4,      #
# smaller numbers are like flashes, so they aren't really       #
# useful.                                                       #
DELAY = 4
#                                                               #
# Deafult file for emotions:                                    #
# This is a tool to make it easier to use, this way you just    #
# write the id of the animation and the event where you want to #
# show it.
DEFAULTFILE = "Balloon"
#                                                               #
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>INSTRUCTIONS<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
#                                                               #
# Whenever you want to use it just use Call Script command      #
# then write:                                                   #
# $scene.emotion(id, ev, image)                                 #
# Being id the number of the emotion in the file (the top one is#
# the 0 and the lowest one the 9), ev the event over which you  #
# are showing the emotion (being -1 for the player and any      #
# other number for events, and image, that is the image file    #
# that you are using for the emotions. This file is to be placed#
# on Pictures folder and should be 256x320 px.                  #
#                                                               #
# Some tips:                                                    #
# If you are using the emotion file specified in DEFAULTFILE    #
# you dont need to include it in the sentence.                  #
# $scene.emotion(id, ev)                                        #
# Now if you are using the default file and also placing the    #
# emotion on the main character, the sentence is reduced to:    #
# $scene.emotion(id)                                            #
#                                                               #
#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>END<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#

#===============================================================#
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>CODE<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<#
#===============================================================#
class Sprite_Character < RPG::Sprite
  alias :old_updateEmo :update
  def update
    old_updateEmo
    if @frames != nil
      @pic.x = (@character.screen_x + 5)
      @pic.y = (@character.screen_y - @ph - @ch.to_i+2)
      if @frames > (1 + LOOP*7)*DELAY
        @pic.zoom_x = 0.6
        @pic.zoom_y = 0.6
        @pic.opacity = 100
        @frames -= 1
        return
      elsif @frames > (LOOP*7)*DELAY
        @pic.zoom_x = 1
        @pic.zoom_y = 1
        @pic.opacity = 255
        @frames -= 1
        @iframe = 1
        @gota = 0
        return
      elsif @frames == 0
        @frames = nil
        @pic.bitmap.dispose
        @pic.dispose
        @picid = nil
        return
      else
        @pic.bitmap.clear
        @pic.bitmap.blt(0,0,RPG::Cache.picture(@picig),Rect.new(@iframe*32, @picid*32, 32, 32))
        @pic.zoom_x = 1
        @pic.zoom_y = 1
        @pic.opacity = 255
        @frames -= 1
        if @gota == DELAY
          @iframe += 1
          if @iframe > 7
            @iframe = 1
          end
          @gota = 0
        end
        @gota +=1
      end
    end
  end
  def emotion (id,ig="Balloon",wt=false)
    if !FileTest.exist?("Graphics/Pictures/"+ig+".png")
      return 0
    end
    @frames = (2 + LOOP*7)*DELAY
    @picid = id > 9 ? 9 : id
    @picig = ig
    @pic = Sprite.new
    @pic.bitmap = Bitmap.new(32,32)
    @pic.bitmap.blt(0, 0, RPG::Cache.picture(@picig), Rect.new(0,32*@picid,32,32))
    @pic.ox = @pic.bitmap.width / 2
    @pic.oy = @ph = @pic.bitmap.height / 2
    @pic.z = 100
    if wt
      return @frames
    else
      return 0
    end
  end
  def dispose
    super
    if @pic != nil
      @pic.bitmap.dispose
      @pic.dispose
    end
  end
end
class Spriteset_Map
  def emotion (id,ev=-1,ig=DEFAULTFILE,wt=false)
    if ev.to_i > -1
      @frames = @character_sprites[ev].emotion(id,ig,wt)
    else
      @frames = @character_sprites[@character_sprites.size - 1].emotion(id,ig,wt)
    end
    return @frames
  end
end
class Scene_Map
  def emotion(id,ev=-1,ig=DEFAULTFILE,wt=false)
    $game_system.map_interpreter.wait_count = @spriteset.emotion(id,ev,ig,wt)
  end
end
class Interpreter
  def wait_count=(frames)
    @wait_count = frames.to_i
  end
end

Thanks for keeping this script alive. I appreciate it.


First things first, do you have Modular Passable?  Its required because that is what allows the comments to be read for any Circular options.

Next, it should be below Modular Passable.  However, I do not believe the order of the scripts afterwards is important, but you can try putting Circular Sprite Motion below the Emotions Script.

Please advise if this helped to correct your issue or not.  Thanks!

EDIT: Nevermind, I didnt read the rest of the posts in the thread.  Glad you got it working!  :D
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on June 22, 2017, 11:18:35 pm
It was just because he had a
__END__
at the top of the Circular Motion script. As stated in his reply,
QuoteI didn't add this line, it's straight out of demo.

Which I find particularly odd.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on June 23, 2017, 01:39:36 am
Eh, it happens. I've uploaded tons of faulty demos in my time. xD
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on July 04, 2017, 03:22:35 pm
Event Transitions is not compatible with XPA - it's throwing Syntax Error.
http://forum.chaos-project.com/index.php?topic=13634.5

...and Blizzard's Anti Lag is not working as well.
http://forum.chaos-project.com/index.php?topic=104.0
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on July 06, 2017, 02:48:49 am
For the syntax error in transitions, if you're talking about "unexpected ':', expecting keyword_then" that has nothing to do with the Tilemap and moreso to do with Ruby 1.8 vs 1.9

#BAD
when 1: "First"
when 2: "Second"

#GOOD
when 1 then "First"
when 2 then "Second"

# ALSO GOOD
when 1
  "First"
when 2
  "Second"

Since TDS already has his whens separated with a newline, just delete the colon in front of them.

          when 0, 1, 2, 3, 4
            sprite[3].dispose
          when 5
            sprite[3].each { |el| el.dispose }
            sprite[3] = []


What about anti-lag is not working?
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on July 06, 2017, 04:44:17 am
With antilag I get superlass mismatch error.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on July 06, 2017, 04:47:33 am
Yeah, that would be the superclass mismatch helper script bundled in the XPA package. I'm still looking for a good solution to resolve that. Did you get a notification that a superclass mismatch was found and you should reopen the project? Do that.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on July 06, 2017, 06:55:54 am
No, i don't get that notification. Program has problem with this line ("TypeError") -

class Sprite_Character < Control_Sprite_Character
 
end

> superclass mismatch for class Sprite_Character.

It seems to work after deleting those two lines.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on July 06, 2017, 02:25:40 pm
In the XPA Configuration, this should be enabled:

  # Checks your scripts for any superclass mismatches and fixes them. This
  # script will run automatically upon test-playing your game. It will make the
  # necessary changes to your scripts and save them directly to your
  # Scripts.rxdata file.
  # Use true or false to enable or disable this script.
  SUPERCLASS_MISMATCH_HELPER = true

Running the project now should fix the superclass mismatch error and the message will pop up saying to reopen your project to apply the fix. You will get a "stack level too deep" error if you try to start a new game.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on July 08, 2017, 06:30:41 am
Yeah, that fixes problem with antilag, but also gets rid of every foreign font character - like 'ą, ź' etc.

Btw. Would it be possible to use VX Ace features like blurring effect on XPA?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on July 08, 2017, 03:49:28 pm
Can you explain the situation where those characters are removed/replaced? I tried simulating a superclass mismatch, had the script find and fix the issue, reopened project, and the two characters you provided were still present in another script.

If by blurring effects you mean RGSS3's built in Bitmap#blur method, then yes, it works.
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on July 09, 2017, 03:12:08 am
That's the script which causes problems.

Spoiler: ShowHide

#==============================================================================
# Text Cache
# by atoa
#==============================================================================
# This script has the objective of storing text bitmap objects in cache.
# By deafult, the RPG Maker draw each character individually from
# scratch, even if the same character is repeated frequently.
# This make bitmap.draw_text really slow.
#
# This script store the character bitmap on cache at the first it's drawn,
# and then use an clone of that bitmap if it's needed again
#
# The main objective of this script is reduce the lag caused by windows
# that are updated constantly or windows with really long text.
#
# The script has one drawback: if the text is bigger than the width set
# for the draw_text, it won't be streched to fit the smaller space.
#==============================================================================

#==============================================================================
# ■ Bitmap
#------------------------------------------------------------------------------
# Classe that handles bitmaps
#==============================================================================

class Bitmap
  #------------------------------------------------------------------------------
  # Draw text
  #     x      : Text Coord X or text rect
  #     y      : Text Coord y or text sting
  #     width  : Text width or text align
  #     height : Text height
  #     str    : Text string
  #     align  : Text align
  #------------------------------------------------------------------------------
  alias text_cache_draw_text draw_text if !method_defined?(:text_cache_draw_text)
  def draw_text(x, y, width = 0, height = 0, str = '', align = 0)
    case x
    when Numeric
      adj = align == 0 ? 0 : align == 1 ? (width / 2) - (text_size(str).width / 2) : width  - text_size(str).width
      i = 0 
      for digit in str.to_s.split('')
        bitmap = check_bitmap(digit)
        blt(adj + x + i, y + 4, bitmap[0], bitmap[1])
        i += bitmap[0].width - 2
      end
    when Rect
      rect  = x
      str   = y
      align = width
      adj = align == 0 ? 0 : align == 1 ? (rect.width / 2) - (text_size(str).width / 2) : rect.width  - text_size(str).width
      i = 0 
      for digit in str.to_s.split('')
        bitmap = check_bitmap(digit)
        blt(adj + rect.x + i, rect.y + 4, bitmap[0], bitmap[1])
        i += bitmap[0].width - 2
      end
    end
  end
  #------------------------------------------------------------------------------
  # Check if bitmap is areay in cache
  #   digit : digit to be drawn
  #------------------------------------------------------------------------------
  def check_bitmap(digit)
    $text_cache ||= {}
    color = [font.color.red, font.color.green, font.color.blue, font.color.alpha]
    key = [digit, color, font.size, font.name]
    if $text_cache[key].nil? or $text_cache[key][0].disposed?
     width = text_size(digit).width + 2
      height = text_size(digit).height + 2
      b = Bitmap.new(width, height)
      $text_cache[key] = [b, b.rect]
      b.font.name = font.name
      b.font.size = font.size
      b.font.color.set(color[0], color[1], color[2], color[3])
      b.text_cache_draw_text(0, 0, width, height, digit)
    end
    return $text_cache[key]
  end
end

#==============================================================================
# ■ Object
#------------------------------------------------------------------------------
# All classes inherit methods from this class
#==============================================================================

class Object
  #------------------------------------------------------------------------------
  # clear text cache
  #------------------------------------------------------------------------------
  def clear_text_cache
    $text_cache ||= {}
    for key in $text_cache.key
      $text_cache[key].dispose
    end
    $text_cache.clear
  end
end


I would like to blur background in menus. I always loved this effect on newer makers. Could you share the code snippet that does that? I'd insert it myself.
Title: Re: [XP] XP Ace Tilemap
Post by: LiTTleDRAgo on July 09, 2017, 05:58:54 am
bitmap = Bitmap.new(32,32)
bitmap.blur

angle    = 180 # 0-360
division = 10  # 2-100
bitmap   = Bitmap.new(32,32)
bitmap.radial_blur(angle,division)
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on July 10, 2017, 04:09:50 am
I made an update to the Superclass Mismatch Helper (SMH) so UTF-8 characters will be displayed properly. Ideally though, you should only run your game with SMH until all superclass errors are resolved.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on August 01, 2017, 04:01:17 am
Updated to Version 0.35

Just some bug fixes that were reported earlier, like priority 1 tiles with opacity were drawing over each other, autotile lecture was wrong, and aliasing Game_Map scroll methods to make the script more compatible (namely with LiTTleDRAgo's pixel movement).

It's just the Ruby code that updated. No need to update the DLL if you were using 0.34 (or probably a couple earlier versions before it)
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on September 08, 2017, 01:17:42 pm
Latest version causes invalid scrolling if player gets teleported or loads save with Drago Smooth Scrolling. This issue wasn't present on previous version.

https://littledrago.blogspot.com/2017/03/rgss-drago-smooth-scroller.html
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on September 08, 2017, 10:07:45 pm
Laughing and hating myself

While I was working on v0.35, I was also experimenting some map scrolling feature for Zexion. That somehow slipped into the official build and is causing the weird behavior.

Can you try this out?

=begin
================================================================================
XPA Tilemap                                                      Version 0.35
by KK20                                                         
________________________________________________________________________________

[ Version History ]

Ver.      Date            Notes
-----     -----------     ----------------------------------------------------
0.35  ... 01 Aug 2017 ... Bug fixes:
                            - Aliased Game_Map#scroll_down/right methods
                            - 48th autotile was being drawn incorrectly
                            - Custom autotile graphics were not functioning
                            - Translucent tiles with a priority of 1 were being
                              redrawn if screen scrolled up and down a lot
0.34  ... 04 May 2017 ... Bug fixes:
                            - CallBackController was not disposing its contents,
                              causing a memory leak whenever a new Tilemap was
                              created (and eventually crashing the game)
0.33  ... 30 Apr 2017 ... Bug fixes:
                            - Maps with empty autotiles would crash the game
                            - Tilesets without a graphic would crash the game
                            - The creation of empty autotiles would continually
                              spawn disposed Bitmap objects (related to above)
                            - 32x32 autotiles that animated would crash the game
0.32  ... 25 Feb 2017 ... Bug fixes:
                            - Child viewports were having display issues when
                              tone changes were involved
                            - Viewport#flash had missing parameters
                            - Added more compatibility for XP games (thanks
                              LiTTleDRAgo!)
0.31  ... 08 Feb 2017 ... Bug fixes:
                            - Bad logic with border sprites for non-wrapping map
                            - Problem with Plane objects not initialized with a
                              viewport, causing children-creation to crash
                            - Disable Graphics.resize_screen in Hime's script
                              for XP games as this method does not exist nor is
                              the code necessary to "break" the resolution limit
                            - RGSS does not support Array#cover?
                           Changes:
                            - The Resolution module is disabled for XPA
                            - If WEATHER_ADJUSTMENT is false, it will disable
                              all of the RPG::Weather and Game_Screen classes
                              from loading rather than only some methods
                            - Input module for supporting different game window
                              sizes is disabled for XP as this feature does not
                              work in RGSS
0.3   ... 04 Feb 2017 ... Bug fixes:
                            - A graphical bug involving priority tiles if the
                              MAX_PRIORITY_LAYERS is set to less than 5
                            - Loading autotiles in RPG::Cache has been revised
                              for better compatibility
                            - CallBackController added to replace the method
                              implemented in v0.2b which prevented saving games
                           Additions:
                            - Commented out a majority of the anonymous scripter
                              code that breaks the resolution limit for RGSS3;
                              its ramifications are unknown at this point
                            - A new Plane rewrite which is merely just creating
                              more Plane objects
                            - Maps that do not wrap have a high z-level black
                              sprite positioned around the map's borders
                            - New fullscreen and other window size options for
                              XPA games (will not work for XP)
                            - Tilesets that are not divisible by 32 will raise
                              an error rather than crash
                            - Maps with invalid tile ID's (caused when a tile
                              was placed with a taller tileset graphic, but then
                              the map uses a shorter tileset) no longer crash
                              the game
0.13b ... 23 Oct 2016 ... Bug fixes:
                            - Resolutions not divisible by 32 would not show the
                              last row/column of tiles entirely
                           ** Fix added on top of v0.12b, not v0.2b, but is
                           ** included in all versions above this one
0.2b  ... 07 Jun 2016 ... Bug fixes:
                            - Shaking still had issues
                           Additions:
                            - Maps can now wrap by putting [WRAP] in the map
                              name, due to a new way of drawing the map
                            - ...which also fixed the shaking above
                            - ...and can also allow vertical shaking
                            - Added Unlimited Resolution, an RMVXA script with
                              some changes
                            - Changing tileset and autotile bitmaps in-game will
                              not crash (assuming you know how to do that)
                            - Overall cleaning of code
0.12b ... 27 Feb 2016 ... Bug fixes:
                            - Tiles with some transparency and priority were
                              being redrawn continuously on each other
                            - Setting the Plane bitmap to nil would crash
0.11b ... 03 Nov 2014 ... Bug fixes:
                            - Table did not take in parameters upon initialize
                            - Centering of maps now shrinks Viewport sizes
                            - Fixed Tilemap#oy= logic
0.1b  ... 02 Nov 2014 ... Initial release
________________________________________________________________________________

[ Introduction ]

In light of recent discoveries regarding the usage of RGSS3 in RPG Maker XP
games, many users were left with a dilemma in choosing which Tilemap rewrite to
use due to the vast differences between RGSS1's and RGSS3's Tilemap classes
that would cause complications in this transition. I aimed to find the best
Tilemap rewrite and decided that I would have to make my own. Like every other
Tilemap rewrite before it, this implementation is in no ways perfect, boasting
PROs and CONs.

This script is intended to be used for RPG Maker XP games using the RGSS3
library (unofficially coined RPG Maker XP Ace); however, it is entirely
compatible with RPG Maker XP games in the RGSS1 library.
________________________________________________________________________________

[ License ]

This work is protected by the following license:
http://creativecommons.org/licenses/by-nc-sa/3.0/

********************************************************************************

You are free:

to Share - to copy, distribute and transmit the work
to Remix - to adapt the work

Under the following conditions:

Attribution:
You must attribute the work in the manner specified by the author or licensor,
but not in any way that suggests that they endorse you or your use of the work.

Noncommercial:
You may not use this work for commercial purposes.

Share alike:
If you alter, transform, or build upon this work, you may distribute the
resulting work only under the same or similar license to this one.

- For any reuse or distribution, you must make clear to others the license terms
  of this work. The best way to do this is with a link to this web page.

- Any of the above conditions can be waived if you get permission from the
  copyright holder.

- Nothing in this license impairs or restricts the author's moral rights.

********************************************************************************

[ Instructions ]

- Place this script below the default scripts but above Main.
- Move 'XPA_Tilemap.dll' into your project folder (same directory as 'Game.exe')
- Configure values at the start of the script
________________________________________________________________________________

[ Features ]

About the script:
- XP and XPA (RGSS1 and RGSS3) compatible, though designed for XPA
- Define your own custom resolution
- Adds new tilemap features
- Maps that are smaller than the game resolution are automatically centered
- Drawing methods written in C-language, which has faster pixel-by-pixel
   operations than Ruby

Add-ons:
- Customize frame rate animation and define unique patterns for your autotiles
- Remove unnecessary priority layers to boost frames-per-second (FPS)
- Extend the default RPG::Weather class to fit larger screens, or not
- Change the way fullscreen works (or disable it), including a double and half-
   size window option (only for XPA)
- more to add later...
________________________________________________________________________________

[ Compatibility ]

- There have been reports of Screen Flash not working for some users, though I
   have yet to receive any valid proof or ways to reproduce this issue
- Your tileset must have dimensions divisible by 32. The game will raise an
   error otherwise.
________________________________________________________________________________

[ Credits ]

KK20 - Author of this script and DLL
Blizzard - Tester and providing bug fixes
LiTTleDRAgo - Reusing code from his edits to Custom Resolution and bug fixes
Zexion - Tester and morale support
ForeverZer0 - Reusing code from his Custom Resolution script, found here:
                http://forum.chaos-project.com/index.php/topic,7814.0.html
________________________________________________________________________________

[ Contact ]

To contact the author of this script, please visit
                http://forum.chaos-project.com/index.php
               
or send an email to
                        tscrane20@gmail.com
                       
================================================================================
=end
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                       B E G I N   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#-------------------------------------------------------------------------------
# The game window's screen resolution. RPG Maker XP's default is [640, 480].
# Do note that a larger resolution is prone to sprite lag.
# Anything larger than the default resolution will enable the custom Plane class.
#-------------------------------------------------------------------------------
SCREEN_RESOLUTION = [640,480]

#-------------------------------------------------------------------------------
# The largest level of priority your game uses. This value should be between
# 1 and 5. If using a large resolution, lowering the number of priority layers
# will help in reducing the lag.
#-------------------------------------------------------------------------------
MAX_PRIORITY_LAYERS = 5

#-------------------------------------------------------------------------------
# If using a larger resolution than 640x480, the default weather effects will
# not cover the entire map. It is recommended that you set this to true to
# compensate for that, unless you are using some custom weather script that can
# address this.
#-------------------------------------------------------------------------------
WEATHER_ADJUSTMENT = false

#-------------------------------------------------------------------------------
# When the map's display_x/y variables extend beyond its borders, the map wraps
# around to fill in the gaps. Setting this to true will prevent that, showing
# black borders instead.
# If you want some maps to wrap around, putting [WRAP] in a map's name will
# allow this.
# Note that the custom Plane class will be enabled in order to create this
# effect regardless of your resolution size.
#-------------------------------------------------------------------------------
DISABLE_WRAP = false

#-------------------------------------------------------------------------------
# Choose a form of fullscreen for your game. The available choices are:
#  0 = Default RPG Maker fullscreen (changes monitor resolution to 640x480)
#  1 = Stetches game window to player's monitor size (only for XPA)
#  2 = Disable the ability to go into fullscreen
# Please note that if you choose anything other than 0, it disables everything
# on the player's computer from being able to use ALT + ENTER.
#-------------------------------------------------------------------------------
FULLSCREEN_METHOD = 0

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 2x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
TWICE_SIZE_BUTTON = Input::F5

#-------------------------------------------------------------------------------
# (only for XPA)
# Button to trigger 0.5x window size. Disable by setting it to false
#-------------------------------------------------------------------------------
HALF_SIZE_BUTTON = Input::F6

#-------------------------------------------------------------------------------
# Set the animation frame rate for autotiles. By default, all autotiles will
# update on the 16th frame. You can change that by providing an array of numbers
# that represent how many frames that particular frame of animation will be
# visible for.
# Format:
#   when AUTOTILE_FILENAME then FRAME_DATA
# where FRAME_DATA is an array containing the number of frames that particular
# animation will play for before moving onto the next frame. Be sure to match
# the number of autotile animation frames with the number of elements you put
# into the array.
# Check the examples below.
#-------------------------------------------------------------------------------
def autotile_framerate(filename)
  case filename
  #------------------------------------------------------ START ------
  when '001-G_Water01' then [8, 8, 8, 8]      # Animates twice as fast
  when '009-G2_Water01' then [20, 20, 20, 20] # Animates a bit slower
  when '024-Ocean01' then [32, 16, 32, 16]    # Sine wave effect
  #------------------------------------------------------- END -------
  # Don't touch any of this below
  else
    return nil if filename == ''
    # Generates array of [16, 16, ...] based on autotile width
    # (or nil if not animating autotile)
    w = RPG::Cache.autotile(filename).width
    h = RPG::Cache.autotile(filename).height
    if (h == 32 && w / 32 == 1) || (h == 192 && w / 256 == 1)
      return nil
    else
      return h == 32 ? Array.new(w/32){|i| 16} : Array.new(w/256){|i| 16}
    end
  end
end

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#                                           E N D   C O N F I G U R A T I O N
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FULLSCREEN_METHOD = 0 unless FULLSCREEN_METHOD.between?(0,2)
if FULLSCREEN_METHOD != 0
  # Disable ALT+Enter
  reghotkey = Win32API.new('user32', 'RegisterHotKey', 'LIII', 'I')
  reghotkey.call(0, 1, 1, 0x0D)
end

XPACE = RUBY_VERSION == "1.9.2"

MAX_PRIORITY_LAYERS = 5 unless (1..5).include?(MAX_PRIORITY_LAYERS)

if XPACE
#===============================================================================
# ** Input
#===============================================================================
module Input

  GetActiveWindow = Win32API.new('user32', 'GetActiveWindow', '', 'L')
  SetWindowLong = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
  SetWindowPos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
  GetSystemMetrics = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
  GetAsyncKeyState = Win32API.new('user32', 'GetAsyncKeyState', 'I', 'I')
 
  @fullscreenKeysReleased = true
  @current_state = 0
  NORMAL_STATE     = 0
  FULLSCREEN_STATE = 1
  TWICESIZE_STATE  = 2
  HALFSIZE_STATE   = 3
 
  class << self
    alias get_fullscreen_keys update
   
    # Check for window resize buttons
    def update
      enterkey_state = GetAsyncKeyState.call(0x0D)
      # If ALT+ENTER was pressed, but only for modified fullscreen
      if FULLSCREEN_METHOD == 1 && @fullscreenKeysReleased && Input.press?(Input::ALT) && enterkey_state != 0
        @current_state = @current_state == FULLSCREEN_STATE ? NORMAL_STATE : FULLSCREEN_STATE
        @fullscreenKeysReleased = false
        # Changing game window to fullscreen
        if @current_state == FULLSCREEN_STATE
          full_screen_size
        else
          normal_screen_size
        end
      # If button to double the normal window size was pressed
      elsif TWICE_SIZE_BUTTON && Input.trigger?(TWICE_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to double or normalize the window
        @current_state = @current_state == TWICESIZE_STATE ? NORMAL_STATE : TWICESIZE_STATE
        if @current_state == TWICESIZE_STATE
          double_screen_size
        else
          normal_screen_size
        end
      # If button to halve the normal window size was pressed
      elsif HALF_SIZE_BUTTON && Input.trigger?(HALF_SIZE_BUTTON)
        # Get out of fullscreen if using default method
        simulate_alt_enter if fullscreen?
        # Check if to halve or normalize the window
        @current_state = @current_state == HALFSIZE_STATE ? NORMAL_STATE : HALFSIZE_STATE
        if @current_state == HALFSIZE_STATE
          half_screen_size
        else
          normal_screen_size
        end
      else
        # Check if ALT or ENTER is released
        @fullscreenKeysReleased = (!Input.press?(Input::ALT) || enterkey_state == 0)
      end
      # Call the alias
      get_fullscreen_keys
    end
   
    # Doubles the window size based on SCREEN_RESOLUTION.
    def double_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] * 2
      nh = SCREEN_RESOLUTION[1] * 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Halves the window size based on SCREEN_RESOLUTION.
    def half_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      nw = SCREEN_RESOLUTION[0] / 2
      nh = SCREEN_RESOLUTION[1] / 2
      x = (rw - nw) / 2
      y = (rh - nh) / 2
      w = nw + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = nh + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Makes game window as large as the monitor's resolution
    def full_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x10000000)
      SetWindowPos.call(GetActiveWindow.call, 0, 0, 0, rw, rh, 0)
    end
   
    # Reverts the game window back to normal size
    def normal_screen_size
      rw = GetSystemMetrics.call(0)
      rh = GetSystemMetrics.call(1)
      x = (rw - SCREEN_RESOLUTION[0]) / 2
      y = (rh - SCREEN_RESOLUTION[1]) / 2
      w = SCREEN_RESOLUTION[0] + (GetSystemMetrics.call(5) + GetSystemMetrics.call(45)) * 2
      h = SCREEN_RESOLUTION[1] + (GetSystemMetrics.call(6) + GetSystemMetrics.call(45)) * 2 + GetSystemMetrics.call(4)
      SetWindowLong.call(GetActiveWindow.call, -16, 0x14CA0000)
      SetWindowPos.call(GetActiveWindow.call, 0, x, y, w, h, 0x0020)
    end
   
    # Simulates the key press of ALT+Enter; called if we need to get in or out
    # of fullscreen even though the player did not press these keys
    def simulate_alt_enter
      keybd = Win32API.new 'user32.dll', 'keybd_event', ['i', 'i', 'l', 'l'], 'v'
      keybd.call(0xA4, 0, 0, 0)
      keybd.call(13, 0, 0, 0)
      keybd.call(13, 0, 2, 0)
      keybd.call(0xA4, 0, 2, 0)
    end
   
    # Check if the game is in default fullscreen
    def fullscreen?
      # We're not using default fullscreen, so this should always be false
      return false if FULLSCREEN_METHOD != 0
      # If current monitor resolution is 640x480, then it is fullscreen
      if GetSystemMetrics.call(0) == 640 && GetSystemMetrics.call(1) == 480
        @current_state = FULLSCREEN_STATE
        return true
      end
    end
   
  end
end

end # if XPACE

if !XPACE
#===============================================================================
# ** Resolution
#===============================================================================
module Resolution
 
  def self.resize_game
    # Set instance variables for calling basic Win32 functions.
    ini = Win32API.new('kernel32', 'GetPrivateProfileStringA','PPPPLP', 'L')
    title = "\0" * 256
    ini.call('Game', 'Title', '', title, 256, '.\\Game.ini')
    title.delete!("\0")
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
    set_window_long = Win32API.new('user32', 'SetWindowLong', 'LIL', 'L')
    set_window_pos  = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
    @metrics         = Win32API.new('user32', 'GetSystemMetrics', 'I', 'I')
    # Set default size, displaying error if size is larger than the hardware.
    default_size = Resolution.size
    # Apply resolution change.
    x = (@metrics.call(0) - SCREEN_RESOLUTION[0]) / 2
    y = (@metrics.call(1) - SCREEN_RESOLUTION[1]) / 2
    set_window_long.call(@window, -16, 0x14CA0000)
    set_window_pos.call(@window, 0, x, y, SCREEN_RESOLUTION[0] + 6, SCREEN_RESOLUTION[1] + 26, 0)
    @window = Win32API.new('user32', 'FindWindow', 'PP', 'I').call('RGSS Player', title)
  end
  #--------------------------------------------------------------------------
  def self.size
    # Returns the screen size of the machine.
    [@metrics.call(0), @metrics.call(1)]
  end
  #--------------------------------------------------------------------------
end

end # if !XPACE

#===============================================================================
# ** NilClass
#===============================================================================
class NilClass
  unless method_defined?(:dispose)
    def dispose; end
    def disposed?; end
  end
end
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
  attr_accessor :filename
  alias set_filename_of_bitmap initialize
  def initialize(*args)
    # Associate the bitmap with the filename of the graphic; empty string otherwise
    @filename = args.size == 1 ? File.basename(args[0], '.*') : ''
    set_filename_of_bitmap(*args)
  end
end
#===============================================================================
# ** RPG::Cache
#===============================================================================
module RPG::Cache
 
  AUTO_INDEX = [
 
  [27,28,33,34],  [5,28,33,34],  [27,6,33,34],  [5,6,33,34],
  [27,28,33,12],  [5,28,33,12],  [27,6,33,12],  [5,6,33,12],
  [27,28,11,34],  [5,28,11,34],  [27,6,11,34],  [5,6,11,34],
  [27,28,11,12],  [5,28,11,12],  [27,6,11,12],  [5,6,11,12],
  [25,26,31,32],  [25,6,31,32],  [25,26,31,12], [25,6,31,12],
  [15,16,21,22],  [15,16,21,12], [15,16,11,22], [15,16,11,12],
  [29,30,35,36],  [29,30,11,36], [5,30,35,36],  [5,30,11,36],
  [39,40,45,46],  [5,40,45,46],  [39,6,45,46],  [5,6,45,46],
  [25,30,31,36],  [15,16,45,46], [13,14,19,20], [13,14,19,12],
  [17,18,23,24],  [17,18,11,24], [41,42,47,48], [5,42,47,48],
  [37,38,43,44],  [37,6,43,44],  [13,18,19,24], [13,14,43,44],
  [37,42,43,48],  [17,18,47,48], [13,18,43,48], [1,2,7,8]
   
  ]
 
  def self.autotile(filename)
    key = "Graphics/Autotiles/#{filename}"
    if !@cache.include?(key) || @cache[key].disposed?
      # Load the autotile graphic.
      orig_bm = self.load_bitmap('Graphics/Autotiles/', filename)
      # Cache each configuration of this autotile.
      new_bm = self.format_autotiles(orig_bm, filename)
      if new_bm != orig_bm
        @cache[key].dispose
        @cache[key] = new_bm
      end
    end
    @cache[key]
  end

  def self.format_autotiles(bitmap, filename)
    if bitmap.height > 32 && bitmap.height < 192
      frames = bitmap.width / 96
      template = Bitmap.new(256*frames,192)
      template.filename = filename
      # Create a bitmap to use as a template for creation.
      (0..frames-1).each{|frame|
      (0...6).each {|i| (0...8).each {|j| AUTO_INDEX[8*i+j].each {|number|
        number -= 1
        x, y = 16 * (number % 6), 16 * (number / 6)
        rect = Rect.new(x + (frame * 96), y, 16, 16)
        template.blt((32 * j + x % 32) + (frame * 256), 32 * i + y % 32, bitmap, rect)
      }}}}
      return template
    else
      return bitmap
    end
  end
 
end
#===============================================================================
# ** CallBackController
#===============================================================================
module CallBackController
  @@callback = {}
 
  def self.clear
    @@callback.clear
  end
 
  def self.setup_callback(obj, proc)
    @@callback[obj.object_id] = proc
  end
 
  def self.call(obj, *args)
    @@callback[obj.object_id].call(*args) if @@callback[obj.object_id]
    true
  end
 
  def self.delete(obj)
    @@callback.delete(obj.object_id)
  end
 
end

#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :offset_x, :offset_y
 
  alias zer0_viewport_resize_init initialize
  def initialize(x=0, y=0, width=SCREEN_RESOLUTION[0], height=SCREEN_RESOLUTION[1], override=false)
    # Variables needed for Viewport children (for the Plane rewrite); ignore if
    # your game resolution is not larger than 640x480
    @offset_x = @offset_y = 0
    if x.is_a?(Rect)
      # If first argument is a Rectangle, just use it as the argument.
      zer0_viewport_resize_init(x)
    elsif [x, y, width, height] == [0, 0, 640, 480] && !override
      # Resize fullscreen viewport, unless explicitly overridden.
      zer0_viewport_resize_init(Rect.new(0, 0, SCREEN_RESOLUTION[0], SCREEN_RESOLUTION[1]))
    else
      # Call method normally.
      zer0_viewport_resize_init(Rect.new(x, y, width, height))
    end
  end
 
  def resize(*args)
    # Resize the viewport. Can call with (X, Y, WIDTH, HEIGHT) or (RECT).
    if args[0].is_a?(Rect)
      args[0].x += @offset_x
      args[0].y += @offset_y
      self.rect = args[0]
    else
      args[0] += @offset_x
      args[1] += @offset_y
      self.rect = Rect.new(*args)
    end
  end
end

#===============================================================================
# ** Tilemap
#===============================================================================
class Tilemap
 
  attr_accessor :tileset, :autotiles, :map_data, :priorities, :ground_sprite
  attr_reader :wrapping
  #---------------------------------------------------------------------------
  # Initialize
  #---------------------------------------------------------------------------
  def initialize(viewport = nil)
    # Ensure that all callbacks are removed to prevent memory leaks
    CallBackController.clear
   
    @viewport = viewport
    @layer_sprites = []
    @autotile_frame = []      #[[ANIMATION_DRAW_INDEX, CURRENT_LOGICAL_FRAME], ... ]
    @autotile_framedata = []  #[[DATA_FROM_CONFIGURATION_ABOVE], ... ]
   
    # Ensures that the bitmap width accounts for an extra tile
    # and is divisible by 32
    bitmap_width = ((SCREEN_RESOLUTION[0] / 32.0).ceil + 1) * 32
    # Create the priority layers
    ((SCREEN_RESOLUTION[1]/32.0).ceil + MAX_PRIORITY_LAYERS).times{ |i|
      s = Sprite.new(@viewport)
      s.bitmap = Bitmap.new(bitmap_width, MAX_PRIORITY_LAYERS * 32)
      @layer_sprites.push(s)
    }
   
    # Same reasons as bitmap_width, but for height
    bitmap_height = ((SCREEN_RESOLUTION[1] / 32.0).ceil + 1) * 32
    # Create the ground layer (priority 0)
    s = Sprite.new(@viewport)
    s.bitmap = Bitmap.new(bitmap_width, bitmap_height)
    @ground_sprite = s
    @ground_sprite.z = 0

    # Initialize remaining variables
    @redraw_tilemap = true
    @tileset = nil
    @autotiles = []
    proc = Proc.new { |x,y| @redraw_tilemap = true; setup_autotile(x) }
    CallBackController.setup_callback(@autotiles, proc)
   
    @map_data = nil
   
    @priorities = nil
    @old_ox = 0
    @old_oy = 0
    @ox = 0
    @oy = 0
    @ox_float = 0.0
    @oy_float = 0.0
    @shift = 0
    @wrapping = (!DISABLE_WRAP || (XPAT_MAP_INFOS[$game_map.map_id].name =~ /.*\[[Ww][Rr][Aa][Pp]\].*/) == 0) ? 1 : 0
    create_border_sprites
   
    # Set up the DLL calls
    @@update = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap2', 'pppp', 'i')
    @@autotile_update = Win32API.new('XPA_Tilemap', 'UpdateAutotiles', 'pppp', 'i')
    @@initial_draw = Win32API.new('XPA_Tilemap', 'DrawMapsBitmap', 'pppp', 'i')
    @empty_tile = Bitmap.new(32,32)
    Win32API.new('XPA_Tilemap','InitEmptyTile','l','i').call(@empty_tile.object_id)
    @black_tile = Bitmap.new(32,32)
    @black_tile.fill_rect(0,0,32,32,Color.new(0,0,0))
    Win32API.new('XPA_Tilemap','InitBlackTile','l','i').call(@black_tile.object_id)
   
  end
  #---------------------------------------------------------------------------
  # Setup autotile animation data
  #---------------------------------------------------------------------------
  def setup_autotile(i)
    # Get animation frame rate of the autotile
    bitmap = @autotiles[i]
    frames = bitmap.nil? ? nil : autotile_framerate(bitmap.filename)
    # If autotile doesn't animate
    if frames.nil?
      @autotile_frame[i] = [0,0]
      @autotile_framedata[i] = nil
    else
      # Save the frame rate data
      @autotile_framedata[i] = frames
      # Determine how long one animation cycle takes and indicate at what time
      # the next frame of animation occurs
      total = 0
      frame_checkpoints = []
     
      frames.each_index{|j| f = frames[j]
        total += f
        frame_checkpoints[j] = total
      }
      # Get animation frame for this autotile based on game time passed
      current_frame = Graphics.frame_count % total
      frame_checkpoints.each_index{|j| c = frame_checkpoints[j]
        next if c.nil?
        if c > current_frame
          @autotile_frame[i] = [j, c - current_frame]
          break
        end
      }
    end
  end
  #---------------------------------------------------------------------------
  # Creates four 32-pixel thick black sprites to surround the map. This is
  # only applied to maps that do not have wrapping enabled. This helps those
  # who have screen shaking in their maps.
  #---------------------------------------------------------------------------
  def create_border_sprites
    @border_sprites = []
    return if @wrapping == 1
    for i in 0..3
      s = Sprite.new(@viewport)
      s.z = 99999
      if i % 2 == 0
        b = Bitmap.new(SCREEN_RESOLUTION[0] + 64,32)
        s.x = -32
        s.y = i == 0 ? -32 : $game_map.height * 32
      else
        b = Bitmap.new(32,SCREEN_RESOLUTION[1] + 64)
        s.x = i == 1 ? -32 : $game_map.width * 32
        s.y = -32
      end
      b.fill_rect(0, 0, b.width, b.height, Color.new(0,0,0))
      s.bitmap = b
      @border_sprites.push(s)
    end
  end
  #---------------------------------------------------------------------------
  # Dispose tilemap
  #---------------------------------------------------------------------------
  def dispose
    @layer_sprites.each{|sprite| sprite.dispose}
    @ground_sprite.dispose
    @border_sprites.each{|sprite| sprite.dispose}
    CallBackController.clear
  end
  #---------------------------------------------------------------------------
  # Check if disposed tilemap
  #---------------------------------------------------------------------------
  def disposed?
    @layer_sprites[0].disposed?
  end
  #---------------------------------------------------------------------------
  # Get viewport
  #---------------------------------------------------------------------------
  def viewport
    @viewport
  end
  #---------------------------------------------------------------------------
  # Return if tilemap is visible
  #---------------------------------------------------------------------------
  def visible
    layer_sprites[0].visible
  end
  #---------------------------------------------------------------------------
  # Show or hide tilemap
  #---------------------------------------------------------------------------
  def visible=(bool)
    @layer_sprites.each{|sprite| sprite.visible = bool}
    @ground_sprite.visible = bool
  end
  #---------------------------------------------------------------------------
  # Set tileset
  #---------------------------------------------------------------------------
  def tileset=(bitmap)
    @tileset = bitmap
    if @tileset.width % 32 != 0 || @tileset.height % 32 != 0
      file = bitmap.filename
      raise "Your tileset graphic #{file} needs to be divisible by 32!"
    end
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set autotiles
  #---------------------------------------------------------------------------
  def autotiles=(array)
    CallBackController.delete(@autotiles)
    @autotiles = array
    proc = Proc.new { |i| @redraw_tilemap = true; setup_autotile(i) }
    CallBackController.setup_callback(@autotiles, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map data
  #---------------------------------------------------------------------------
  def map_data=(table)
    CallBackController.delete(@map_data)
    @map_data = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@map_data, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Set map priorities
  #---------------------------------------------------------------------------
  def priorities=(table)
    CallBackController.delete(@priorities)
    @priorities = table
    proc = Proc.new { @redraw_tilemap = true }
    CallBackController.setup_callback(@priorities, proc)
    @redraw_tilemap = true
  end
  #---------------------------------------------------------------------------
  # Get horizontal shift
  #---------------------------------------------------------------------------
  def ox
    @ox + @ox_float
  end
  #---------------------------------------------------------------------------
  # Get vertical shift
  #---------------------------------------------------------------------------
  def oy
    @oy + @oy_float
  end
  #---------------------------------------------------------------------------
  # Shift tilemap horizontally
  #---------------------------------------------------------------------------
  def ox=(ox)
    @ox_float = (ox - ox.to_i) % 1
    @ox = ox.floor
    @border_sprites.each{ |s|
      next if s.bitmap.height == 32
      s.ox = @ox
    }
  end
  #---------------------------------------------------------------------------
  # Shift tilemap vertically
  #---------------------------------------------------------------------------
  def oy=(oy)
    @oy_float = (oy - oy.to_i) % 1
    @oy = oy.floor
    @border_sprites.each{ |s|
      next if s.bitmap.width == 32
      s.oy = @oy
    }
  end
  #---------------------------------------------------------------------------
  # Update tilemap graphics
  #---------------------------------------------------------------------------
  def update; end;
  def draw
    # Figure out what the new X and Y coordinates for the ground layer would be
    x = @old_ox - @ox
    @old_ox = @ox
    x += @ground_sprite.x

    y = @old_oy - @oy
    @old_oy = @oy
    y += @ground_sprite.y

    # No reason to do sprite shifting if we're just redrawing everything
    if !@redraw_tilemap
      # If layers would be too far to the left
      if x < @viewport.ox - 31
        # If still too far, then force redraw
        if x + 32 < @viewport.ox - 31
          @redraw_tilemap = true
        else
          # Shift all layers right by 32 and clear out left-most column
          x += 32
          @ground_sprite.bitmap.fill_rect(0, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(0, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 1 # Redraw right column bit-flag (0001)
        end
      # If layers would be too far to the right
      elsif x > @viewport.ox
        # If still too far, then force redraw
        if x - 32 > @viewport.ox
          @redraw_tilemap = true
        else
          # Shift all layers left by 32 and clear out right-most column
          x -= 32
          @ground_sprite.bitmap.fill_rect(@ground_sprite.bitmap.width - 32, 0, 32, @ground_sprite.bitmap.height, Color.new(0,0,0,0))
          @layer_sprites.each{|sprite|
            sprite.bitmap.fill_rect(sprite.bitmap.width - 32, 0, 32, sprite.bitmap.height, Color.new(0,0,0,0))
          }
          @shift += 2 # Redraw left column bit-flag (0010)
        end
      end
      # Apply the change in X to the layers
      if !@redraw_tilemap
        @ground_sprite.x = x
        @layer_sprites.each{|sprite| sprite.x = x}

        # If layers would be too far up
        if y < @viewport.oy - 31
          # If still too far, then force redraw
          if y + 32 < @viewport.oy - 31
            @redraw_tilemap = true
          else
            y += 32
            layer = @layer_sprites.shift
            layer.bitmap.clear
            @layer_sprites.push(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            num = @layer_sprites.size
            (1..MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[num-index].bitmap.fill_rect(0, (index - 1) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 4 # Redraw bottom row bit-flag (0100)
          end
        # If layers would be too far down
        elsif y > @viewport.oy
          # If still too far, then force redraw
          if y - 32 > @viewport.oy
            @redraw_tilemap = true
          else
            y -= 32
            layer = @layer_sprites.pop
            layer.bitmap.clear
            @layer_sprites.unshift(layer)
            # Clear out the rows in the layers to prepare for drawing in #update
            width = @layer_sprites[0].bitmap.width
            (1...MAX_PRIORITY_LAYERS).each{ |index|
              @layer_sprites[index].bitmap.fill_rect(0, (MAX_PRIORITY_LAYERS - 1 - index) * 32, width, 32, Color.new(0,0,0,0))
            }
            @shift += 8 # Redraw top row bit-flag (1000)
          end
        end
        # Apply the change to layers' Y and Z values
        if !@redraw_tilemap
          @ground_sprite.y = y
          @layer_sprites.each_index{ |i| sprite = @layer_sprites[i]
            sprite.y = y - 32 * (MAX_PRIORITY_LAYERS - 1 - i)
            sprite.z = sprite.y + (192 - (5 - MAX_PRIORITY_LAYERS) * 32)
          }
        end
      end
    end

    autotile_need_update = []
    # Update autotile animation frames
    for i in 0..6
      autotile_need_update[i] = false
      # If this autotile doesn't animate, skip
      next if @autotile_framedata[i].nil?
      # Reduce frame count
      @autotile_frame[i][1] -= 1
      # Autotile requires update
      if @autotile_frame[i][1] == 0
        @autotile_frame[i][0] = (@autotile_frame[i][0] + 1) % @autotile_framedata[i].size
        @autotile_frame[i][1] = @autotile_framedata[i][@autotile_frame[i][0]]
        autotile_need_update[i] = true
      end
    end
   
   
    # Stop the update unless redrawing, there is shifting, or an autotile needs to update
    return unless @redraw_tilemap || @shift != 0 || !autotile_need_update.index(true).nil?

    # Set up the array for the priority layers
    layers = [@layer_sprites.size + 1]
    # Insert higher priority layers into the array in order (least to most y-value sprite)
    @layer_sprites.each{|sprite| layers.push(sprite.bitmap.object_id) }
    # Insert ground layer last in the array
    layers.push(@ground_sprite.bitmap.object_id)
    # Load autotile bitmap graphics into array
    tile_bms = [self.tileset.object_id]
    self.autotiles.each{|autotile| tile_bms.push(autotile.object_id) }
    # Store autotile animation frame data
    autotiledata = []
    for i in 0..6
      autotiledata.push(@autotile_frame[i][0])
      autotiledata.push(autotile_need_update[i] ? 1 : 0)
    end
    # Fills in remaining information of other tilemaps
    misc_data = [@ox + @viewport.ox, @oy + @viewport.oy,
      self.map_data.object_id, self.priorities.object_id, @shift,
      MAX_PRIORITY_LAYERS, @wrapping]
   
    # If forcing fresh redraw of the map (or drawing for first time)
    if @redraw_tilemap
      # Initialize layer sprite positions and clear them for drawing
      @ground_sprite.bitmap.clear
      @ground_sprite.x = (@viewport.ox - @viewport.ox % 32) - (@ox % 32)
      @ground_sprite.x += 32 if @ground_sprite.x < @viewport.ox - 31
      @ground_sprite.y = (@viewport.oy - @viewport.oy % 32) - (@oy % 32)
      @ground_sprite.y += 32 if @ground_sprite.y < @viewport.oy - 31

      y_buffer = 32 * (MAX_PRIORITY_LAYERS - 1)
      z_buffer = MAX_PRIORITY_LAYERS * 32 + 32
      @layer_sprites.each_index{|i| layer = @layer_sprites[i]
        layer.bitmap.clear
        layer.x = @ground_sprite.x
        layer.y = @ground_sprite.y - y_buffer + 32 * i
        layer.z = layer.y + z_buffer
      }
      # Make DLL call
      @@initial_draw.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    elsif @shift != 0
      # Update for shifting
      @@update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Check for autotile updates (at least one autotile needs an update)
    # No need if redrawn tilemap since it already handled the updated autotiles
    if !@redraw_tilemap && !autotile_need_update.index(true).nil?
      @@autotile_update.call(layers.pack("L*"), tile_bms.pack("L*"), autotiledata.pack("L*"), misc_data.pack("L*"))
    end
    # Turn off flag
    @redraw_tilemap = false
    # Reset shift flag
    @shift = 0
  end
 
end
#===============================================================================
# ** Game_Player
#===============================================================================
class Game_Player
 
  CENTER_X = ((SCREEN_RESOLUTION[0] / 2) - 16) * 4    # Center screen x-coordinate * 4
  CENTER_Y = ((SCREEN_RESOLUTION[1] / 2) - 16) * 4    # Center screen y-coordinate * 4
 
  def center(x, y)
    # Recalculate the screen center based on the new resolution.
    max_x = (($game_map.width - (SCREEN_RESOLUTION[0]/32.0)) * 128).to_i
    max_y = (($game_map.height - (SCREEN_RESOLUTION[1]/32.0)) * 128).to_i
    $game_map.display_x = [0, [x * 128 - CENTER_X, max_x].min].max
    $game_map.display_y = [0, [y * 128 - CENTER_Y, max_y].min].max
  end
end
#===============================================================================
# ** Game_Map
#===============================================================================
class Game_Map
  alias zer0_map_edge_setup setup
  def setup(map_id)
    zer0_map_edge_setup(map_id)
    # Find the displayed area of the map in tiles. No calcualting every step.
    @map_edge = [self.width - (SCREEN_RESOLUTION[0]/32.0), self.height - (SCREEN_RESOLUTION[1]/32.0)]
    @map_edge.collect! {|size| size * 128 }
    # Change the map center if map is smaller than the resolution
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      Game_Player.const_set(:CENTER_X, $game_map.width * 128)
    else
      Game_Player.const_set(:CENTER_X, ((SCREEN_RESOLUTION[0] / 2) - 16) * 4)
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      Game_Player.const_set(:CENTER_Y, $game_map.height * 128)
    else
      Game_Player.const_set(:CENTER_Y, ((SCREEN_RESOLUTION[1] / 2) - 16) * 4)
    end
  end

  alias scroll_down_xpat scroll_down
  def scroll_down(distance)
    pre_alias = @display_y + distance
    scroll_down_xpat(distance)
    @display_y = pre_alias if @display_y == (self.height - 15) * 128
    # Find point that the map edge meets the screen edge, using custom size.
    @display_y = [@display_y, @map_edge[1]].min
  end

  alias scroll_right_xpat scroll_right
  def scroll_right(distance)
    pre_alias = @display_x + distance
    scroll_right_xpat(distance)
    @display_x = pre_alias if @display_x == (self.width - 20) * 128
    # Find point that the map edge meets the screen edge, using custom size.
    @display_x = [@display_x, @map_edge[0]].min
  end

end

# Override set-methods to allow callbacks (necessary for Tilemap)
#===============================================================================
# ** Array
#===============================================================================
class Array
  alias flag_changes_to_set []=
  def []=(x, y)
    flag_changes_to_set(x, y)
    CallBackController.call(self, x, y)
  end
end
#===============================================================================
# ** Table
#===============================================================================
class Table
  alias flag_changes_to_set []=
  def []=(*args)
    flag_changes_to_set(*args)
    CallBackController.call(self, *args)
  end
end

if WEATHER_ADJUSTMENT
#===============================================================================
# ** RPG::Weather
#===============================================================================
class RPG::Weather
 
  alias add_more_weather_sprites initialize
  def initialize(vp = nil)
    add_more_weather_sprites(vp)
    total_sprites = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 7680
    if total_sprites > 40
      for i in 1..(total_sprites - 40)
        sprite = Sprite.new(vp)
        sprite.z = 1000
        sprite.visible = false
        sprite.opacity = 0
        @sprites.push(sprite)
      end
    end
  end
 
  def type=(type)
    return if @type == type
    @type = type
    case @type
    when 1
      bitmap = @rain_bitmap
    when 2
      bitmap = @storm_bitmap
    when 3
      bitmap = @snow_bitmap
    else
      bitmap = nil
    end
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
        sprite.bitmap = bitmap
      end
    end
  end
 
  def max=(max)
    return if @max == max;
    @max = [[max, 0].max, @sprites.size].min
    for i in 1..@sprites.size
      sprite = @sprites[i]
      if sprite != nil
        sprite.visible = (i <= @max)
      end
    end
  end
 
  def update
    return if @type == 0
    for i in 1..@max
      sprite = @sprites[i]
      if sprite == nil
        break
      end
      if @type == 1
        sprite.x -= 2
        sprite.y += 16
        sprite.opacity -= 8
      end
      if @type == 2
        sprite.x -= 8
        sprite.y += 16
        sprite.opacity -= 12
      end
      if @type == 3
        sprite.x -= 2
        sprite.y += 8
        sprite.opacity -= 8
      end
      x = sprite.x - @ox
      y = sprite.y - @oy
      if sprite.opacity < 64
        sprite.x = rand(SCREEN_RESOLUTION[0] + 100) - 100 + @ox
        sprite.y = rand(SCREEN_RESOLUTION[0] + 200) - 200 + @oy
        sprite.opacity = 160 + rand(96)
      end
    end
  end
 
end
#===============================================================================
# ** Game_Screen
#===============================================================================
class Game_Screen
  #--------------------------------------------------------------------------
  # * Set Weather
  #     type : type
  #     power : strength
  #     duration : time
  #--------------------------------------------------------------------------
  def weather(type, power, duration)
    @weather_type_target = type
    if @weather_type_target != 0
      @weather_type = @weather_type_target
    end
    if @weather_type_target == 0
      @weather_max_target = 0.0
    else
      num = SCREEN_RESOLUTION[0] * SCREEN_RESOLUTION[1] / 76800.0
      @weather_max_target = (power + 1) * num
    end
    @weather_duration = duration
    if @weather_duration == 0
      @weather_type = @weather_type_target
      @weather_max = @weather_max_target
    end
  end
 
end

end # if WEATHER_ADJUSTMENT
#===============================================================================
# ** Spriteset_Map
#===============================================================================
class Spriteset_Map

  alias init_for_centered_small_maps initialize
  #---------------------------------------------------------------------------
  # Resize and reposition viewport so that it fits smaller maps
  #---------------------------------------------------------------------------
  def initialize
    @center_offsets = [0,0]
    if $game_map.width < SCREEN_RESOLUTION[0] / 32
      x = (SCREEN_RESOLUTION[0] - $game_map.width * 32) / 2
    else
      x = 0
    end
    if $game_map.height < SCREEN_RESOLUTION[1] / 32
      y = (SCREEN_RESOLUTION[1] - $game_map.height * 32) / 2
    else
      y = 0
    end
    init_for_centered_small_maps
    w = [$game_map.width  * 32 , SCREEN_RESOLUTION[0]].min
    h = [$game_map.height * 32 , SCREEN_RESOLUTION[1]].min
    @viewport1.resize(x,y,w,h)
  end
  #---------------------------------------------------------------------------
  # Puts the tilemap update method at the end, ensuring that both
  # @tilemap.ox/oy and @viewport1.ox/oy are set.
  #---------------------------------------------------------------------------
  alias update_tilemap_for_real update
  def update
    update_tilemap_for_real
    @tilemap.draw
  end
end

# The following script will only be enabled if the resolution is bigger than the
# default OR if the game does not want certain maps to wrap around.
if DISABLE_WRAP || SCREEN_RESOLUTION[0] > 640 || SCREEN_RESOLUTION[1] > 480
#--------------------------------------------[Unlimited Resolution by Hime]-----
=begin
#===============================================================================
Title: Unlimited Resolution
Date: Oct 24, 2013
Author: Hime ( ** Modified by KK20 ** )
--------------------------------------------------------------------------------   
Terms of Use
Free
--------------------------------------------------------------------------------
Description

This script modifies Graphics.resize_screen to overcome the 640x480 limitation.
It also includes some modifications to module Graphics such as allowing the
default fade transition to cover the entire screen.

Now you can have arbitrarily large game resolutions.
--------------------------------------------------------------------------------
Credits

Unknown author for overcoming the 640x480 limitation
Lantier, from RMW forums for posting the snippet above
Esrever for handling the viewport
Jet, for the custom Graphics code
FenixFyre, for the Plane class fix
Kaelan, for several bug fixes
--------------------------------------------------------------------------------
KK20 Notes:
- Plane class was rewritten from the original script. Certain lines in the
   unknown scripter's code can be omitted entirely to allow this implementation.
- Likewise, the Viewport class needed new methods to handle this Plane rewrite.
- This entire script only applies to games that go beyond the default 640x480
   resolution.

#===============================================================================
=end
unless XPACE
class Bitmap
  #----------------------------------------------------------------------------
  # ● New method: address
  #----------------------------------------------------------------------------
  def address
    @rtlmemory_pi ||= Win32API.new('kernel32','RtlMoveMemory','pii','i')
    @address ||= (  @rtlmemory_pi.call(a="\0"*4, __id__*2+16, 4)
                      @rtlmemory_pi.call(a, a.unpack('L')[0]+8, 4)
                      @rtlmemory_pi.call(a, a.unpack('L')[0]+16, 4)
                      a.unpack('L')[0]    )
  end
end
end
#===============================================================================
# ** Graphics
#===============================================================================
module Graphics
 
  @@super_sprite = Sprite.new
  @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
 
  class << self
   
    def freeze(*args, &block)
      ensure_sprite
      @@super_sprite.bitmap = snap_to_bitmap
    end
   
    def transition(time = 10, filename = nil, vague = nil)
      if filename
        @@super_sprite.bitmap = Bitmap.new(filename)
      end
      @@super_sprite.opacity = 255
      incs = 255.0 / time
      time.times do |i|
        @@super_sprite.opacity = 255.0 - incs * i
        Graphics.wait(1)
      end
      @@super_sprite.bitmap.dispose if @@super_sprite.bitmap
      reform_sprite_bitmap
      Graphics.brightness = 255
    end
   
    def reform_sprite_bitmap
      @@super_sprite.bitmap = Bitmap.new(Graphics.width, Graphics.height)
      @@super_sprite.bitmap.fill_rect(@@super_sprite.bitmap.rect, Color.new(0, 0, 0, 255))
    end
   
    def fadeout(frames)
      incs = 255.0 / frames
      frames.times do |i|
        i += 1
        Graphics.brightness = 255 - incs * i
        Graphics.wait(1)
      end
    end
   
    def fadein(frames)
      incs = 255.0 / frames
      frames.times do |i|
        Graphics.brightness = incs * i
        Graphics.wait(1)
      end
    end

    def brightness=(i)
      @@super_sprite.opacity = 255.0 - i
    end
   
    def brightness
      255 - @@super_sprite.opacity
    end
   
    def ensure_sprite
      if @@super_sprite.disposed?
        @@super_sprite = Sprite.new
        @@super_sprite.z = (2 ** (0.size * 8 - 2) - 1)
        reform_sprite_bitmap
      end
    end
   
    # XP does not have a snap_to_bitmap method built-in
    unless XPACE
      define_method(:width)  { Resolution.size.at(0) }
      define_method(:height) { Resolution.size.at(1) }
      #--------------------------------------------------------------------------
      # * snap_to_bitmap
      #--------------------------------------------------------------------------
      def snap_to_bitmap
        @window      ||= Win32API.new('user32','GetActiveWindow', '', 'L')
        @getdc       ||= Win32API.new('user32','GetDC','i','i')
        @ccdc        ||= Win32API.new('gdi32','CreateCompatibleDC','i','i')
        @selectobject||= Win32API.new('gdi32','SelectObject','ii','i')
        @deleteobject||= Win32API.new('gdi32','DeleteObject','i','i')
        @setdibits   ||= Win32API.new('gdi32','SetDIBits','iiiiipi','i')
        @getdibits   ||= Win32API.new('gdi32','GetDIBits','iiiiipi','i')
        @bitblt      ||= Win32API.new('gdi32','BitBlt','iiiiiiiii','i')
        @ccbitmap    ||= Win32API.new('gdi32','CreateCompatibleBitmap','iii','i')
       
        bitmap = Bitmap.new(w = Graphics.width,h = Graphics.height)
        @deleteobject.call(@selectobject.call((hDC = @ccdc.call((dc = @getdc.call(@window.call)))),(hBM = @ccbitmap.call(dc,w,h))))
        @setdibits.call(hDC, hBM, 0, h, (a = bitmap.address), (info = [40,w,h,1,32,0,0,0,0,0,0].pack('LllSSLLllLL')), 0)
        @bitblt.call(hDC, 0, 0, w, h, dc, 0, 0, 0xCC0020)
        @getdibits.call(hDC, hBM, 0, h, a, info, 0)
        @deleteobject.call(hBM)
        @deleteobject.call(hDC)
        return bitmap
      end 
   
      def wait(frame=1)
        frame.times {|s| update }
      end
    end
 
# Graphics.resize_screen is only for XPA games
if XPACE
    #-----------------------------------------------------------------------------
    # Unknown Scripter. Copied from http://pastebin.com/sM2MNJZj
    #-----------------------------------------------------------------------------
    alias :th_large_screen_resize_screen :resize_screen
    def resize_screen(width, height)
      wt, ht = width.divmod(32), height.divmod(32)
      #wt.last + ht.last == 0 || fail('Incorrect width or height')
      #wh = -> w, h, off = 0 { [w + off, h + off].pack('l2').scan /.{4}/ }
      wh = lambda {|w,h,off| [w + off, h + off].pack('l2').scan(/.{4}/) }
      w, h     = wh.call(width, height,0)
      ww, hh   = wh.call(width, height, 32)
      www, hhh = wh.call(wt.first.succ, ht.first.succ,0)
      base = 0x10000000  # fixed?
      #mod = -> adr, val { DL::CPtr.new(base + adr)[0, val.size] = val }
      mod = lambda {|adr,val| (DL::CPtr.new(base + adr))[0, val.size] = val}
      # Didn't see anything happen here
  #    mod.(0x195F, "\x90" * 5)  # ???
  #    mod.(0x19A4, h)
  #    mod.(0x19A9, w)
  #    mod.(0x1A56, h)
  #    mod.(0x1A5B, w)
   
      # The following four seem to change the window size. But I dunno why there
      # are two. I commented out a pair of them but they still do the same thing.
      mod.call(0x20F6, w) && mod.call(0x20FF, w)     
      mod.call(0x2106, h) && mod.call(0x210F, h) 
     
      # speed up y?
      #mod.(0x1C5E3, h) ##
      #mod.(0x1C5E8, w) ##
      #zero = [0].pack ?l
      zero = [0].pack(?l)
     
      # Without these, I can use the default Plane class
  #    mod.(0x1C5E3, zero)
  #    mod.(0x1C5E8, zero)
   
      # And not sure what these do
  #    mod.(0x1F477, h)
  #    mod.(0x1F47C, w)
  #    mod.(0x211FF, hh)
  #    mod.(0x21204, ww)
  #    mod.(0x21D7D, hhh[0])
  #    mod.(0x21E01, www[0])
  #    mod.(0x10DEA8, h)
  #    mod.(0x10DEAD, w)
  #    mod.(0x10DEDF, h)
  #    mod.(0x10DEF0, w)
  #    mod.(0x10DF14, h)
  #    mod.(0x10DF18, w)
  #    mod.(0x10DF48, h)
  #    mod.(0x10DF4C, w)
  #    mod.(0x10E6A7, w)
  #    mod.(0x10E6C3, h)
  #    mod.(0x10EEA9, w)
  #    mod.(0x10EEB9, h)
      th_large_screen_resize_screen(width, height)
    end
   
  end # class << self
 
end # if XPACE

end
#===============================================================================
# ** Viewport
#===============================================================================
class Viewport
  attr_accessor :parent, :children
 
  alias init_children_vps initialize
  def initialize(*args)
    @children = []
    @parent = false
    init_children_vps(*args)
  end
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias flash_parent flash
  def flash(color, duration)
    if @parent
      @children.each{|child| child.flash_parent(color, duration)}
    else
      flash_parent(color, duration)
    end
  end
 
  alias update_parent update
  def update
    @children.each{|child| child.update} if @parent
    update_parent
  end
 
  alias resize_trigger resize
  def resize(*args)
    @children.each{ |child|
      if args[0].is_a?(Rect)
        rect = args[0]
        new_args = Rect.new(rect.x,rect.y,child.rect.width,child.rect.height)
      else
        new_args = [args[0],args[1]]
        new_args[2] = child.rect.width
        new_args[3] = child.rect.height
      end
      child.resize_trigger(*new_args)
    } if @parent
    resize_trigger(*args)
  end
 
  alias set_trigger_vp_ox ox=
  def ox=(nx)
    return if self.ox == nx
    set_trigger_vp_ox(nx)
    @children.each{|child| child.ox = nx}
  end
 
  alias set_trigger_vp_oy oy=
  def oy=(ny)
    return if self.oy == ny
    set_trigger_vp_oy(ny)
    @children.each{|child| child.oy = ny}
  end
 
  alias tone_parent tone=
  def tone=(t)
    if @parent
      @children.each{|child| child.tone_parent(t)}
    else
      tone_parent(t)
    end
  end

end
#===============================================================================
# ** Plane
#===============================================================================
class Plane
  attr_accessor :offset_x, :offset_y
 
  alias parent_initialize initialize
  def initialize(viewport=nil,parent=true)
    @parent = parent
    @children = []
    parent_initialize(viewport)
    @offset_x = 0
    @offset_y = 0
    # If the parent Plane object; but don't make more children if already have
    # some. This occurs in Spriteset_Map when initializing the Panorama and Fog
    if @parent && viewport
      viewport.parent = true
      create_children
    end
  end
 
  def create_children
    gw = [SCREEN_RESOLUTION[0], $game_map.width * 32].min
    gh = [SCREEN_RESOLUTION[1], $game_map.height * 32].min
    w = (gw - 1) / 640
    h = (gh - 1) / 480
    for y in 0..h
      for x in 0..w
        # This is the top-left default/parent Plane, so skip it
        #next if x == 0 && y == 0
        # Create viewport unless it already exists
        width = w > 0 && x == w ? gw - 640 : 640
        height = h > 0 && y == h ? gh - 480 : 480
        vp = Viewport.new(x * 640, y * 480, width, height, true)
        vp.offset_x = x * 640
        vp.offset_y = y * 480
        # Have to do this in order to prevent overlapping with the parent
        # (for Spriteset_Map viewport1 mainly)
        vp.z = self.viewport.z - 1
        self.viewport.children.push(vp)
        # Create the child Plane
        plane = Plane.new(vp,false)
        plane.offset_x = x * 640
        plane.ox = 0
        plane.offset_y = y * 480
        plane.oy = 0
        # Push to array
        @children.push(plane)
      end
    end
  end
 
  # For the remaining Plane properties, if the parent changes, so do its children
 
  alias dispose_parent dispose
  def dispose
    @children.each{|child| child.dispose} if @parent
    dispose_parent
  end
 
  alias zoom_x_parent zoom_x=
  def zoom_x=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_x_parent(new_val)} if @parent
    zoom_x_parent(new_val)
  end
 
  alias zoom_y_parent zoom_y=
  def zoom_y=(new_val)
    new_val = 0 if new_val < 0
    @children.each{|child| child.zoom_y_parent(new_val)} if @parent
    zoom_y_parent(new_val)
  end
 
  alias ox_parent ox=
  def ox=(new_val)
    @children.each{|child| child.ox = new_val} if @parent
    ox_parent(new_val + @offset_x)
  end
 
  alias oy_parent oy=
  def oy=(new_val)
    @children.each{|child| child.oy = new_val} if @parent
    oy_parent(new_val + @offset_y)
  end
 
  alias bitmap_parent bitmap=
  def bitmap=(new_val)
    @children.each{|child| child.bitmap_parent(new_val)} if @parent
    #bitmap_parent(new_val)
  end
 
  alias visible_parent visible=
  def visible=(new_val)
    @children.each{|child| child.visible_parent(new_val)} if @parent
    visible_parent(new_val)
  end
 
  alias z_parent z=
  def z=(new_val)
    # Because the children spawn new Viewports, they have to be lower than the
    # parent's viewport to prevent drawing OVER the parent...unless the Plane's
    # z-value is more than zero, in which case the children viewports NEED to be
    # higher than the parent's. By doing this, we can have panoramas be below
    # the tilemap and fogs be over the tilemap.
    if @parent && @children[0]
      child = @children[0]
      if new_val > 0 && child.viewport.z < self.viewport.z
        @children.each{|child| child.viewport.z += 1}
      elsif new_val <= 0 && child.viewport.z >= self.viewport.z
        @children.each{|child| child.viewport.z -= 1}
      end
    end
   
    @children.each{|child| child.z_parent(new_val)} if @parent
    z_parent(new_val)
  end
 
  alias opacity_parent opacity=
  def opacity=(new_val)
    @children.each{|child| child.opacity_parent(new_val)} if @parent
    opacity_parent(new_val)
  end
 
  alias color_parent color=
  def color=(new_val)
    if @parent
      @children.each{|child| child.color_parent(new_val)}
    else
      color_parent(new_val)
    end
  end
 
  alias blend_type_parent blend_type=
  def blend_type=(new_val)
    @children.each{|child| child.blend_type_parent(new_val)} if @parent
    blend_type_parent(new_val)
  end
 
  alias tone_parent tone=
  def tone=(new_val)
    if @parent
      @children.each{|child| child.tone_parent(new_val)}
    else
      tone_parent(new_val)
    end
  end
 
end
#------------------------------------------[End of Unlimited Resolution]--------
end

# Resize the game window (if using XP) and load the MapInfos file
Resolution.resize_game unless XPACE
XPAT_MAP_INFOS = load_data("Data/MapInfos.rxdata")
Title: Re: [XP] XP Ace Tilemap
Post by: Kise on September 09, 2017, 03:41:52 am
Works perfectly, thank you.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on September 10, 2017, 01:30:43 am
Thanks for the confirmation.
Version 0.36 uploaded to resolve that issue.
Title: Re: [XP] XP Ace Tilemap
Post by: whitespirits on October 12, 2017, 12:30:02 pm
Hey guys, love this tilemap great work! I wanted to ask if there is any addon that can manage UI or HUD elements to fit the chosen resolution? Im using Netmaker. Thanks!
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on October 12, 2017, 01:57:53 pm
That's impossible unless the scripter of the HUD allowed their script to adjust its positioning based on the game's resolution. How is XPA Tilemap supposed to be aware of these scripts and change their coordinates accordingly?
Title: Re: [XP] XP Ace Tilemap
Post by: whitespirits on October 12, 2017, 02:29:51 pm
Ye that makes sense, I will need to adjust the in game setup, its mainly the icons bottom left?
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on October 13, 2017, 09:44:48 am
Why is not possible to do full screen for XP ?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on October 13, 2017, 02:22:19 pm
Largely because I never looked into it fully. RMXP is picky when it comes to fullscreen, namely that it always changes the monitor resolution to 640x480. You have to use Win32API calls to forcefully change the monitor resolution to a custom size. Same thing occurs when switching back to window mode.

I can take another look at it this weekend.
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on October 18, 2017, 03:11:43 pm
BTW, your script is awesome !

But he's not compatible with Advanced Weather System.
You can't adjust when the script is below XPA_Tilemap.
And when you put under XPA_Tilemap, you can't use another weather effects.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on October 19, 2017, 02:20:50 am
Can you describe the situation a bit more? The scripts do work together and I see no conflicts at all. The only issue would probably be that Advanced Weather assumes a default 640x480 resolution. XPA Tilemap's weather adjustment setting only applies to the default RMXP weather effects.
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on October 19, 2017, 09:07:50 am
I forget to say it's because my game screen is 854x480.
As you saying, the script assumes a default 640x480 resolution.

Too large for the Advanced Weather, maybe ?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on October 19, 2017, 05:35:15 pm
Advanced Weather is going to need to be modified a bit. Take a look here
http://forum.chaos-project.com/index.php/topic,7947.0.html
You'll see an entry for Advanced Weather fix. Try it out. Obviously, replace SCREEN with SCREEN_RESOLUTION.

I'm putting compatibility patches on my To-Do list.
Title: Re: [XP] XP Ace Tilemap
Post by: kreiss on October 19, 2017, 11:54:47 pm
Thanks, it work perfectly !
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on December 18, 2017, 11:37:34 am
Hi! Here I am, trying to report a bug.

I was just trying my game, everything worked nicely, but after some time (15mins maybe) of doing random stuff like walking teleporting, battling, the game crashed after attempting to load the next map. The error said "Failed to create bitmap". Weird thing is, it happened when I was at a town, then entered a house, did some basic stuff, then tried to get back to town and it crashed. That's just to say the map just worked before.

Here is the lines it points to.
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
  attr_accessor :filename
  alias set_filename_of_bitmap initialize
  def initialize(*args)
    # Associate the bitmap with the filename of the graphic; empty string otherwise
    @filename = args.size == 1 ? File.basename(args[0], '.*') : ''
    set_filename_of_bitmap(*args)
  end
end

Basically, it fails when loading a bitmap, still not sure which one since I haven't been able to reproduce the bug (will do if I encounter it some more times :^D).

Still, haven't tried but I'm pretty sure it's one of these weird bugs that just happen at seemingly random moments. I'll try and replicate it if I can.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on December 18, 2017, 02:37:47 pm
I have seen this reported before, but can't remember the details. It might have something to do with autotiles. Be sure to put some print statements to see what file it is you're loading.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on December 18, 2017, 02:41:11 pm
I think I might have reported this.

Did you try updating to the newest version first?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on December 18, 2017, 03:50:33 pm
Yep you did (http://forum.chaos-project.com/index.php/topic,14638.msg195620.html#msg195620)
But I don't think a solution was ever found. I don't remember reproducing the example you gave either.
Title: Re: [XP] XP Ace Tilemap
Post by: orochii on December 18, 2017, 11:19:31 pm
I just did update to the most recent version (was using the 0.32 or something like that). I'll be using this one, doing more of these "extensive tests" and keep an eye on it.

I'm still confused though, since the map actually works, it's just maybe after several teleports. I remember an issue with RGSS3's way of handling disposed bitmaps that gave errors before, but I remember that being resolved. As for files, since the map actually loads fine, just sometimes don't, I am not even sure if there is an actual problem with the map itself.

But yeah, I'll keep an eye on it. Hopefully I'll find the same bug again this week xD. Dunno how elusive it is.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on December 19, 2017, 08:48:46 am
Wasn't the issue that the bitmap size was 0? Something with missing autotiles?
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on December 19, 2017, 02:33:59 pm
It can't be, especially since he claims that it worked before. What you're mentioning was an entirely different bug where the game hard crashed (DLL was attempting to draw with no bitmap).

The only time the error can occur is if directly calling Bitmap#new where width < 0 or height == 0 (height < 0 still works, which I believe you discovered during ARC) OR you draw too many bitmaps.

In v0.33 I did mention this change:
QuoteCreation of autotile graphics was handled poorly. If it did not fit the RPG Maker standards, it would dispose the original graphic but never replace it. This could have led to memory leaks, but you would ultimately crash before that happened (see first bullet point).

Which is probably the problem being discussed here.
Title: Re: [XP] XP Ace Tilemap
Post by: Sin86 on January 14, 2018, 01:06:13 pm
I am loving this so far. However, I am looking for a way to have the camera center around my character as I am using the custom resolution aspect of the script. My camera focuses on my character veering to the left rather than the center. On the default resolution, it is on the center. I'm using Blizz ABS btw.

Also, wanted to say that I went ahead to see if I needed to see if this fix would work from the Resolution Compatibility thread(http://forum.chaos-project.com/index.php/topic,7947.0.html) for Blizz ABS and I did get the SCREEN error and though I did change it to SCREEN_RESOLUTION, that fixed the first error but goes back to the 2nd, which I said in the other thread, so here I'll repost it.


Accidently deleted my post when I was going to edit it. Anyway, I am using 0.97

However, Blizz ABS plugin no longer works. I tested it on 0.96 and it worked well there but then I get this error on 0.97.


Script Custom Resolution for Blizz ABS line 14 Nomethoderror occurred
undefined method tile_size for #<game_map:0xedd44e0>

I can get through just fine but the reason why I'm not using 0.96 is because of some wall clipping issue when going behind walls with priority tiles.



Might be some other issues I am unaware of with the Blizz ABS patch so that is why I am reposting this here.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 14, 2018, 04:35:12 pm
http://forum.chaos-project.com/index.php/topic,7947.msg196388.html#msg196388

Again, replacing SCREEN with SCREEN_RESOLUTION.
Title: Re: [XP] XP Ace Tilemap
Post by: Sin86 on January 14, 2018, 05:03:15 pm
Thanks KK20, I'll let you know if anything goes wrong.

Also, to add on to this. It is best to change all SCREEN to SCREEN_RESOLUTION because I found more errors, not just those that was from your extra script or the beginning of the script where the errors where first at.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 14, 2018, 05:06:29 pm
I mean obviously. Custom Resolution uses SCREEN to set the game resolution. XPA Tilemap uses SCREEN_RESOLUTION instead. Of course you want to replace all instances of SCREEN with SCREEN_RESOLUTION; there is no constant variable SCREEN defined in XPA Tilemap.
Title: Re: [XP] XP Ace Tilemap
Post by: Sin86 on January 14, 2018, 10:27:58 pm
Somehow I am getting an error that does not pinpoint me to any lines in any scripts but if I am using the F12 script, http://forum.chaos-project.com/index.php/topic,3613.0.html I see that my game freezes. No error message, just a freeze

I went to see on moving my most recent scripts and can confirm that this is the only script doing this. Went as far as also making a new project with just this script and that one. Went and tested the most updated version of the F12 fix too. Only difference I get is the exploding animation, then a freeze, but still, a freeze.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 14, 2018, 10:50:16 pm
QuoteF12 Pause with image script

Literally doing what the script was designed to do.

I think this is what you're looking for: http://forum.chaos-project.com/index.php/topic,13629.0.html

Or, if you are using XPA, there's no need for an F12 script.
Title: Re: [XP] XP Ace Tilemap
Post by: Sin86 on January 15, 2018, 12:22:34 am
Oops, sorry about that. I went to go search for it in the database and I accidently clicked the wrong one. Stupid of me lol.

Anyway, this script is fantastic.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 16, 2018, 01:35:24 am
Updated to version 0.4!



Thanks to Blizzard for the transition algorithm that I largely based mine off of.
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 16, 2018, 02:50:55 am
... what transition algorithm? O_o I don't remember anything specific I made. xD
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 16, 2018, 03:17:50 am
Start here: http://forum.chaos-project.com/index.php/topic,14638.msg195492.html#msg195492
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on January 16, 2018, 03:38:58 am
Oh that, nice. xD
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on January 29, 2018, 01:09:57 am
Update to version 0.41 to address a potential issue with renamed games using Enigma Virtual Box (http://forum.chaos-project.com/index.php/topic,15507.0.html). This only applies to XP users. XPA users are advised to update to XPA 2.31 (http://forum.chaos-project.com/index.php/topic,12899.0.html)

Note this was only a minor script update. No changes were made to the DLLs.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on March 24, 2019, 12:22:32 am
Updated to v0.42
(Sorry Memor-X that it took this long!)



In terms of things to bring to XPAT, I have started work on a highly requested feature:
Spoiler: ShowHide
(https://cdn.discordapp.com/attachments/177202881177452544/550600312080302086/zoomy.gif)
Title: Re: [XP] XP Ace Tilemap
Post by: Blizzard on March 24, 2019, 07:25:09 am
Quote from: KK20 on March 24, 2019, 12:22:32 am
Additionally, Planes initialized without a Viewport on larger resolutions would not appear


So, if I decide to make CP 16:9, I'll have to update?
Title: Re: [XP] XP Ace Tilemap
Post by: schmoggi on February 20, 2022, 05:11:40 am
Hi,

hope this is not seen as necroposting. I'm curious if this project (the tilemap / the xpace project) is still getting updates? Some years have passed since the last post. The last teaser with the zoom feature looks interesting. Any news on this?

Thank you!
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 20, 2022, 03:03:07 pm
So the thing with the camera never really got out of the experimental phase. I was going to use it in another project first to try and work out the bugs, but that ended fairly quickly. Then Jaiden came along and wanted to use it, so I gave the script and offered minimal support to get it working in their project. Skip ahead a year and we moved over to MKXP. The camera script is still being used, but not alongside XPAT. We gave up on XPA because of performance issues.

Here's the demo I made some years back. If you're able to make use of it, go ahead and use it. But all interest has been lost by me and everyone else, so nothing official will ever come from it.

https://www.dropbox.com/s/m9mhaylk66fjsho/ZoomDemo.zip?dl=0
Title: Re: [XP] XP Ace Tilemap
Post by: schmoggi on February 21, 2022, 07:54:27 am
Thanks for answering.

Well, not much surprise on my end. MKXP, in my tests, is really making a difference and efforts like XPA(T), though great work, becomes obsolete in a way. I was kind of divided which one to use, actually. But thanks for posting the demo. I will definitely go through it, even if it is only for experimenting and learning purpose. I didn't know MKXP had a zoom function for the tilemap or some kind of similar build in feature. Definitely going to study that one a bit more.
Title: Re: [XP] XP Ace Tilemap
Post by: KK20 on February 21, 2022, 12:37:39 pm
MKXP doesn't have tilemap zoom, Jaiden added it on a private github repo.
Title: Re: [XP] XP Ace Tilemap
Post by: schmoggi on February 22, 2022, 04:06:19 am
Ah, okay. Thanks for clearing that up. So it's basically possible then, good to know. Guess I'll have to dive deep into the code someday and see what one with basic coding skills can do :D.
Title: Re: [XP] XP Ace Tilemap
Post by: Jaiden on March 07, 2022, 02:29:13 pm
I will eventually make the fork public (I technically am obliged to, due to GPL's terms). Code is currently just too much of a dumping ground to share. You can keep an eye on my Github (https://github.com/JaidenAlemni), if you'd like.