=begin
============
Fog of War - version 1.01 (2005-11-04)
============
by Wachunga
0.8 - original release
0.85
- added colour parameter to map names
- fixed bug where map grids overlapped
0.9
- switched over to a tilemap (from a sprite)
- now more compatible with minimap scripts (but they'll have to take
extra tilemap into account)
1.0
- switched over to an autotile instead of using a custom tileset
* edges looks nicer, but gradual fading had to be removed
* colour parameter no longer possible (set by autotile)
- move event (including jumping and speed changes) bug fixed
- teleportation bug fixed
- some optimization
- made compatible with Cogwheel's Pixel Movement script
(see
http://www.rmxp.net/forums/index.php?showtopic=24716 for details)
1.01
- fixed bug when teleporting from map without FoW to a map with FoW
Note:
There's no need to add the autotile via the database. Just place the file in
the autotile folder, import it, and change the FOW_AT_NAME constant to
the appropriate filename. To change the colour of the fog of war, create a
new autotile.
To indicate a map is to have fog of war (i.e. its tiles are dark until
the player gets within visual range), include <FoW> in its name. You may
also optionally specify a range between 0 and 3. This may also be
included in the map name, as in this example:
"your-map-name <FoW><2>" (range is 2)
The ranges work as follows:
range = 0 reveals just the square on which the player stands
range = 1 is the same as range 0 plus four adjacent tiles
i.e. @
@P@
@
range = 2 is the same as range 1 plus eight additional tiles
i.e. @
@@@
@@P@@
@@@
@
range = 3 (default) is the same as range 2 plus twelve additional tiles
i.e. @
@@@
@@@@@
@@@P@@@
@@@@@
@@@
@
=end
#-------------------------------------------------------------------------------
FOW = 0b00
REVEALED = 0b01
# tiles with no surrounding fog are flagged "SKIP" for efficiency
SKIP = 0b10
FOW_AT_NAME = "fow_default"
#-------------------------------------------------------------------------------
class Game_Map
attr_reader :fow_on
attr_reader :fow_grid
attr_reader :fow_range
alias dm_setup setup_map
def setup_map(map_id)
dm_setup(map_id)
# set defaults
@fow_on = false
@fow_grid = nil
@fow_range = 3
# get any tags from the map name
tags = $game_map.map_name.delete(' ').scan(/<[A-Za-z0-9_.,]+>/)
if not tags.empty? and tags[0].upcase == '<FOW>'
tags.shift # remove FOW tag
@fow_on = true
if @fow_grid == nil # only if not already defined
@fow_grid = Array.new(@map.width, FOW)
for i in 0...@map.width
@fow_grid[i] = Array.new(@map.height, FOW)
end
end
# check if range specified, else default to 3
if not tags.empty?
x = tags[0].delete("<>").to_i
@fow_range = x if x >= 0 and x < 4
end
end
end
=begin
Updates the underlying grid which keeps track of which tiles have been
"discovered" (i.e. no fog of war) based on where player has already explored.
=end
def update_fow_grid
px = $game_player.x
py = $game_player.y
@fow_grid[px][py] |= REVEALED
# reveal more, depending on range
if @fow_range > 0
if px > 0
@fow_grid[px-1][py] |= REVEALED
end
if py < @map.height-1
@fow_grid[px][py+1] |= REVEALED
end
if py > 0
@fow_grid[px][py-1] |= REVEALED
end
if px < @map.width-1
@fow_grid[px+1][py] |= REVEALED
end
if @fow_range > 1
if px > 0
if py > 0
@fow_grid[px-1][py-1] |= REVEALED
end
if py < @map.height-1
@fow_grid[px-1][py+1] |= REVEALED
end
if px > 1
@fow_grid[px-2][py] |= REVEALED
end
end
if px < @map.width-1
if py > 0
@fow_grid[px+1][py-1] |= REVEALED
end
if py < @map.height-1
@fow_grid[px+1][py+1] |= REVEALED
end
end
if px < @map.width-2
@fow_grid[px+2][py] |= REVEALED
end
if py > 1
@fow_grid[px][py-2] |= REVEALED
end
if py < @map.height-2
@fow_grid[px][py+2] |= REVEALED
end
if @fow_range > 2
if px > 0
if py > 1
@fow_grid[px-1][py-2] |= REVEALED
end
if py < @map.height-2
@fow_grid[px-1][py+2] |= REVEALED
end
if px > 1
if py > 0
@fow_grid[px-2][py-1] |= REVEALED
end
if py < @map.height-1
@fow_grid[px-2][py+1] |= REVEALED
end
if px > 2
@fow_grid[px-3][py] |= REVEALED
end
end
end
if px < @map.width-1
if py > 1
@fow_grid[px+1][py-2] |= REVEALED
end
if py < @map.height-2
@fow_grid[px+1][py+2] |= REVEALED
end
if px < @map.width-2
if py > 0
@fow_grid[px+2][py-1] |= REVEALED
end
if py < @map.height-1
@fow_grid[px+2][py+1] |= REVEALED
end
if px < @map.width-3
@fow_grid[px+3][py] |= REVEALED
end
end
end
if py > 2
@fow_grid[px][py-3] |= REVEALED
end
if py < @map.height-3
@fow_grid[px][py+3] |= REVEALED
end
end
end
end
end
def map_name
return load_data("Data/MapInfos.rxdata")[@map_id].name
end
end
#-------------------------------------------------------------------------------
class Spriteset_Map
def initialize
@viewport1 = Viewport.new(0, 0, 640, 480)
@viewport2 = Viewport.new(0, 0, 640, 480)
@viewport3 = Viewport.new(0, 0, 640, 480)
@viewport2.z = 200
@viewport3.z = 5000
@tilemap = Tilemap.new(@viewport1)
@tilemap.tileset = RPG::Cache.tileset($game_map.tileset_name)
for i in 0..6
autotile_name = $game_map.autotile_names[i]
@tilemap.autotiles[i] = RPG::Cache.autotile(autotile_name)
end
@tilemap.map_data = $game_map.data
@tilemap.priorities = $game_map.priorities
@panorama = Plane.new(@viewport1)
@panorama.z = -1000
@fog = Plane.new(@viewport1)
@fog.z = 3000
@character_sprites = []
for i in $game_map.events.keys.sort
sprite = Sprite_Character.new(@viewport1, $game_map.events[i])
@character_sprites.push(sprite)
end
@character_sprites.push(Sprite_Character.new(@viewport1, $game_player))
@weather = RPG::Weather.new(@viewport1)
@picture_sprites = []
for i in 1..50
@picture_sprites.push(Sprite_Picture.new(@viewport2,
$game_screen.pictures[i]))
end
@timer_sprite = Sprite_Timer.new
# add fog of war tilemap...
if $game_map.fow_on
for m in 0...$game_map.width
for n in 0...$game_map.height
# reset SKIP flag
$game_map.fow_grid[m][n] &= ~SKIP
end
end
@fow_tilemap = Tilemap.new(@viewport1)
@fow_tilemap.autotiles[0] = RPG::Cache.autotile(FOW_AT_NAME)
@fow_autotiles = Hash.new(0)
j = 48 # starting autotile index
for i in Autotile_Keys
@fow_autotiles[i] = j
j += 1
end
# add duplicates
for i in Duplicate_Keys.keys
@fow_autotiles[i] = @fow_autotiles[Duplicate_Keys[i]]
end
data = Table.new($game_map.width, $game_map.height, 3)
# set everything to fog
for x in 0...$game_map.width
for y in 0...$game_map.height
data[x,y,2] = 48 # fog
end
end
@fow_tilemap.map_data = data
priorities = Table.new(96)
# set to highest priority to ensure everything is covered
for i in 48...96
priorities[i] = 5
end
@fow_tilemap.priorities = priorities
$game_map.update_fow_grid
update_fow_tilemap # reveal any explored tiles
end
update
end
=begin
Updates the fog of war tilemap based on the map's underlying grid.
This method is called by Game_Player.update whenever the player moves.
=end
def update_fow_tilemap
checked = Array.new($game_map.width,0)
for k in 0...$game_map.width
checked[k] = Array.new($game_map.height,0)
end
for x in (($game_map.display_x/128)-1).round .. (($game_map.display_x/128)+21).round
for y in (($game_map.display_y/128)-1).round .. (($game_map.display_y/128)+16).round
# check boundaries
if x > $game_map.width - 1 or x < 0 then next end
if y > $game_map.height - 1 or y < 0 then next end
if $game_map.fow_grid[x][y] == REVEALED # (but not SKIP)
others = false
@fow_tilemap.map_data[x,y,2] = 0 if @fow_tilemap.map_data[x,y,2] != 0
for i in x-1 .. x+1
for j in y-1 .. y+1
# check new boundaries
if i > $game_map.width - 1 or i < 0 then next end
if j > $game_map.height - 1 or j < 0 then next end
if $game_map.fow_grid[i][j] == FOW
others = true # can't flag as SKIP because there's nearby fog
if checked[i][j] == 0
checked[i][j] = 1
# only fill if not already revealed
if @fow_tilemap.map_data[i,j,2] != 0
# calculate adjacent fog
adj = ''
if (i == 0)
adj << '147'
else
if (j == 0) then adj << '1'
else
if ($game_map.fow_grid[i-1][j-1] == FOW) then adj << '1' end
end
if ($game_map.fow_grid[i-1][j] == FOW) then adj << '4' end
if (j == $game_map.height-1) then adj << '7'
else
if ($game_map.fow_grid[i-1][j+1] == FOW) then adj << '7' end
end
end
if (i == $game_map.width-1)
adj << '369'
else
if (j == 0) then adj << '3'
else
if ($game_map.fow_grid[i+1][j-1] == FOW) then adj << '3' end
end
if ($game_map.fow_grid[i+1][j] == FOW) then adj << '6' end
if (j == $game_map.height-1) then adj << '9'
else
if ($game_map.fow_grid[i+1][j+1] == FOW) then adj << '9' end
end
end
if (j == 0)
adj << '2'
else
if ($game_map.fow_grid[i][j-1] == FOW) then adj << '2' end
end
if (j == $game_map.height-1)
adj << '8'
else
if ($game_map.fow_grid[i][j+1] == FOW) then adj << '8' end
end
# if no adjacent fog, set it as 0
if (adj == '') then adj = '0' end
# convert to an array, sort, and then back to a string
adj = adj.split(//).sort.join
@fow_tilemap.map_data[i,j,2] = eval '@fow_autotiles[adj.to_i]'
end
end
end
end
end
if not others
# no adjacent fog found, so flag tile to prevent processing again
$game_map.fow_grid[x][y] |= SKIP
end
end
end
end
end
alias old_dispose dispose
def dispose
if @fow_tilemap != nil
@fow_tilemap.dispose
end
old_dispose
end
alias old_update update
def update
if $game_map.fow_on == true
@fow_tilemap.ox = $game_map.display_x / 4
@fow_tilemap.oy = $game_map.display_y / 4
@fow_tilemap.update
end
old_update
end
end
#-------------------------------------------------------------------------------
class Game_Player
def initialize
super
@last_x = @x
@last_y = @y
end
def update_jump
super
# only update when about to land, not revealing anything jumped over
if $game_map.fow_on and @jump_count == 0
$game_map.update_fow_grid
$scene.spriteset.update_fow_tilemap
end
end
def update_move
super
if $game_map.fow_on and (@x != @last_x or @y != @last_y)
unless jumping?
$game_map.update_fow_grid
$scene.spriteset.update_fow_tilemap
end
end
@last_x = @x
@last_y = @y
end
end
#-------------------------------------------------------------------------------
class Scene_Map
attr_reader :spriteset
end
=begin
Autotile in column 2:
row\col| 1 2 3 4 5 6 7 8
---------------------------
1 | 48 49 50 51 52 53 54 55
2 | 56 57 58 59 60 61 62 63
3 | 64 65 66 67 68 69 70 71
4 | 72 73 74 75 76 77 78 79
5 | 80 81 82 83 84 85 86 87
6 | 88 89 90 91 92 93 94 95
The function to return the index of a single tile within an autotile
(given by at_index) is (at_index-1)*48 + col-1 + (row-1)*8
(where row, col, and at_index are again NOT zero-indexed)
=end
=begin
The following array lists systematic keys which are based on adjacent
walls (where 'W' is the wall itself):
1 2 3
4 W 6
7 8 9
e.g. 268 is the key that will be used to refer to the autotile
which has adjacent walls north, east, and south. For the Castle Prison
tileset (autotile #1), this is 67.
(It's a bit unwieldy, but it works.)
=end
Autotile_Keys = [
12346789,
2346789,
1246789,
246789,
1234678,
234678,
124678,
24678,
1234689,
234689,
124689,
24689,
123468,
23468,
12468,
2468,
23689,
2689,
2368,
268,
46789,
4678,
4689,
468,
12478,
1248,
2478,
248,
12346,
2346,
1246,
246,
28,
46,
689,
68,
478,
48,
124,
24,
236,
26,
8,
6,
2,
4,
0 ]
# many autotiles handle multiple situations
# this hash keeps track of which keys are identical
# to ones already defined above
Duplicate_Keys = {
123689 => 23689,
236789 => 23689,
1236789 => 23689,
34689 => 4689,
14689 => 4689,
134689 => 4689,
14678 => 4678,
34678 => 4678,
134678 => 4678,
146789 => 46789,
346789 => 46789,
1346789 => 46789,
23467 => 2346,
23469 => 2346,
234679 => 2346,
123467 => 12346,
123469 => 12346,
1234679 => 12346,
12467 => 1246,
12469 => 1246,
124679 => 1246,
124789 => 12478,
123478 => 12478,
1234789 => 12478,
146 => 46,
346 => 46,
467 => 46,
469 => 46,
1346 => 46,
1467 => 46,
1469 => 46,
3467 => 46,
3469 => 46,
4679 => 46,
13467 => 46,
13469 => 46,
14679 => 46,
34679 => 46,
134679 => 46,
128 => 28,
238 => 28,
278 => 28,
289 => 28,
1238 => 28,
1278 => 28,
1289 => 28,
2378 => 28,
2389 => 28,
2789 => 28,
12378 => 28,
12389 => 28,
12789 => 28,
23789 => 28,
123789 => 28,
1247 => 124,
2369 => 236,
147 => 4,
247 => 24,
14 => 4,
47 => 4,
1478 => 478,
3478 => 478,
4789 => 478,
134789 => 478,
14789 => 478,
13478 => 478,
34789 => 478,
1234 => 124,
1247 => 124,
1249 => 124,
12347 => 124,
12349 => 124,
12479 => 124,
123479 => 124,
1236 => 236,
2367 => 236,
2369 => 236,
12367 => 236,
12369 => 236,
23679 => 236,
123679 => 236,
12368 => 2368,
23678 => 2368,
123678 => 2368,
12348 => 1248,
12489 => 1248,
123489 => 1248,
1689 => 689,
3689 => 689,
6789 => 689,
13689 => 689,
16789 => 689,
36789 => 689,
136789 => 689,
12689 => 2689,
26789 => 2689,
126789 => 2689,
23478 => 2478,
24789 => 2478,
234789 => 2478,
12 => 2,
23 => 2,
27 => 2,
29 => 2,
123 => 2,
127 => 2,
129 => 2,
237 => 2,
239 => 2,
279 => 2,
1237 => 2,
1239 => 2,
1279 => 2,
2379 => 2,
12379 => 2,
14 => 4,
47 => 4,
34 => 4,
49 => 4,
147 => 4,
134 => 4,
347 => 4,
349 => 4,
149 => 4,
479 => 4,
1347 => 4,
1479 => 4,
1349 => 4,
3479 => 4,
13479 => 4,
16 => 6,
36 => 6,
67 => 6,
69 => 6,
136 => 6,
167 => 6,
169 => 6,
367 => 6,
369 => 6,
679 => 6,
1369 => 6,
3679 => 6,
1367 => 6,
1679 => 6,
13679 => 6,
78 => 8,
89 => 8,
18 => 8,
38 => 8,
138 => 8,
789 => 8,
178 => 8,
189 => 8,
378 => 8,
389 => 8,
1789 => 8,
3789 => 8,
1378 => 8,
1389 => 8,
13789 => 8,
1468 => 468,
3468 => 468,
13468 => 468,
2467 => 246,
2469 => 246,
24679 => 246,
2348 => 248,
2489 => 248,
23489 => 248,
1268 => 268,
2678 => 268,
12678 => 268,
148 => 48,
348 => 48,
489 => 48,
1348 => 48,
1489 => 48,
3489 => 48,
13489 => 48,
168 => 68,
368 => 68,
678 => 68,
1368 => 68,
1678 => 68,
3678 => 68,
13678 => 68,
234 => 24,
247 => 24,
249 => 24,
2347 => 24,
2349 => 24,
2479 => 24,
23479 => 24,
126 => 26,
267 => 26,
269 => 26,
1267 => 26,
1269 => 26,
2679 => 26,
12679 => 26,
}