-
Notifications
You must be signed in to change notification settings - Fork 12
/
Fog of War.rb
357 lines (313 loc) · 11.7 KB
/
Fog of War.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#===============================================================================
# TheoAllen - Fog of War
# Requested by : Zero0018
# Last edited : 15.01.2015
#-------------------------------------------------------------------------------
# How to use :
# Put the script below materials but above main
# No external resource is required
#
#------------------------------------------------------------------------------
# ** MAP NOTETAG :
#------------------------------------------------------------------------------
# To show fog in map, simply put <fog> in map note
# To hide fog in map, simply put <no fog> in map note
#
# Set the default of showing fog in configuration
#
#------------------------------------------------------------------------------
# ** SCRIPT CALL :
#------------------------------------------------------------------------------
#
# $game_map.reveal_tiles(x, y)
# $game_map.reveal_tiles(x, y, distance)
# Will reveal tiles in x,y within the distance. If distance is ommited, it will
# be same as the VisiRange in script setting
#
# $game_map.events[event_id].reveal_tiles
# $game_map.events[event_id].reveal_tiles(distance)
# Will reveal tiles from the event location within the distance. If distance is
# ommited, it will be same as the VisiRange in script setting
#
#-------------------------------------------------------------------------------
# Configuration
#===============================================================================
module Theo
VisiRange = 4
# Visibility range of the character. Larger value, longer distance
FogOpacity = 255
# Fog opacity. Set 255 for full opacity.
DefaultFog = true
# If set to true, every map will has fog. Unless you put <no fog>
# If set to false, every map will has no fog. Unless you put <fog>
end
#===============================================================================
# End of config
#===============================================================================
#===============================================================================
# ** Bitmap
#===============================================================================
class Bitmap
# Fill entire bitmap with color
def entire_fill(color = Color.new(0,0,0,150))
fill_rect(self.rect,color)
end
end
#===============================================================================
# ** Fog of War
#===============================================================================
class Fog_of_War < Plane
@@bitmap_cache = {}
#----------------------------------------------------------------------------
# * Initialize
#----------------------------------------------------------------------------
def initialize(vport)
super(vport)
@id = -1
end
#----------------------------------------------------------------------------
# * Update
#----------------------------------------------------------------------------
def update
if $game_map
if @id != $game_map.map_id
@id = $game_map.map_id
@width = $game_map.width
@height = $game_map.height
update_bitmap
end
self.ox = $game_map.display_x * 32
self.oy = $game_map.display_y * 32
self.visible = !$game_map.no_fog?
end
end
#----------------------------------------------------------------------------
# * Update bitmap
#----------------------------------------------------------------------------
def update_bitmap
bmp = @@bitmap_cache[@id]
unless bmp && !bmp.disposed?
bmp = Bitmap.new(@width * 32, @height * 32)
@@bitmap_cache[@id] = bmp
end
self.bitmap = bmp
return if $game_map.no_fog?
bitmap.entire_fill(Color.new(0,0,0,Theo::FogOpacity))
reveal_tiles($game_system.revealed_tiles)
reveal_tiles($game_player.reveal_tiles)
end
#----------------------------------------------------------------------------
# * Reveal Tiles
#----------------------------------------------------------------------------
def reveal_tiles(tiles)
tiles.each do |pos|
x = pos.x * 32
y = pos.y * 32
bitmap.clear_rect(x,y,32,32)
end unless disposed?
end
end
#===============================================================================
# ** Game_System
#===============================================================================
class Game_System
#----------------------------------------------------------------------------
# * Revealed tiles
#----------------------------------------------------------------------------
def revealed_tiles
@revealed_map ||= {}
@revealed_map[$game_map.map_id] ||= []
@revealed_map[$game_map.map_id]
end
#----------------------------------------------------------------------------
# * Revealed tiles =
#----------------------------------------------------------------------------
def revealed_tiles=(t)
@revealed_map ||= {}
@revealed_map[$game_map.map_id] = t
end
end
#===============================================================================
# ** Revealed Node
#===============================================================================
class Revealed_Node
#----------------------------------------------------------------------------
# * Public attributes
#----------------------------------------------------------------------------
attr_accessor :parent
attr_accessor :visited
attr_accessor :x
attr_accessor :y
attr_reader :expanded
attr_reader :nodes
#----------------------------------------------------------------------------
# * Initialize
#----------------------------------------------------------------------------
def initialize(x,y)
@x ,@y = x, y
@nodes = {}
@visited = false
@expanded = false
end
#----------------------------------------------------------------------------
# * Expand node
#----------------------------------------------------------------------------
def expand_node(mapnodes, char)
dir = [2,4,6,8]
dir.each do |d|
xpos = $game_map.round_x_with_direction(@x, d)
ypos = $game_map.round_y_with_direction(@y, d)
key = [xpos, ypos]
next_node = mapnodes[key]
if next_node.nil?
next_node = Revealed_Node.new(xpos, ypos)
mapnodes[key] = next_node
elsif next_node.visited
next
end
next_node.parent = self
self.nodes[d] = next_node
end
@expanded = true
end
#----------------------------------------------------------------------------
# * Get Parent Direction
#----------------------------------------------------------------------------
def get_parent_dir
parent.nodes.index(self)
end
end
#===============================================================================
# ** Game_Map
#===============================================================================
class Game_Map
#----------------------------------------------------------------------------
# * No fog?
#----------------------------------------------------------------------------
def no_fog?
return false unless @map
return true if @map.note[/<no[\s_]+fog>/i]
return false if @map.note[/<fog>/i]
return !Theo::DefaultFog
end
#----------------------------------------------------------------------------
# * Reveal tiles
#----------------------------------------------------------------------------
def reveal_tiles(x, y, distance = Theo::VisiRange, reveal = true)
return if no_fog?
# Initialize
@revealed_nodes = {}
@max_distance = distance - 1
@init_x = x
@init_y = y
# Make first node to check
first_node = Revealed_Node.new(x, y)
first_node.expand_node(@revealed_nodes, self)
first_node.visited = true
@revealed_nodes[[x, y]] = first_node
@reveal_queue = []
@reveal_queue.push(first_node)
# spread search using BFS
until @reveal_queue.empty?
spread_search(@reveal_queue.shift)
end
node_to_reveal = @revealed_nodes.values - $game_system.revealed_tiles
sprset = SceneManager.scene.spriteset
sprset.fogofwar.reveal_tiles(node_to_reveal) if sprset
$game_system.revealed_tiles += @revealed_nodes.values
end
#----------------------------------------------------------------------------
# * Spread search
#----------------------------------------------------------------------------
def spread_search(node)
dir = [2,4,6,8]
dir.shuffle.each do |d|
next_node = node.nodes[d]
next unless next_node
next if next_node.visited
next if get_distance(next_node) > @max_distance
next_node.expand_node(@revealed_nodes, self) unless next_node.expanded
next_node.visited = true
@reveal_queue.push(next_node, node)
end
end
#----------------------------------------------------------------------------
# * Get distance
#----------------------------------------------------------------------------
def get_distance(node)
range_x = node.x - @init_x
range_y = node.y - @init_y
result = Math.sqrt((range_x**2) + (range_y**2))
return result
end
end
#===============================================================================
# ** Game_Character
#===============================================================================
class Game_Character
#----------------------------------------------------------------------------
# * Reveal tiles
#----------------------------------------------------------------------------
def reveal_tiles(distance = Theo::VisiRange)
$game_map.reveal_tiles(x, y, distance)
end
end
#===============================================================================
# ** Game_Player
#===============================================================================
class Game_Player
#----------------------------------------------------------------------------
# * Increase step
#----------------------------------------------------------------------------
alias theo_fogofwar_increase_steps increase_steps
def increase_steps
theo_fogofwar_increase_steps
reveal_tiles
end
end
#===============================================================================
# ** Spriteset_Map
#===============================================================================
class Spriteset_Map
#----------------------------------------------------------------------------
# * Attribute Reader
#----------------------------------------------------------------------------
attr_reader :fogofwar
#----------------------------------------------------------------------------
# * Create viewports (alias)
#----------------------------------------------------------------------------
alias theo_fogofwar_create_viewports create_viewports
def create_viewports
theo_fogofwar_create_viewports
create_fogofwar
end
#----------------------------------------------------------------------------
# * Create fog of war
#----------------------------------------------------------------------------
def create_fogofwar
@fogofwar = Fog_of_War.new(@viewport1)
@fogofwar.z = 210
end
#----------------------------------------------------------------------------
# * Update (alias)
#----------------------------------------------------------------------------
alias theo_fogofwar_update update
def update
theo_fogofwar_update
@fogofwar.update
end
#----------------------------------------------------------------------------
# * Dispose (alias)
#----------------------------------------------------------------------------
alias theo_fogofwar_dispose dispose
def dispose
theo_fogofwar_dispose
@fogofwar.dispose
end
end
#===============================================================================
# ** Scene_Base
#===============================================================================
class Scene_Base
attr_reader :spriteset
end