| Wachunga's Fog of War Script | ||||||||||
| Ok, now, before we get into too much here, please be aware that there is a newer version of this at RMXP.net, but I am using this older one. | ||||||||||
| Now, If you are using Rataime's Sun/Shadow scripts, please place the new class for this above those. Also, at the bottom of the page there is a link to the Auto-tile for this script. So, make a new Class called Fog of War and place this into it: | ||||||||||
| =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 [email protected] @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, } |
||||||||||
| Now, to use this, place <FOW> into the map name of the map that you want the fog of war on. Here is the auto tile btw, just import it into yout resource editor: | ||||||||||
| FOW Auto Tile | ||||||||||