图块通行度增强 Enhanced Tile Passage

插件简介:

一直很不满RPG Maker VX以后的自动单层地图的绘制系统,感觉很难画出美观复杂的地图了。这个脚本允许角色从墙壁后通行,并自动计算通行度和遮挡。同时也提供了根据区域ID调节图块通行和遮挡的功能。

比如下图的地图:
原始地图
实际不可通行的只有黄色区域(只是展示用,使用时不需要画区域)
实际不可通行区域为黄色部分
此外本脚本还提供通过区域ID强制改变图块通行度和优先度的功能:

  • 强制可通行并处于主角上方(星形通行)
  • 强制处于主角上方(不更改通行)
  • 强制可通行(不更改优先级)
  • 强制不可通行(不更改优先级)

食用方法:

  1. 直接安装插件;
  2. 设置参数:
    • Wall Top Terrain Tag:设定为这个地形标记的图块将当作墙壁顶面,用来计算墙壁厚度。默认值7,不启用请设为大于7的数
    • Wall Front Terrain Tag:设定为这个地形标记的图块将当作墙壁正面,用来计算墙壁高度。默认值6,不启用请设为大于7的数
    • Default Wall Height:当墙壁正面不存在时(如地图底部),默认的墙壁高度。默认值2,不启用请设为0
    • Star Terrain Tag:设定为这个地形标记的图块将强制显示在角色之上,并可通行。默认值99,不启用请设为大于7的数
    • Star Region ID List:设定为这个区域ID的图块将强制显示在角色之上,并可通行。多个区域用半角逗号隔开。默认值0,不启用请设为0
    • Higher Tile Region ID List: 设定为这个区域ID的图块将强制显示在角色之上,通行度不会改变。多个区域用半角逗号隔开。默认值0,不启用请设为0
    • Passable Tile Region ID List: 设定为这个区域ID的图块将强制可以通行,优先级不会改变。多个区域用半角逗号隔开。默认值0,不启用请设为0
    • Impassable Tile Region ID List: 设定为这个区域ID的图块将强制不可通行,优先级不会改变。多个区域用半角逗号隔开。默认值0,不启用请设为0
  3. 进入数据库,给需要做为墙壁的图块设定相应的地形标记,比如自动墙壁图块的上部为7,下部为6,墙壁元件的通行将根据绘制情况自动计算 地形标记设置
  4. 如需使用区域ID功能,则根据需求用对应区域ID填在所需图块上。

注意事项:

以上tag和区域id元件不支持四方通行设置。

为了减少对于地图的副作用,降低不可预期图块通行错误的可能,0.80版本后涉及地形标记的功能将只对A类图块组起效。B~E图块组的相关效果可以通过手动使用区域ID功能实现。

如果需要在高层图块(遮挡角色的部分)上显示事件,事件的优先级需要在角色之上。

建议新建/复制图块组使用本插件,旧有图块设置请做好备份。由于RM自身图层设计很不灵活,复杂的遮挡效果难以正确实现,建议墙壁通行的功能只用在以墙壁为主的迷宫场景。

使用条款:

非商业·商业皆可,请credit AndrewX

更新履历:

Version 0.82:
  • 修改:增加未指定时的默认参数值
Version 0.81:
  • 修改:插件名称更改为 Enhanced Tile Passage
  • 新增:可通行图块行区域ID功能(强制图块可通行)
  • 修改:插件参数描述提升
Version 0.80:
  • 新增:高层图块区域ID功能(强制图块处于角色之上)
  • 新增:不可通行图块区域ID功能(强制图块不可通行)
  • 移除:取消Default Wall Thickness参数,因为实用性很低
  • 移除:为了减少对于地图的副作用,降低不可预期图块通行错误的可能,插件中涉及地形标记的功能将只对A类图块组起效。B~E图块组的相关效果可以通过手动使用区域ID功能实现
Version 0.71:
  • 修改:优化通行度判定逻辑
  • 修改:优化高层图块判定逻辑
Version 0.70:
  • 新增:支持多个区域ID
  • 修改:修正小bug
Version 0.60:
  • 修改:优化通行度判定逻辑
Version 0.51:
  • 修改:优化高层和通行度判定逻辑
  • 默认不启用default wall thickness属性
Version 0.50:
  • 新增:可以设定区域ID来实现星形通行
  • 新增: 墙壁的高层低层遮挡现已可以自动计算,不需要使用额外的遮挡修正插件
  • 新增: B~E组元件可以正确显示在上层,无需额外修改星形通行
  • 修改:调整参数显示顺序
Version 0.01:
  • 完成插件原型

插件内容:

插件内容AndrewX_EnhancedTilePassage.js
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
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
//=============================================================================
// AndrewX - Enhanced Tile Passage
// AndrewX_EnhancedTilePassage.js
//=============================================================================
var AndrewX = AndrewX || {};
AndrewX.ETP = AndrewX.ETP || {};
//=============================================================================
/*:
* @plugindesc v0.82 Enable characters to walk behind walls.
* Also enable you to modify tile passage and priority.
* @author AndrewX
*
* @param Wall Top Terrain Tag
* @desc Tiles with this Terrain Tag will be calculated as wall top side. (Default: 7, Disable: a number greater than 7)
* Use a number greater than 7 (e.g. 99) if you do not wish to make use of this property.
* @default 7
*
* @param Wall Front Terrain Tag
* @desc Tiles with this Terrain Tag will be calculated as wall front side. (Default: 6, Disable: a number greater than 7)
* Use a number greater than 7 (e.g. 99) if you do not wish to make use of this property.
* @default 6
*
* @param Default Wall Height
* @desc If wall front side cannot be sampled, this will be the default wall height. (Default: 2, Disable: 0)
* Use 0 if you do not wish to make use of this property.
* @default 2
*
* @param Star Terrain Tag
* @desc Tiles with this Terrain Tag will be set to star passage (above characters). (Default: 99, Disable: greater than 7)
* Use a number greater than 7 (e.g. 99) if you do not wish to make use of this property.
* @default 99
*
* @param Star Region ID List
* @desc Tiles with listed Region ID will be set to star passage. Separate multiple ID with commas. (Disable: 0)
* Use 0 if you do not wish to make use of this property.
* @default 0
*
* @param Higher Tile Region ID List
* @desc Tiles with listed Region ID will be shown above characters (passage unchanged). Separate with commas. (Disable: 0)
* Use 0 if you do not wish to make use of this property.
* @default 0
*
* @param Passable Tile Region ID List
* @desc Tiles with listed Region ID will be always passable. Separate multiple ID with commas. (Disable: 0)
* Use 0 if you do not wish to make use of this property.
* @default 0
*
* @param Impassable Tile Region ID List
* @desc Tiles with listed Region ID will not be passable. Separate multiple ID with commas. (Disable: 0)
* Use 0 if you do not wish to make use of this property.
* @default 0
*
* @help
* ============================================================================
* Introduction and Instructions
* ============================================================================
*
* It's a pity multi-layered mapping is canceled since RMVX, and characters are
* no longer able to walk behind walls, which makes maps a bit of weird. With
* this plugin, you can set two terrain tags as wall top and wall front, and
* passage behind walls are calculated automatically.
*
* Or you can also set a terrain tag as Star Terrain Tag, which makes tiles to be
* star passage.
*
* Note: above tags only works for tiles in set A.
*
* You can also set lists of region IDs as following:
* Star Region ID: Tiles with these IDs will be star passage.
*
* Higher Tile Region ID: Tiles with these IDs will be shown above characters,
* with passage unchanged.
*
* Passable Tile Region ID: Tiles with these IDs will be always passable.
* (layer unchanged)
*
* Impassable Tile Region ID: Tiles with these IDs will be not passable.
*
* To disable certain function, set parameter as following:
* Wall Top Terrain Tag: a number greater than 7 (e.g. 99)
* Wall Front Terrain Tag: a number greater than 7 (e.g. 99)
* Default Wall Height: set to 0
* Star Terrain Tag: a number greater than 7 (e.g. 99)
* Star Region ID List: set to 0
* Higher Tile Region ID List: set to 0
* Passable Tile Region ID List: set to 0
* Impassable Tile Region ID List: set to 0
*
* Note:
* - 4-direction passage does not work on tiles with above tags/region id.
* - Events in higher layer of wall need to be set to above characters priority
* in order to be displayed above the wall.
*
*
* ============================================================================
* Changelog
* ============================================================================
*
* Version 0.82:
* - Modified: Added default parameter values.
*
* Version 0.81:
* - Modified: Pulgin name changed to: Enhanced Tile Passage
* - New: Passable Tile Region ID function (force tile to be passable)
* - Modified: Plugin parameter description improved
*
* Version 0.80:
* - New: Higher Tile Region ID function (force tile to be higher tile)
* - New: Impassable Tile Region ID function (force tile to be impassable)
* - Removed: Removed Default Wall Thickness property, which is not so useful
* - Removed: To minimize side-effects on map, terrain tags only works for
* tiles in set A now
*
* Version 0.71:
* - Modified: Improved passage check logic
* - Modified: Improved layer check logic
*
* Version 0.70:
* - New: Can use multiple star region IDs
* - Modified: Minor bug fix
*
* Version 0.60:
* - Modified: Improved passage check logic
*
* Version 0.51:
* - Modified: Optimized logic for passage and higher layer check
* - Modified: Disabled default wall thickness by default
*
* Version 0.50:
* - New: Star region ID can be used now
* - New: Higher and lower layers of wall tile are calculated automatically now
* - New: B~E tiles can be displayed above walls. So no need to modify
* additional star passage
* - Modified: Rearrange the order of parameters
*
* Version 0.01:
* - Finished prototype
*
* ============================================================================
* Term of Use
* ============================================================================
*
* Free for use in non-commercial or commercial RMMV projects
* Please credit AndrewX
*
*/

//=============================================================================
(function() {
//=============================================================================
// Parameter Variables
//=============================================================================

var parameters = PluginManager.parameters('AndrewX_EnhancedTilePassage');
var starTag = Number(parameters['Star Terrain Tag'] || 99);
var starId = parameters['Star Region ID List'].split(",");
for (var i = 0; i < starId.length; i++) {
starId[i] = Number(starId[i]);
};
var higherId = parameters['Higher Tile Region ID List'].split(",");
for (var i = 0; i < higherId.length; i++) {
higherId[i] = Number(higherId[i]);
};
var passableId = parameters['Passable Tile Region ID List'].split(",");
for (var i = 0; i < higherId.length; i++) {
passableId[i] = Number(passableId[i]);
};
var impassableId = parameters['Impassable Tile Region ID List'].split(",");
for (var i = 0; i < higherId.length; i++) {
impassableId[i] = Number(impassableId[i]);
};
var topTag = Number(parameters['Wall Top Terrain Tag'] || 99);
var frontTag = Number(parameters['Wall Front Terrain Tag'] || 99);
var defWallHeight = Number(parameters['Default Wall Height'] || 0);

//=============================================================================
// Private tag check for game map
//=============================================================================

Game_Map.prototype._hasTag = function(x, y, t) {
var flags = this.tilesetFlags();
var tiles = this.allTiles(x, y);
if (tiles[0] === 0 && tiles[1] === 0 && tiles[2] === 0 && tiles[3] === 0) {
return false;
}
if ((flags[tiles[3]] & 0xF000) === (t << 12)) {
return true;
}
return false;
};

//=============================================================================
// Private passage check for upper layers
//=============================================================================

Game_Map.prototype._normalCheckPassage = function(x, y, bit) {
var flags = this.tilesetFlags();
var tiles = this.allTiles(x, y);
for (var i = 0; i < tiles.length - 2; i++) {
var flag = flags[tiles[i]];
if ((flag & 0x10) !== 0) // [*] No effect on passage
continue;
if ((flag & bit) === 0) // [o] Passable
return true;
if ((flag & bit) === bit) // [x] Impassable
return false;
}
return false;
};

//=============================================================================
// Modified passage check
//=============================================================================

AndrewX.ETP.checkPassage = Game_Map.prototype.checkPassage;
Game_Map.prototype.checkPassage = function(x, y, bit) {
var flags = this.tilesetFlags();
var tiles = this.allTiles(x, y);
var mapHeight = $dataMap.height;
var upperTop = 0;
var upperFront = 0;
var lowerTop = 0;
var lowerFront = 0;
if ($gameMap.regionId(x, y) && starId.contains($gameMap.regionId(x, y))) {
return true;
}
if ($gameMap.regionId(x, y) && passableId.contains($gameMap.regionId(x, y))) {
return true;
}
if ($gameMap.regionId(x, y) && impassableId.contains($gameMap.regionId(x, y))) {
return false;
}
if (!(this._hasTag(x, y, topTag) || this._hasTag(x, y, frontTag) ||
this._hasTag(x, y, starTag))) {
return AndrewX.ETP.checkPassage.call(this, x, y, bit);
}
if (this._hasTag(x, y, starTag)) {
return true;
} else if (this._hasTag(x, y, frontTag)) {
var j = 1;
while (y + j < mapHeight && this._hasTag(x, y + j, frontTag)) {
lowerFront++;
j++;
}
j = 1;
while (y - j >= 0 && this._hasTag(x, y - j, frontTag)) {
upperFront++;
j++;
}
while (y - j >= 0 && this._hasTag(x, y - j, topTag)) {
upperTop++;
j++;
}
if (upperTop === 0) {
return this._normalCheckPassage(x, y, bit);
} else if (lowerFront + 1 <= upperTop) {
return this._normalCheckPassage(x, y, bit);
} else {
return true;
}
} else if (this._hasTag(x, y, topTag)) {
var j = 1;
while (y - j >= 0 && this._hasTag(x, y - j, topTag)) {
upperTop++;
j++;
}
j = 1;
while (y + j < mapHeight && this._hasTag(x, y + j, topTag)) {
lowerTop++;
j++;
}
while (y + j < mapHeight && this._hasTag(x, y + j, frontTag)) {
lowerFront++;
j++;
}
if (lowerFront === 0) {
if (upperTop + 1 <= defWallHeight) {
return true;
} else {
return this._normalCheckPassage(x, y, bit);
}
} else if (upperTop + 1 <= lowerFront) {
return true;
} else {
return this._normalCheckPassage(x, y, bit);
}
}
};

//=============================================================================
// Private tag check for tilemap
//=============================================================================

Tilemap.prototype._tileHasTag = function(x, y, t) {
var tileId = this._readMapData(x, y, 0);
if ((this.flags[tileId] & 0xF000) === (t << 12)) {
return true;
}
return false;
};

//=============================================================================
// Private new higher tile check
//=============================================================================

Tilemap.prototype._isHigherTileNew = function(x, y) {
var mapHeight = this._mapHeight;
var upperTop = 0;
var upperFront = 0;
var lowerTop = 0;
var lowerFront = 0;
if ($gameMap.regionId(x, y + 1) && starId.contains($gameMap.regionId(x, y + 1))) {
return true;
} //if lower tile is star passage
if ($gameMap.regionId(x, y) && starId.contains($gameMap.regionId(x, y))) {
return true;
} else if ($gameMap.regionId(x, y) && higherId.contains($gameMap.regionId(x, y))) {
return true;
} else if (this._tileHasTag(x, y, starTag)) {
return true;
} else if (this._tileHasTag(x, y, frontTag)) {
var i = 1;
while (y + i < mapHeight && this._tileHasTag(x, y + i, frontTag)) {
lowerFront++;
i++;
}
i = 1;
while (y - i >= 0 && this._tileHasTag(x, y - i, frontTag)) {
upperFront++;
i++;
}
while (y - i >= 0 && this._tileHasTag(x, y - i, topTag)) {
upperTop++;
i++;
}
if (upperTop === 0) {
return false;
} else if (lowerFront + 1 <= upperTop) {
return false;
} else {
return true;
}
} else if (this._tileHasTag(x, y, topTag)) {
var i = 1;
while (y - i >= 0 && this._tileHasTag(x, y - i, topTag)) {
upperTop++;
i++;
}
i = 1;
while (y + i < mapHeight && this._tileHasTag(x, y + i, topTag)) {
lowerTop++;
i++;
}
while (y + i < mapHeight && this._tileHasTag(x, y + i, frontTag)) {
lowerFront++;
i++;
}
if (lowerFront === 0) {
if (upperTop + 1 <= defWallHeight) {
return true;
} else {
return false;
}
} else if (upperTop + 1 <= lowerFront) {
return true;
} else {
return false;
}
} else {
return false;
}
};

//=============================================================================
// Modified _paintTiles
//=============================================================================

AndrewX.ETP._paintTiles = Tilemap.prototype._paintTiles;
Tilemap.prototype._paintTiles = function(startX, startY, x, y) {
if (($gameMap.regionId(startX + x, startY + y) &&
starId.contains($gameMap.regionId(startX + x, startY + y))) ||
($gameMap.regionId(startX + x, startY + y) &&
higherId.contains($gameMap.regionId(startX + x, startY + y))) ||
this._tileHasTag(startX + x, startY + y, starTag) ||
this._tileHasTag(startX + x, startY + y, topTag) ||
this._tileHasTag(startX + x, startY + y, frontTag)) {
var tableEdgeVirtualId = 10000;
var mx = startX + x;
var my = startY + y;
var dx = (mx * this._tileWidth).mod(this._layerWidth);
var dy = (my * this._tileHeight).mod(this._layerHeight);
var lx = dx / this._tileWidth;
var ly = dy / this._tileHeight;
var tileId0 = this._readMapData(mx, my, 0);
var tileId1 = this._readMapData(mx, my, 1);
var tileId2 = this._readMapData(mx, my, 2);
var tileId3 = this._readMapData(mx, my, 3);
var shadowBits = this._readMapData(mx, my, 4);
var upperTileId1 = this._readMapData(mx, my - 1, 1);
var lowerTiles = [];
var upperTiles = [];

var isHigher = this._isHigherTileNew(mx, my);

if (isHigher) {
upperTiles.push(tileId0);
} else {
lowerTiles.push(tileId0);
}
if (isHigher) {
upperTiles.push(tileId1);
} else {
lowerTiles.push(tileId1);
}

lowerTiles.push(-shadowBits);

if (this._isTableTile(upperTileId1) && !this._isTableTile(tileId1)) {
if (!Tilemap.isShadowingTile(tileId0)) {
lowerTiles.push(tableEdgeVirtualId + upperTileId1);
}
}

if (this._isOverpassPosition(mx, my)) {
upperTiles.push(tileId2);
upperTiles.push(tileId3);
} else {
if (isHigher) {
upperTiles.push(tileId2);
} else {
lowerTiles.push(tileId2);
}
if (isHigher) {
upperTiles.push(tileId3);
} else {
lowerTiles.push(tileId3);
}
}

var count = 1000 + this.animationCount - my;
var frameUpdated = (count % 30 === 0);
this._animationFrame = Math.floor(count / 30);

var lastLowerTiles = this._readLastTiles(0, lx, ly);
if (!lowerTiles.equals(lastLowerTiles) ||
(Tilemap.isTileA1(tileId0) && frameUpdated)) {
this._lowerBitmap.clearRect(dx, dy, this._tileWidth, this._tileHeight);
for (var i = 0; i < lowerTiles.length; i++) {
var lowerTileId = lowerTiles[i];
if (lowerTileId < 0) {
this._drawShadow(this._lowerBitmap, shadowBits, dx, dy);
} else if (lowerTileId >= tableEdgeVirtualId) {
this._drawTableEdge(this._lowerBitmap, upperTileId1, dx, dy);
} else {
this._drawTile(this._lowerBitmap, lowerTileId, dx, dy);
}
}
this._writeLastTiles(0, lx, ly, lowerTiles);
}

var lastUpperTiles = this._readLastTiles(1, lx, ly);
if (!upperTiles.equals(lastUpperTiles)) {
this._upperBitmap.clearRect(dx, dy, this._tileWidth, this._tileHeight);
for (var j = 0; j < upperTiles.length; j++) {
this._drawTile(this._upperBitmap, upperTiles[j], dx, dy);
}
this._writeLastTiles(1, lx, ly, upperTiles);
}
} else {
AndrewX.ETP._paintTiles.call(this, startX, startY, x, y);
}
};

})();